|
Jeff Mahoney |
638ee5 |
From: David Sterba <dsterba@suse.com>
|
|
Jeff Mahoney |
638ee5 |
Date: Thu, 2 Jun 2016 13:50:44 +0200
|
|
Michal Kubecek |
0a6d0d |
Subject: btrfs: serialize subvolume mounts with potentially mismatching rw flags
|
|
Michal Kubecek |
0a6d0d |
Patch-mainline: Never, ugly <dsterba: ugly but necessary, upstream fix will be more involved>
|
|
David Sterba |
dd5896 |
References: bsc#951844 bsc#1024015 bsc#1099745
|
|
Jeff Mahoney |
638ee5 |
|
|
Jeff Mahoney |
638ee5 |
Racing subvolume mounts with mixed ro/rw flags can fail if the mount and
|
|
Jeff Mahoney |
638ee5 |
remount are not done atomically.
|
|
Jeff Mahoney |
638ee5 |
|
|
Jeff Mahoney |
638ee5 |
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
Jeff Mahoney |
638ee5 |
---
|
|
Michal Kubecek |
a42dcc |
fs/btrfs/super.c | 23 +++++++++++++++++++++++
|
|
Jeff Mahoney |
638ee5 |
1 file changed, 23 insertions(+)
|
|
Jeff Mahoney |
638ee5 |
|
|
Jeff Mahoney |
638ee5 |
--- a/fs/btrfs/super.c
|
|
Jeff Mahoney |
638ee5 |
+++ b/fs/btrfs/super.c
|
|
Michal Kubecek |
0a6d0d |
@@ -1607,6 +1607,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
|
|
David Sterba |
dd5896 |
char *subvol_name = NULL;
|
|
David Sterba |
dd5896 |
u64 subvol_objectid = 0;
|
|
David Sterba |
dd5896 |
int error = 0;
|
|
Jeff Mahoney |
638ee5 |
+ static DEFINE_MUTEX(subvol_lock);
|
|
Jeff Mahoney |
638ee5 |
|
|
Michal Kubecek |
0a6d0d |
error = btrfs_parse_subvol_options(data, &subvol_name,
|
|
Michal Kubecek |
0a6d0d |
&subvol_objectid);
|
|
Michal Kubecek |
0a6d0d |
@@ -1615,6 +1616,24 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
|
|
David Sterba |
dd5896 |
return ERR_PTR(error);
|
|
Jeff Mahoney |
638ee5 |
}
|
|
Jeff Mahoney |
638ee5 |
|
|
Jeff Mahoney |
638ee5 |
+ /*
|
|
Jeff Mahoney |
638ee5 |
+ * Protect against racing mounts of subvolumes with different RO/RW
|
|
Jeff Mahoney |
638ee5 |
+ * flags. The first vfs_kern_mount could fail with -EBUSY if the rw
|
|
Jeff Mahoney |
638ee5 |
+ * flags do not match with the first and the currently mounted
|
|
Jeff Mahoney |
638ee5 |
+ * subvolume.
|
|
Jeff Mahoney |
638ee5 |
+ *
|
|
Jeff Mahoney |
638ee5 |
+ * To resolve that, we adjust the rw flags and do remount. If another
|
|
Jeff Mahoney |
638ee5 |
+ * mounts goes through the same path and hits the window between the
|
|
Jeff Mahoney |
638ee5 |
+ * adjusted vfs_kern_mount and btrfs_remount, it will fail because of
|
|
Jeff Mahoney |
638ee5 |
+ * the ro/rw mismatch in btrfs_mount.
|
|
Jeff Mahoney |
638ee5 |
+ *
|
|
Jeff Mahoney |
638ee5 |
+ * If the mounts do not race and are serialized externally, everything
|
|
Jeff Mahoney |
638ee5 |
+ * works fine. The function-local mutex enforces the serialization but
|
|
Jeff Mahoney |
638ee5 |
+ * is otherwise only an ugly workaround due to lack of better
|
|
Jeff Mahoney |
638ee5 |
+ * solutions.
|
|
Jeff Mahoney |
638ee5 |
+ */
|
|
Jeff Mahoney |
638ee5 |
+ mutex_lock(&subvol_lock);
|
|
Jeff Mahoney |
638ee5 |
+
|
|
David Sterba |
dd5896 |
/* mount device's root (/) */
|
|
David Sterba |
dd5896 |
mnt_root = vfs_kern_mount(&btrfs_root_fs_type, flags, device_name, data);
|
|
David Sterba |
dd5896 |
if (PTR_ERR_OR_ZERO(mnt_root) == -EBUSY) {
|
|
Michal Kubecek |
0a6d0d |
@@ -1626,6 +1645,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
|
|
David Sterba |
dd5896 |
flags | SB_RDONLY, device_name, data);
|
|
David Sterba |
dd5896 |
if (IS_ERR(mnt_root)) {
|
|
David Sterba |
dd5896 |
root = ERR_CAST(mnt_root);
|
|
Jeff Mahoney |
638ee5 |
+ mutex_unlock(&subvol_lock);
|
|
Michal Kubecek |
a42dcc |
kfree(subvol_name);
|
|
Jeff Mahoney |
638ee5 |
goto out;
|
|
Jeff Mahoney |
638ee5 |
}
|
|
Michal Kubecek |
0a6d0d |
@@ -1636,11 +1656,14 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
|
|
David Sterba |
dd5896 |
if (error < 0) {
|
|
David Sterba |
dd5896 |
root = ERR_PTR(error);
|
|
David Sterba |
dd5896 |
mntput(mnt_root);
|
|
Jeff Mahoney |
638ee5 |
+ mutex_unlock(&subvol_lock);
|
|
Michal Kubecek |
a42dcc |
kfree(subvol_name);
|
|
Jeff Mahoney |
638ee5 |
goto out;
|
|
Jeff Mahoney |
638ee5 |
}
|
|
Jeff Mahoney |
638ee5 |
}
|
|
Jeff Mahoney |
638ee5 |
}
|
|
Jeff Mahoney |
638ee5 |
+ mutex_unlock(&subvol_lock);
|
|
Jeff Mahoney |
638ee5 |
+
|
|
David Sterba |
dd5896 |
if (IS_ERR(mnt_root)) {
|
|
David Sterba |
dd5896 |
root = ERR_CAST(mnt_root);
|
|
Michal Kubecek |
a42dcc |
kfree(subvol_name);
|