Thread (12 messages) 12 messages, 4 authors, 2021-09-18

Re: [PATCH RFC V5 2/2] btrfs: consolidate device_list_mutex in prepare_sprout to its parent

flat view

From: Anand Jain <hidden>
Date: 2021-09-18 00:10:46


On 17/09/2021 23:37, David Sterba wrote:
On Tue, Aug 31, 2021 at 09:21:29AM +0800, Anand Jain wrote:
quoted
btrfs_prepare_sprout() moves seed devices into its own struct fs_devices,
so that its parent function btrfs_init_new_device() can add the new sprout
device to fs_info->fs_devices.

Both btrfs_prepare_sprout() and btrfs_init_new_device() needs
device_list_mutex. But they are holding it sequentially, thus creates a
small window to an opportunity to race. Close this opportunity and hold
device_list_mutex common to both btrfs_init_new_device() and
btrfs_prepare_sprout().
I don't se what exactly would go wrong with the separate device list
locking, but I see at least one potential problem with the new code.
quoted
Signed-off-by: Anand Jain <redacted>
---
RFC because IMO the cleanup of device_list_mutex makes sense even though
there isn't another thread that could race potentially race as of now.

Depends on
  [PATCH v2] btrfs: fix lockdep warning while mounting sprout fs
which removed the device_list_mutex from clone_fs_devices() otherwise
this patch will cause a double mutex error.

v2: fix the missing mutex_unlock in the error return
v3: -
v4: -
v5: - (Except for the change in below SO comments)

  fs/btrfs/volumes.c | 7 ++++---
  1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index fa9fe47b5b68..53ead67b625c 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2369,6 +2369,8 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info)
  	u64 super_flags;
  
  	lockdep_assert_held(&uuid_mutex);
+	lockdep_assert_held(&fs_devices->device_list_mutex);
+
  	if (!fs_devices->seeding)
  		return -EINVAL;
  
@@ -2400,7 +2402,6 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info)
  	INIT_LIST_HEAD(&seed_devices->alloc_list);
quoted
  	mutex_init(&seed_devices->device_list_mutex);
 BTW mutex_init here will go, as the sprout's private
 fs_devices::device_list_mutex is unused. It is a pending cleanup.
A few lines before this one there's alloc_fs_devices and
clone_fs_devices, both allocating memory. This would happen under a big
lock as device_list_mutex also protects superblock write. This is a
pattern to avoid.
 Oh. That's right. Thx. One way is to flag NOFS alloc.
A rough idea would be to split btrfs_prepare_sprout into parts where the
allocations are not done under the lock and the locked part. It could be
partially inlined to btrfs_init_new_device.
 I think you mean something like this...

 btrfs_init_new_device()
 <snip>
   if seeding_dev
      alloc_prepare_sprout
   mutex_lock(&fs_devices->device_list_mutex);
   if seeding_dev
      finish_prepare_sprout
   <snip>
   mutex_unlock(&fs_devices->device_list_mutex);

 I am trying.

Thanks, Anand
quoted
  
-	mutex_lock(&fs_devices->device_list_mutex);
  	list_splice_init_rcu(&fs_devices->devices, &seed_devices->devices,
  			      synchronize_rcu);
  	list_for_each_entry(device, &seed_devices->devices, dev_list)
@@ -2416,7 +2417,6 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info)
  	generate_random_uuid(fs_devices->fsid);
  	memcpy(fs_devices->metadata_uuid, fs_devices->fsid, BTRFS_FSID_SIZE);
  	memcpy(disk_super->fsid, fs_devices->fsid, BTRFS_FSID_SIZE);
-	mutex_unlock(&fs_devices->device_list_mutex);
  
  	super_flags = btrfs_super_flags(disk_super) &
  		      ~BTRFS_SUPER_FLAG_SEEDING;
@@ -2591,10 +2591,12 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
  	device->dev_stats_valid = 1;
  	set_blocksize(device->bdev, BTRFS_BDEV_BLOCKSIZE);
  
+	mutex_lock(&fs_devices->device_list_mutex);
  	if (seeding_dev) {
  		btrfs_clear_sb_rdonly(sb);
  		ret = btrfs_prepare_sprout(fs_info);
  		if (ret) {
+			mutex_unlock(&fs_devices->device_list_mutex);
  			btrfs_abort_transaction(trans, ret);
  			goto error_trans;
  		}
@@ -2604,7 +2606,6 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
  
  	device->fs_devices = fs_devices;
  
-	mutex_lock(&fs_devices->device_list_mutex);
  	mutex_lock(&fs_info->chunk_mutex);
  	list_add_rcu(&device->dev_list, &fs_devices->devices);
  	list_add(&device->dev_alloc_list, &fs_devices->alloc_list);
-- 
2.31.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help