Get device with major number 0 (btrfs subvolume)

btrfsfilesystemsstatsystem-calls

When I stat a file on a btrfs subvolume I get a major device number of 0.
Is there a reliable way to find the mount point of this device, without knowing in advance it is a btrfs subvolume?

e.g. I'd like to be able to do this in 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'

(in my case sda1(/sys/dev/block/8:1) is mounted on /boot, and /home is a btrfs subvolume of sda2).

Edit

I'd need to be able to do this without knowing the path of the file. Above I used os.stat as an example however the information is actually retrieved from an ioctl call to a loop device which returns:

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];
};

There is the field lo_file_name however it has a max length of 63 chars so cannot be relied open. I am also aware of /sys/block/loopX/loop/backing_file, however this is only available in Linux >= 2.6.37 and my code needs to run on CentOS 6 (2.6.32).

Edit #2

My ultimate goal here is to be able to find the backing file for a loop device reliably. Even util-linux does not do this on kernels < 2.6.37, e.g.

> 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_*)

Notice that the filename is truncated, this is because util-linux uses the loop_info64 struct which has a 63 char limit on the lo_file_name field.

What I can get reliably is the device ID and the inode number of the backing file. This is where I hit a wall, as the backing file is stored on a btrfs subvolume.

Best Answer

I looked at the Gnu core-utils source code, particularly at the df command.

It recursively descends the hierarchy until the device IDs change. At the point where the IDs change is the mount point.

I just tried to find the mount point of the filesystem that ~/home/me/a-dir/another-dir is in. I did:

stat . #noting device IDs
while id not changes and root not hit
do
  cd ..
  stat .
done
if root not hit
then
  cd -
fi

(this code is pseudo bash, all the conditional and loops where done manually. It just to prove the concept. I will leave the programming and translation to python as on exercise for the reader.)

Related Question