#1589 Issue closed: function btrfs_subvolume_exists fails to properly evaluate some entries

Labels: bug, support / question, fixed / solved / done

WackyOne opened issue at 2017-11-21 15:53:

  • rear version (/usr/sbin/rear -V):
    Relax-and-Recover 2.2-git.0.0.unknown / 2017-10-03
  • OS version (cat /etc/rear/os.conf or lsb_release -a):
    OS_VENDOR=SUSE_LINUX
    OS_VERSION=12
  • rear configuration files (cat /etc/rear/site.conf or cat /etc/rear/local.conf):
    Empty (all defaults)
  • Are you using legacy BIOS or UEFI boot?
    BIOS
  • Brief description of the issue:
    There are various ways that subvolumes may appear under the root volume. One example is:
    ID 259 gen 6876715 top level 5 path opt
    ID 261 gen 6879102 top level 5 path tmp
    ID 265 gen 6872990 top level 5 path var/opt
    ID 267 gen 6879047 top level 5 path var/tmp
    For path 'opt' and for path 'tmp' it matches twice, therefor returning false.
  • Work-around, if any:
    I have no work-around other than changing the function to do a better match.

jsmeix commented at 2017-11-21 16:34:

@OliverO2
could you have a look what goes on here
because the btrfs_subvolume_exists() function
in lib/filesystems-functions.sh is from you so that
perhaps you see immediatley what is missing here.
Many thanks in advance!

jsmeix commented at 2017-11-21 16:39:

@WackyOne
when you use SUSE with its default btrfs subvolume structure
you basically must use a matching
conf/examples/SLE*btrfs-example.conf
config file as template - regarding "matching" see
https://github.com/rear/rear/issues/1368#issuecomment-302410707

OliverO2 commented at 2017-11-21 17:00:

I'll try to come up with a fix. What we're seeing here is just an unexpected (but valid) subvolume structure.

A fix would be quite easy if btrfs subvolume list would produce more consistent output. But its output can look like this:

ID 5125 gen 27216 top level 257 path @/var/lib/docker/btrfs/subvolumes/8bfcbb9c775e910d504ac7d0f091e9668d700fffcc4c10e71118330ddad47b80

or like this (at least with the -a option):

ID 5125 gen 27216 top level 257 path <FS_TREE>/@/var/lib/docker/btrfs/subvolumes/8bfcbb9c775e910d504ac7d0f091e9668d700fffcc4c10e71118330ddad47b80

I'll check if this is still relevant.

jsmeix commented at 2017-11-21 17:14:

@OliverO2
when I implemented some btrfs code in ReaR
I learned to always use "btrfs subvolume list -a" (i.e. with '-a')
but right now I don't remember the exact reason why but
I guess it was something related to more consistent output.

E.g. see
layout/prepare/GNU/Linux/130_include_mount_subvolumes_code.sh
where I use things like

btrfs subvolume list -a ... | sed -e 's/<FS_TREE>\///' 

because - as far as I remember - when one cuts '<FS_TREE>' away
the rest is the subvolume with absolute path (i.e. its path "relative"
to the root of the btrfs filesystem) and usually that is what one
wants to get (and not some path "relative" to whatever else).

OliverO2 commented at 2017-11-21 18:22:

You are probably right in assuming that using -a and stripping the <FS_TREE> stuff is even safer. So I'll amend my fix.

The problem is that btrfs subvolume is not properly documented and it is not immediately clear (if at all) what the <FS_TREE> stuff in the output actually means. If tried with different file system paths and it looks weird.

Additionally, on Ubuntu 16.04 LTS, the btrfs-subvolume(8) manual page is out of sync with actual behavior. For the list subcommand it states:

For every subvolume the following information is shown by default.
ID <ID> top level <ID> path <path> where path is the relative path of the subvolume to the top level subvolume. [...]

Actual output looks like:

ID <ID> gen <gen> top level <level> path <path>

So we don't have a specific format to really rely on and have to resort to a reasonable guess.

jsmeix commented at 2017-11-22 09:18:

@OliverO2
don't worry - also I am still wondering how btrfs works
and what things like '<FS_TREE>' actually mean ;-)
By luck I found (via Google)
https://www.carta.tech/man-pages/man8/btrfs-subvolume.8.html
that reads

... top-level subvolume, whose subvolume id is 5(FS_TREE)

(which is not in my "man btrfs-subvolume" man page).
From that I guess/conclude 'FS_TREE' probably
means the root of the btrfs filesystem.

Careful:
The root of a filesystem is not the root of the tree
of mounted filesystems (the latter is the '/' directory)
and
the root of a btrfs filesystem (i.e. its root subvolume)
is not necessarily the "entry point" into the btrfs filesystem
when the btrfs filesystem gets mounted at a mountpoint directory
because any subvolume of a btrfs filesystem can be mounted
so that any subvolume can be an "entry point" into the btrfs
filesystem and one same btrfs filesystem can be mounted
several times simultaneously so that one can set up a nice
"mess of various entry points" into one same btrfs filesystem.
It is left as an exercise for the reader to find out if and how
access to same files works consistently when one same
btrfs filesystem is mouted several times...

jsmeix commented at 2017-11-22 10:36:

With https://github.com/rear/rear/pull/1591 merged
I consider this issue to be fixed.

@WackyOne
please test with current GitHub ReaR master code
whether or not it now also works in your particular case.
FYI:
How to verify that your ReaR code contains the fix:

# git log | grep 1591

Merge pull request #1591 from OliverO2/fix/btrfs_subvolume_exists

jsmeix commented at 2017-11-22 10:50:

@OliverO2
many thanks for your prompt response
and for your quick fix!

OliverO2 commented at 2017-11-22 11:08:

@jsmeix Regarding the <FS_TREE> tag, look at the differences when calling btrfs subvolume list -a with different mountpoints referring to subvolumes of the same btrfs file system:

# findmnt -t btrfs
TARGET         SOURCE                             FSTYPE OPTIONS
/              /dev/sda2[/@]                      btrfs  rw,noatime,nodiratime,s
├─/volumes/01  /dev/sda2                          btrfs  rw,noatime,nodiratime,s
├─/var/lib/docker/btrfs
│              /dev/sda2[/@/var/lib/docker/btrfs] btrfs  rw,noatime,nodiratime,s
└─/home        /dev/sda2[/@home]                  btrfs  rw,noatime,nodiratime,s

# btrfs subvol list -a / | head
ID 257 gen 202134 top level 5 path <FS_TREE>/@
ID 258 gen 202134 top level 5 path <FS_TREE>/@home
ID 5125 gen 27216 top level 257 path @/var/lib/docker/btrfs/subvolumes/8bfcbb9c775e910d504ac7d0f091e9668d700fffcc4c10e71118330ddad47b80
ID 5126 gen 27217 top level 257 path @/var/lib/docker/btrfs/subvolumes/4209efbc4922061100d9922741e2b5135d396a1586d1111f72d1beb9ea1cc513
ID 5127 gen 27218 top level 257 path @/var/lib/docker/btrfs/subvolumes/e44faf88d5e4a25366e7e0eb2882f40b1c0d2b5fef1142f06b0dad3cd4e1ee4f
ID 5128 gen 27219 top level 257 path @/var/lib/docker/btrfs/subvolumes/268b6c560568411d38215d3d87c08ddc0fb373bb02b4d1a114c589c790a69101
ID 5129 gen 28716 top level 257 path @/var/lib/docker/btrfs/subvolumes/4c48e4299061b98be208013f5be89f05107f075fea4c4e659f117fa55225971b
ID 5134 gen 181545 top level 257 path @/var/lib/docker/btrfs/subvolumes/e18c9690831dd193f37d5dadf0e0ff0f9cac75e6bba09e5b471b7a16538e639b
ID 5137 gen 181545 top level 257 path @/var/lib/docker/btrfs/subvolumes/813f7476ee473d6a1e64b4e08877b0fd76ce0e6a472dfea8ca4f44711e545946
ID 5149 gen 181545 top level 257 path @/var/lib/docker/btrfs/subvolumes/1f45e82870cc392d533d0976f2e1a732b8fab8b85f322ae77533c8cfd676dbff

# btrfs subvol list -a /volumes/01 | head
ID 257 gen 202135 top level 5 path @
ID 258 gen 202135 top level 5 path @home
ID 5125 gen 27216 top level 257 path <FS_TREE>/@/var/lib/docker/btrfs/subvolumes/8bfcbb9c775e910d504ac7d0f091e9668d700fffcc4c10e71118330ddad47b80
ID 5126 gen 27217 top level 257 path <FS_TREE>/@/var/lib/docker/btrfs/subvolumes/4209efbc4922061100d9922741e2b5135d396a1586d1111f72d1beb9ea1cc513
ID 5127 gen 27218 top level 257 path <FS_TREE>/@/var/lib/docker/btrfs/subvolumes/e44faf88d5e4a25366e7e0eb2882f40b1c0d2b5fef1142f06b0dad3cd4e1ee4f
ID 5128 gen 27219 top level 257 path <FS_TREE>/@/var/lib/docker/btrfs/subvolumes/268b6c560568411d38215d3d87c08ddc0fb373bb02b4d1a114c589c790a69101
ID 5129 gen 28716 top level 257 path <FS_TREE>/@/var/lib/docker/btrfs/subvolumes/4c48e4299061b98be208013f5be89f05107f075fea4c4e659f117fa55225971b
ID 5134 gen 181545 top level 257 path <FS_TREE>/@/var/lib/docker/btrfs/subvolumes/e18c9690831dd193f37d5dadf0e0ff0f9cac75e6bba09e5b471b7a16538e639b
ID 5137 gen 181545 top level 257 path <FS_TREE>/@/var/lib/docker/btrfs/subvolumes/813f7476ee473d6a1e64b4e08877b0fd76ce0e6a472dfea8ca4f44711e545946
ID 5149 gen 181545 top level 257 path <FS_TREE>/@/var/lib/docker/btrfs/subvolumes/1f45e82870cc392d533d0976f2e1a732b8fab8b85f322ae77533c8cfd676dbff

jsmeix commented at 2017-11-22 11:51:

@OliverO2
many thanks for that example.

It proves that whenever one does something
with a btrfs filesystem that has subvolumes
one basically must always inspect and use
the btrfs filesystem at its top level subvolume
(i.e. at its root subvolume) as entry point.

Using any other subvolume below the root subvolume
as entry point causes nothing else but confusion
(at least for me).

Because when looking at a btrfs filesystem from
an inner entry point of view things look strange
in particular things that belong to higher parts
that are above the current inner entry point of view.

I think I can reproduce such unexpected
"btrfs subvol list -a" output on my SLES12-SP2 system
with its btrfs default structure.

The crucial point why "btrfs subvol list -a /" looks strange
is when what is mounted at '/' is not the root subvolume
but an inner subvolume so that '/' is an inner entry point
of view.

What I get on SLES12-SP2 (excerpts as needed):

# findmnt -t btrfs -o TARGET,SOURCE
TARGET                    SOURCE
/                         /dev/sda2[/@/.snapshots/1/snapshot]
...
|-/var/lib/mysql          /dev/sda2[/@/var/lib/mysql]
|-/var/lib/named          /dev/sda2[/@/var/lib/named]
|-/var/lib/libvirt/images /dev/sda2[/@/var/lib/libvirt/images]
|-/var/lib/mariadb        /dev/sda2[/@/var/lib/mariadb]
|-/var/lib/mailman        /dev/sda2[/@/var/lib/mailman]
|-/var/lib/machines       /dev/sda2[/@/var/lib/machines]
|-/var/lib/pgsql          /dev/sda2[/@/var/lib/pgsql]

# btrfs subvolume create /var/lib/mystuff         
Create subvolume '/var/lib/mystuff'

# btrfs subvol list -a / | grep var/lib
ID 269 gen 760 top level 257 path <FS_TREE>/@/var/lib/libvirt/images
ID 270 gen 760 top level 257 path <FS_TREE>/@/var/lib/machines
ID 271 gen 760 top level 257 path <FS_TREE>/@/var/lib/mailman
ID 272 gen 760 top level 257 path <FS_TREE>/@/var/lib/mariadb
ID 273 gen 760 top level 257 path <FS_TREE>/@/var/lib/mysql
ID 274 gen 760 top level 257 path <FS_TREE>/@/var/lib/named
ID 275 gen 760 top level 257 path <FS_TREE>/@/var/lib/pgsql
ID 300 gen 879 top level 259 path @/.snapshots/1/snapshot/var/lib/mystuff

# mkdir /tmp/btrfsroot

# mount -t btrfs -o subvolid=0 /dev/sda2 /tmp/btrfsroot/

# btrfs subvol list -a /tmp/btrfsroot/ | grep var/lib
ID 269 gen 760 top level 257 path <FS_TREE>/@/var/lib/libvirt/images
ID 270 gen 760 top level 257 path <FS_TREE>/@/var/lib/machines
ID 271 gen 760 top level 257 path <FS_TREE>/@/var/lib/mailman
ID 272 gen 760 top level 257 path <FS_TREE>/@/var/lib/mariadb
ID 273 gen 760 top level 257 path <FS_TREE>/@/var/lib/mysql
ID 274 gen 760 top level 257 path <FS_TREE>/@/var/lib/named
ID 275 gen 760 top level 257 path <FS_TREE>/@/var/lib/pgsql
ID 300 gen 879 top level 259 path <FS_TREE>/@/.snapshots/1/snapshot/var/lib/mystuff

WackyOne commented at 2017-11-22 13:58:

@jsmeix I tested the new code for my case and it works.

@OliverO2 thanks for the very quick resolution

OliverO2 commented at 2017-11-22 14:26:

@WackyOne You're welcome. Thanks for the bug report and your test feedback!

jsmeix commented at 2017-11-23 09:31:

@WackyOne
many thanks for your prompt verification and feedback
whether or not it also works for you.


[Export of Github issue for rear/rear.]