Skip to content

Instantly share code, notes, and snippets.

@mvollmer
Created January 16, 2024 12:59
Show Gist options
  • Save mvollmer/1cf111cfdb4f7ec55248ecd23ea4284d to your computer and use it in GitHub Desktop.
Save mvollmer/1cf111cfdb4f7ec55248ecd23ea4284d to your computer and use it in GitHub Desktop.
# What's wrong with UDisks2 Btrfs.GetSubvolumes
GetSubvolumes is implemented by finding the mount point of a arbitrary
mounted subvolume of a btrfs filesystem and then running "btrfs
subvolume list -p <mount point>".
The pathnames in the result are kind-of-sort-of relative to the chosen
subvolume, and thus the result of GetSubvolumes can change when
different subvolumes are mounted. That's unexpected.
# mkfs.btrfs -f /dev/sda
# mount /dev/sda /mnt/butter
# btrfs subvol create /mnt/butter/one
# btrfs subvol create /mnt/butter/one/two
# mkdir /mnt/butter/one/two/one
# mkdir /mnt/butter/one/two/one/two
# btrfs subvol create /mnt/butter/one/two/two/two/three
# find /mnt/butter
/mnt/butter
/mnt/butter/one
/mnt/butter/one/two
/mnt/butter/one/two/one
/mnt/butter/one/two/one/two
/mnt/butter/one/two/one/two/three
# busctl call org.freedesktop.UDisks2 /org/freedesktop/UDisks2/block_devices/sda org.freedesktop.UDisks2.Filesystem.BTRFS GetSubvolumes "ba{sv}" false 0
a(tts)i 3 256 5 "one" 257 256 "one/two" 258 257 "one/two/one/two/three" 3
Here we get the expected full names "one", "one/two", and "one/two/one/two/three".
# umount /mnt/butter
# mount /dev/sda /mnt/butter -o subvol=one/two
# busctl call org.freedesktop.UDisks2 /org/freedesktop/UDisks2/block_devices/sda org.freedesktop.UDisks2.Filesystem.BTRFS GetSubvolumes "ba{sv}" false 0
a(tts)i 3 256 5 "one" 257 256 "one/two" 258 257 "one/two/three" 3
Now we get "one", "one/two", and "one/two/three". The last name is
relative to "one/two", but we can't reliably tell that.
To underscore the last point, here is another scenario that produces
the same output:
# mkfs.btrfs -f /dev/sda
# mount /dev/sda /mnt/butter
# btrfs subvol create /mnt/butter/one
# btrfs subvol create /mnt/butter/one/two
# btrfs subvol create /mnt/butter/one/two/three
# find /mnt/butter
/mnt/butter
/mnt/butter/one
/mnt/butter/one/two
/mnt/butter/one/two/three
# busctl call org.freedesktop.UDisks2 /org/freedesktop/UDisks2/block_devices/sda org.freedesktop.UDisks2.Filesystem.BTRFS GetSubvolumes "ba{sv}" false 0
a(tts)i 3 256 5 "one" 257 256 "one/two" 258 257 "one/two/three" 3
A possible workaround for Cockpit is to figure out which mount point
was used by UDisks2 and which subvolume corresponds to it. Then we
know which names in the result of GetSubvolumes are relative to what.
UDisks will use the first entry in Filesystem.Mountpoints, and findmnt
can tell us which subvolume is mounted there.
But the easiest thing is to add "-a" to the "btrfs subvol list"
invocation in libblockdev. Clients like Cockpit might want to detect
whether "-a" was used or not. For that, we could prepend a "/" to the
names when "-a" is used.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment