diff mbox series

[05/17] btrfs: open block devices after superblock creation

Message ID 20230811100828.1897174-6-hch@lst.de (mailing list archive)
State New, archived
Headers show
Series [01/17] FOLD: reverts part of "fs: use the super_block as holder when mounting file systems" | expand

Commit Message

Christoph Hellwig Aug. 11, 2023, 10:08 a.m. UTC
Currently btrfs_mount_root opens the block devices before committing to
allocating a super block. That creates problems for restricting the
number of writers to a device, and also leads to a unusual and not very
helpful holder (the fs_type).

Reorganize the code to first check whether the superblock for a
particular fsid does already exist and open the block devices only if it
doesn't, mirroring the recent changes to the VFS mount helpers.  To do
this the increment of the in_use counter moves out of btrfs_open_devices
and into the only caller in btrfs_mount_root so that it happens before
dropping uuid_mutex around the call to sget.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/btrfs/super.c   | 40 +++++++++++++++++++++++-----------------
 fs/btrfs/volumes.c | 15 +++++----------
 2 files changed, 28 insertions(+), 27 deletions(-)

Comments

Christian Brauner Aug. 11, 2023, 12:44 p.m. UTC | #1
On Fri, Aug 11, 2023 at 12:08:16PM +0200, Christoph Hellwig wrote:
> Currently btrfs_mount_root opens the block devices before committing to
> allocating a super block. That creates problems for restricting the
> number of writers to a device, and also leads to a unusual and not very
> helpful holder (the fs_type).
> 
> Reorganize the code to first check whether the superblock for a
> particular fsid does already exist and open the block devices only if it
> doesn't, mirroring the recent changes to the VFS mount helpers.  To do
> this the increment of the in_use counter moves out of btrfs_open_devices
> and into the only caller in btrfs_mount_root so that it happens before
> dropping uuid_mutex around the call to sget.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---

Looks good to me,
Acked-by: Christian Brauner <brauner@kernel.org>

And ofc, would be great to get btrfs reviews.
David Sterba Aug. 11, 2023, 1:11 p.m. UTC | #2
On Fri, Aug 11, 2023 at 02:44:50PM +0200, Christian Brauner wrote:
> On Fri, Aug 11, 2023 at 12:08:16PM +0200, Christoph Hellwig wrote:
> > Currently btrfs_mount_root opens the block devices before committing to
> > allocating a super block. That creates problems for restricting the
> > number of writers to a device, and also leads to a unusual and not very
> > helpful holder (the fs_type).
> > 
> > Reorganize the code to first check whether the superblock for a
> > particular fsid does already exist and open the block devices only if it
> > doesn't, mirroring the recent changes to the VFS mount helpers.  To do
> > this the increment of the in_use counter moves out of btrfs_open_devices
> > and into the only caller in btrfs_mount_root so that it happens before
> > dropping uuid_mutex around the call to sget.
> > 
> > Signed-off-by: Christoph Hellwig <hch@lst.de>
> > ---
> 
> Looks good to me,
> Acked-by: Christian Brauner <brauner@kernel.org>
> 
> And ofc, would be great to get btrfs reviews.

I'll take a look but there are some performance regressions to deal with
and pre-merge window freeze so it won't be soon.
David Sterba Aug. 17, 2023, 1:24 p.m. UTC | #3
On Fri, Aug 11, 2023 at 03:11:31PM +0200, David Sterba wrote:
> On Fri, Aug 11, 2023 at 02:44:50PM +0200, Christian Brauner wrote:
> > On Fri, Aug 11, 2023 at 12:08:16PM +0200, Christoph Hellwig wrote:
> > > Currently btrfs_mount_root opens the block devices before committing to
> > > allocating a super block. That creates problems for restricting the
> > > number of writers to a device, and also leads to a unusual and not very
> > > helpful holder (the fs_type).
> > > 
> > > Reorganize the code to first check whether the superblock for a
> > > particular fsid does already exist and open the block devices only if it
> > > doesn't, mirroring the recent changes to the VFS mount helpers.  To do
> > > this the increment of the in_use counter moves out of btrfs_open_devices
> > > and into the only caller in btrfs_mount_root so that it happens before
> > > dropping uuid_mutex around the call to sget.
> > > 
> > > Signed-off-by: Christoph Hellwig <hch@lst.de>
> > > ---
> > 
> > Looks good to me,
> > Acked-by: Christian Brauner <brauner@kernel.org>
> > 
> > And ofc, would be great to get btrfs reviews.
> 
> I'll take a look but there are some performance regressions to deal with
> and pre-merge window freeze so it won't be soon.

I'd rather take the btrfs patches via my tree and get them tested for a
longer time.  This patch in particular changes locking, mount, device
management, that's beyond what I'd consider safe to get merged outside
of btrfs.
diff mbox series

Patch

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 2bbc041ac2e2c5..1079a0f541790d 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1434,7 +1434,6 @@  static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
 static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
 		int flags, const char *device_name, void *data)
 {
-	struct block_device *bdev = NULL;
 	struct super_block *s;
 	struct btrfs_device *device = NULL;
 	struct btrfs_fs_devices *fs_devices = NULL;
@@ -1486,18 +1485,9 @@  static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
 
 	fs_devices = device->fs_devices;
 	fs_info->fs_devices = fs_devices;
-
-	error = btrfs_open_devices(fs_devices, sb_open_mode(flags), fs_type);
+	fs_devices->in_use++;
 	mutex_unlock(&uuid_mutex);
-	if (error)
-		goto error_fs_info;
-
-	if (!(flags & SB_RDONLY) && fs_devices->rw_devices == 0) {
-		error = -EACCES;
-		goto error_fs_info;
-	}
 
-	bdev = fs_devices->latest_dev->bdev;
 	s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | SB_NOSEC,
 		 fs_info);
 	if (IS_ERR(s)) {
@@ -1510,7 +1500,22 @@  static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
 		if ((flags ^ s->s_flags) & SB_RDONLY)
 			error = -EBUSY;
 	} else {
-		snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
+		struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+
+		mutex_lock(&uuid_mutex);
+		error = btrfs_open_devices(fs_devices, sb_open_mode(flags),
+					   fs_type);
+		mutex_unlock(&uuid_mutex);
+		if (error)
+			goto error_deactivate;
+
+		if (!(flags & SB_RDONLY) && fs_devices->rw_devices == 0) {
+			error = -EACCES;
+			goto error_deactivate;
+		}
+
+		snprintf(s->s_id, sizeof(s->s_id), "%pg",
+			 fs_devices->latest_dev->bdev);
 		shrinker_debugfs_rename(&s->s_shrink, "sb-%s:%s", fs_type->name,
 					s->s_id);
 		btrfs_sb(s)->bdev_holder = fs_type;
@@ -1518,12 +1523,9 @@  static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
 	}
 	if (!error)
 		error = security_sb_set_mnt_opts(s, new_sec_opts, 0, NULL);
+	if (error)
+		goto error_deactivate;
 	security_free_mnt_opts(&new_sec_opts);
-	if (error) {
-		deactivate_locked_super(s);
-		return ERR_PTR(error);
-	}
-
 	return dget(s->s_root);
 
 error_fs_info:
@@ -1531,6 +1533,10 @@  static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
 error_sec_opts:
 	security_free_mnt_opts(&new_sec_opts);
 	return ERR_PTR(error);
+
+error_deactivate:
+	deactivate_locked_super(s);
+	goto error_sec_opts;
 }
 
 /*
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 3ac1a3aa8939bc..b909e593c0f1bc 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1272,8 +1272,6 @@  static int devid_cmp(void *priv, const struct list_head *a,
 int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
 		       blk_mode_t flags, void *holder)
 {
-	int ret;
-
 	lockdep_assert_held(&uuid_mutex);
 	/*
 	 * The device_list_mutex cannot be taken here in case opening the
@@ -1282,14 +1280,11 @@  int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
 	 * We also don't need the lock here as this is called during mount and
 	 * exclusion is provided by uuid_mutex
 	 */
-	if (!fs_devices->is_open) {
-		list_sort(NULL, &fs_devices->devices, devid_cmp);
-		ret = open_fs_devices(fs_devices, flags, holder);
-		if (ret)
-			return ret;
-	}
-	fs_devices->in_use++;
-	return 0;
+	ASSERT(fs_devices->in_use);
+	if (fs_devices->is_open)
+		return 0;
+	list_sort(NULL, &fs_devices->devices, devid_cmp);
+	return open_fs_devices(fs_devices, flags, holder);
 }
 
 void btrfs_release_disk_super(struct btrfs_super_block *super)