Util-Linux package development
 help / color / mirror / Atom feed
From: Stanislav Brabec <sbrabec@suse.cz>
To: Karel Zak <kzak@redhat.com>
Cc: util-linux@vger.kernel.org, David Sterba <dsterba@suse.cz>
Subject: Re: [PATCH] tests: add btrfs mount tests (fails!)
Date: Wed, 9 Mar 2016 20:13:26 +0100	[thread overview]
Message-ID: <56E075D6.2040704@suse.cz> (raw)
In-Reply-To: <56C72E9B.3050402@suse.cz>

On Feb 19, 2016 at 16:02 Stanislav Brabec wrote:
> On Feb 11 2016 at 14:47 Stanislav Brabec wrote:
>> There are missing umount commands in the middle of the test, which
>> trigger following problem:
>>
>> Additionally, I am working on a reproducer of an invalid "mount -a"
>> behavior triggered by kernel bug reporting false subvol.
> 
>> I already have a possible fix for it, but I want to confirm that it is
>> correct before sending it upstream.
> 
> I finally found a reproducer.
> 
Well, now I have a real reproducer that is not triggered by another bug.

My findings:

1) The way to reproduce is extremely obscure, because not only subvolid
has to match, but also target.

2) There is no way to fix it in an easy way. I suggested a new
algorithm searching for shortest subvol, but it would be vulnerable to
bad evaluation as well.

So I decided to keep the code as it is.

Way to reproduce:

To confuse the algorithm, there has to be a mounted something else into
the target than fstab specifies.

Step 1:
/dev/loop0 /btrfs_mnt_root btrfs subvol=/ 0 0
/btrfs_mnt_root/d0/dd0/ddd0/s1/d1/dd1/ddd1/s2/bind-mnt /btrfs_mnt_bind btrfs bind,private 0 0

It will create following mountinfo:
299 72 0:83 / /btrfs_mnt_root rw,relatime shared:211 - btrfs /dev/loop0 rw,space_cache,subvolid=5,subvol=/
312 72 0:83 /d0/dd0/ddd0/s1/d1/dd1/ddd1/s2/bind-mnt /btrfs_mnt_bind rw,relatime shared:211 - btrfs /dev/loop0 rw,space_cache,subvolid=258,subvol=/d0/dd0/ddd0/s1/d1/dd1/ddd1/s2/bind-mnt

Note that subvolid 258 does not correspond to / nor to
d0/dd0/ddd0/s1/d1/dd1/ddd1/s2/bind-mnt, but it corresponds to
d0/dd0/ddd0/s1/d1/dd1/ddd1/s2.

Now remove both lines from fstab and add:

/dev/loop0 /btrfs_mnt_bind btrfs defaults 0 0

Default subvolume is d0/dd0/ddd0/s1/d1/dd1/ddd1/s2, but the algorithm
(both the existing and the previously suggested one) falsely assumes
that it is /d0/dd0/ddd0/s1/d1/dd1/ddd1/s2/bind-mnt, because both
subvolid and target match.

In theory, the new fstab should cause mounting the default subvolume
over the existing one, but nothing happens.

Summary:

- The full fix would mean evaluation of the btrfs subvolume tree
  structure (several ioctl() with possible need of disk lookups) just
  to find, whether it is already mounted or no.

- The reproducer is really obscure, and nothing from a real life cannot
  trigger it.

- The full fix will be vulnerable to another unfixable problems (e. g.
  when somebody changes the default subvolume path while the device is
  mounted).

=> I propose to keep this part of code with a known bug.



Here is the the previously proposed (obsolete) fix:

---
 libmount/src/tab.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/libmount/src/tab.c b/libmount/src/tab.c
index 102ed25..556d835 100644
--- a/libmount/src/tab.c
+++ b/libmount/src/tab.c
@@ -1224,6 +1224,18 @@ static char *remove_mountpoint_from_path(const char *path, const char *mnt)
 }
 
 #ifdef HAVE_BTRFS_SUPPORT
+/* All currently existing kernels reports incorrect values for bind
+ * mounts. Instead of subvol/subvolid of a subvolume used for creating of bind
+ * mount, it reports subvolid corresponding to nearest upper subvol node and
+ * subvol pointing to the current dir relative to btrfs root.
+ *
+ * The current kernel btrfs implementation has not access to proper VFS
+ * structures, so it is just guessing. Fixing this will need refactoring of
+ * kernel btrfs subvol implementation. It is not expected to happen anytime
+ * soon. Set this define to suppose that kernels are buggy, and don't blindly
+ * trust to the reported mountinfo values. */
+#define KERNEL_BTRFS_REPORTS_FALSE_SUBVOL 1
+
 static int get_btrfs_fs_root(struct libmnt_table *tb, struct libmnt_fs *fs, char **root)
 {
 	char *vol = NULL, *p;
@@ -1236,6 +1248,12 @@ static int get_btrfs_fs_root(struct libmnt_table *tb, struct libmnt_fs *fs, char
 		char *target;
 		struct libmnt_fs *f;
 		char subvolidstr[sizeof(stringify_value(UINT64_MAX))];
+#ifdef KERNEL_BTRFS_REPORTS_FALSE_SUBVOL
+		struct libmnt_fs *t;
+		struct libmnt_iter itr;
+		char *optval = NULL;
+		size_t optvalsz = 0, valsz, bestvalsz = PATH_MAX;
+#endif
 
 		DBG(BTRFS, ul_debug(" found subvolid=%s, checking", vol));
 
@@ -1248,9 +1266,24 @@ static int get_btrfs_fs_root(struct libmnt_table *tb, struct libmnt_fs *fs, char
 			goto err;
 
 		DBG(BTRFS, ul_debug(" tring target=%s subvolid=%s", target, subvolidstr));
+#ifndef KERNEL_BTRFS_REPORTS_FALSE_SUBVOL
 		f = mnt_table_find_target_with_option(tb, target,
 					"subvolid", subvolidstr,
 					MNT_ITER_BACKWARD);
+#else
+		f = NULL;
+		valsz = strlen(subvolidstr);
+		mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
+		while (mnt_table_next_fs(tb, &itr, &t) == 0) {
+			if (mnt_fs_streq_target(t, target)
+			    && mnt_fs_get_option(t, "subvolid", &optval, &optvalsz) == 0
+			    && optvalsz == valsz
+			    && strncmp(optval, subvolidstr, optvalsz) == 0
+			    && optvalsz < bestvalsz)
+				f = t;
+		}
+#endif
+
 		if (!tb->cache)
 			free(target);
 		if (!f)
@@ -1271,6 +1304,12 @@ static int get_btrfs_fs_root(struct libmnt_table *tb, struct libmnt_fs *fs, char
 		char *target;
 		struct libmnt_fs *f;
 		char default_id_str[sizeof(stringify_value(UINT64_MAX))];
+#ifdef KERNEL_BTRFS_REPORTS_FALSE_SUBVOL
+		struct libmnt_fs *t;
+		struct libmnt_iter itr;
+		char *optval = NULL;
+		size_t optvalsz = 0, valsz, bestvalsz = PATH_MAX;
+#endif
 
 		DBG(BTRFS, ul_debug(" subvolid/subvol not found, checking default"));
 
@@ -1295,9 +1334,24 @@ static int get_btrfs_fs_root(struct libmnt_table *tb, struct libmnt_fs *fs, char
 		DBG(BTRFS, ul_debug(" tring target=%s default subvolid=%s",
 					target, default_id_str));
 
+#ifndef KERNEL_BTRFS_REPORTS_FALSE_SUBVOL
 		f = mnt_table_find_target_with_option(tb, target,
 					"subvolid", default_id_str,
 					MNT_ITER_BACKWARD);
+#else
+		f = NULL;
+		valsz = strlen(default_id_str);
+		mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
+		while (mnt_table_next_fs(tb, &itr, &t) == 0) {
+			if (mnt_fs_streq_target(t, target)
+			    && mnt_fs_get_option(t, "subvolid", &optval, &optvalsz) == 0
+			    && optvalsz == valsz
+			    && strncmp(optval, default_id_str, optvalsz) == 0
+			    && optvalsz < bestvalsz)
+				f = t;
+		}
+#endif
+
 		if (!tb->cache)
 			free(target);
 		if (!f)
-- 
2.7.2

-- 
Best Regards / S pozdravem,

Stanislav Brabec
software developer
---------------------------------------------------------------------
SUSE LINUX, s. r. o.                         e-mail: sbrabec@suse.com
Lihovarská 1060/12                            tel: +49 911 7405384547
190 00 Praha 9                                 fax:  +420 284 084 001
Czech Republic                                    http://www.suse.cz/
PGP: 830B 40D5 9E05 35D8 5E27 6FA3 717C 209F A04F CD76

  reply	other threads:[~2016-03-09 19:13 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-02 18:00 [PATCH] tests: add btrfs mount tests Stanislav Brabec
2016-02-02 20:14 ` [PATCH] tests: add btrfs mount tests (fails!) Stanislav Brabec
2016-02-03 17:00   ` Stanislav Brabec
2016-02-03 18:39     ` Stanislav Brabec
2016-02-10 16:03     ` another mount -a problem, not related to btrfs Stanislav Brabec
2016-02-11  9:43   ` [PATCH] tests: add btrfs mount tests (fails!) Karel Zak
2016-02-11 13:47     ` Stanislav Brabec
2016-02-11 16:34       ` Stanislav Brabec
2016-02-11 18:07         ` [PATCH] tests: add btrfs mount tests Stanislav Brabec
2016-02-12  9:38           ` Karel Zak
2016-02-12 10:07         ` [PATCH] tests: add btrfs mount tests (fails!) Karel Zak
2016-02-19 15:02       ` Stanislav Brabec
2016-03-09 19:13         ` Stanislav Brabec [this message]
2016-03-14  1:20 ` [PATCH] tests: add btrfs mount tests Ruediger Meier
2016-03-14 14:19   ` Stanislav Brabec
2016-03-14 23:27     ` Ruediger Meier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=56E075D6.2040704@suse.cz \
    --to=sbrabec@suse.cz \
    --cc=dsterba@suse.cz \
    --cc=kzak@redhat.com \
    --cc=util-linux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox