]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: run btrfs subvol checks for "subvolid" option
authorStanislav Brabec <sbrabec@suse.cz>
Wed, 27 Jan 2016 20:37:00 +0000 (21:37 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 1 Feb 2016 11:23:18 +0000 (12:23 +0100)
It is possible to identify btrfs subvolume with "subvolid" instead of "subvol".
In such case, btrfs specific check mistakenly assumes that the default subvolume
is going to be mounted, even if subvolid specifies id of non-default subvolume.

Implement a code for "subvolid" option.

For easier review, this fix comes in two patches:
PATCH 1/2: libmount: run btrfs subvol checks for "subvolid" option
PATCH 2/2: code re-indentation

How to reproduce:
truncate -s1G btrfs_test.img
mkdir -p btrfs_mnt
/sbin/mkfs.btrfs -f -d single -m single ./btrfs_test.img
mount -o loop btrfs_test.img btrfs_mnt
pushd .
cd btrfs_mnt
mkdir -p d0/dd0/ddd0
cd d0/dd0/ddd0
touch file{1..5}
btrfs subvol create s1
cd s1
touch file{1..5}
mkdir -p d1/dd1/ddd1
cd d1/dd1/ddd1
btrfs subvol create s2
rid=$(btrfs inspect rootid s2)
echo new default $rid
btrfs subvol get-default .
btrfs subvol set-default $rid .
popd
DEFAULT_SUBVOLID=`btrfs subvolume get-default btrfs_mnt | while read dummy id rest ; do echo $id ; done`
NON_DEFAULT_SUBVOLID=`btrfs subvolume list btrfs_mnt | while read dummy id rest ; do if test $id = $DEFAULT_SUBVOLID ; then continue ; fi ; echo $id ; done`
umount btrfs_mnt
losetup /dev/loop0 $PWD/btrfs_test.img
echo "/dev/loop0 $PWD/btrfs_mnt btrfs subvolid=$NON_DEFAULT_SUBVOLID 0 0" >>/etc/fstab
./mount -a
./mount -a
umount btrfs_mnt
sed -i "/\/dev\/loop0/d" /etc/fstab
losetup -d /dev/loop0
rm btrfs_test.img
rmdir btrfs_mnt

Current behavior of second "mount -a":
    mount: /dev/loop0 is already mounted or /root/btrfs_mnt busy
           /dev/loop0 is already mounted on /root/btrfs_mnt

Signed-off-by: Stanislav Brabec <sbrabec@suse.cz>
libmount/src/tab.c

index e8920cbb396408288ea10ef340a07b6af9dc235f..71dfbf5e717c0f25a5070e808b7c8512470a09a9 100644 (file)
@@ -1325,6 +1325,7 @@ struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
 
                DBG(BTRFS, ul_debug("lookup for FS root"));
 
+               if (mnt_fs_get_option(fs, "subvolid", &vol, &volsz)) {
                if (mnt_fs_get_option(fs, "subvol", &vol, &volsz)) {
                        /* If fstab entry does not contain "subvol", we have to
                         * check, whether btrfs has default subvolume defined.
@@ -1352,7 +1353,7 @@ struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
                        snprintf(default_id_str, sizeof(default_id_str), "%llu",
                                        (unsigned long long int) default_id);
 
-                       DBG(BTRFS, ul_debug("target=%s subvolid=%s", target, default_id_str));
+                       DBG(BTRFS, ul_debug("target=%s default subvolid=%s", target, default_id_str));
                        f = mnt_table_find_target_with_option(tb, target,
                                                "subvolid", default_id_str,
                                                MNT_ITER_BACKWARD);
@@ -1369,6 +1370,37 @@ struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
                                goto dflt;
                } else
                        DBG(BTRFS, ul_debug("setting FS root: btrfs subvol"));
+               } else {
+                       char *target;
+                       struct libmnt_fs *f;
+                       char subvolidstr[sizeof(stringify_value(UINT64_MAX))];
+
+                       assert (volsz + 1 < sizeof(stringify_value(UINT64_MAX)));
+                       memcpy(subvolidstr, vol, volsz);
+                       subvolidstr[volsz] = '\0';
+
+                       target = mnt_resolve_spec(mnt_fs_get_target(fs), tb->cache);
+                       if (!target)
+                               goto err;
+
+                       DBG(BTRFS, ul_debug("target=%s subvolid=%s", target, subvolidstr));
+                       f = mnt_table_find_target_with_option(tb, target,
+                                               "subvolid", subvolidstr,
+                                               MNT_ITER_BACKWARD);
+                       if (!tb->cache)
+                               free(target);
+
+                       if (!f)
+                               goto dflt;
+
+                       /* Instead of set of BACKREF queries constructing
+                        * subvol path corresponding to a particular subvolid,
+                        * use the one in mountinfo. Kernel keeps subvol path
+                        * up to date.
+                        */
+                       if (mnt_fs_get_option(f, "subvol", &vol, &volsz))
+                               goto dflt;
+               }
 
                sz = volsz;
                if (*vol != '/')