获取主编号为 0 的设备(btrfs 子卷)

Jez*_*Jez 5 filesystems system-calls stat btrfs

当我在 btrfs 子卷上统计文件时,我得到的主要设备编号为0. 有没有一种可靠的方法来找到这个设备的挂载点,而无需事先知道它是一个 btrfs 子卷?

例如,我希望能够在 python 中做到这一点:

>>> st = os.stat('a file')
>>> os.major(st.st_dev)
0
>>> os.minor(st.st_dev)
38
>>> os.path.exists('/sys/dev/block/0:38')
False
>>> magic_method_that_gets_mount_point(0, 38)
'/home'
>>> magic_method_that_gets_mount_point(8, 1)
'/boot'
Run Code Online (Sandbox Code Playgroud)

(在我的情况下,sda1( /sys/dev/block/8:1) 安装在 上/boot,并且/home是 的 btrfs 子卷sda2)。

编辑

我需要能够在不知道文件路径的情况下执行此操作。上面我用作os.stat示例,但是信息实际上是从ioctl对循环设备的调用中检索的,该循环设备返回:

struct loop_info64 {
    uint64_t    lo_device;
    uint64_t    lo_inode;
    uint64_t    lo_rdevice;
    uint64_t    lo_offset;
    uint64_t    lo_sizelimit;
    uint32_t    lo_number;
    uint32_t    lo_encrypt_type;
    uint32_t    lo_encrypt_key_size;
    uint32_t    lo_flags;
    uint8_t     lo_file_name[64];
    uint8_t     lo_crypt_name[64];
    uint8_t     lo_encrypt_key[32];
    uint64_t    lo_init[2];
};
Run Code Online (Sandbox Code Playgroud)

有该字段,lo_file_name但它的最大长度为 63 个字符,因此不能依赖打开。我也知道/sys/block/loopX/loop/backing_file,但是这仅在 Linux >= 2.6.37 中可用,并且我的代码需要在 CentOS 6 (2.6.32) 上运行。

编辑 #2

我的最终目标是能够可靠地找到循环设备的后备文件。甚至 util-linux 也不会在 <2.6.37 的内核上执行此操作,例如

> dd if=/dev/urandom bs=4096 count=256 of=/root/a_really_really_really_really_really_really_really_long_file_name.img
256+0 records in
256+0 records out
1048576 bytes (1.0 MB) copied, 0.137397 s, 7.6 MB/s
> LD=`losetup -f --show /root/a_really_really_really_really_really_really_really_long_file_name.img`
> losetup $LD
/dev/loop1: [fd00]:922372 (/root/a_really_really_really_really_really_really_really_long_*)
Run Code Online (Sandbox Code Playgroud)

请注意,文件名被截断了,这是因为 util-linux 使用了loop_info64字段上有 63 个字符限制的结构lo_file_name

我能可靠地得到的是设备 ID 和后备文件的 inode 编号。这是我碰壁的地方,因为后备文件存储在 btrfs 子卷上。

ctr*_*lor 1

我查看了 Gnu core-utils 源代码,特别是命令df

它会递归地降低层次结构,直到设备 ID 发生变化。ID 发生变化的点就是挂载点。

我只是试图找到~/home/me/a-dir/another-dir所在文件系统的挂载点。我做了:

stat . #noting device IDs
while id not changes and root not hit
do
  cd ..
  stat .
done
if root not hit
then
  cd -
fi
Run Code Online (Sandbox Code Playgroud)

(这段代码是伪 bash,所有条件和循环都是手动完成的。它只是为了证明这个概念。我将把编程和翻译留给 python 作为读者的练习。)