]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
btrfs: extend locked section when adding a new device in device_list_add
authorAnand Jain <anand.jain@oracle.com>
Tue, 29 May 2018 06:10:20 +0000 (14:10 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 6 Aug 2018 11:12:46 +0000 (13:12 +0200)
Make sure the device_list_lock is held the whole time:

* when the device is being looked up
* new device is initialized and put to the list
* the list counters are updated (fs_devices::opened, fs_devices::total_devices)

Signed-off-by: Anand Jain <anand.jain@oracle.com>
[ update changelog ]
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/volumes.c

index c84a9e22daf1e06395f72512594d06e019a9c78e..870732ef356ceb66a6efb78f8fd5e9e0ab6eb6ad 100644 (file)
@@ -762,21 +762,26 @@ static noinline struct btrfs_device *device_list_add(const char *path,
                if (IS_ERR(fs_devices))
                        return ERR_CAST(fs_devices);
 
+               mutex_lock(&fs_devices->device_list_mutex);
                list_add(&fs_devices->fs_list, &fs_uuids);
 
                device = NULL;
        } else {
+               mutex_lock(&fs_devices->device_list_mutex);
                device = find_device(fs_devices, devid,
                                disk_super->dev_item.uuid);
        }
 
        if (!device) {
-               if (fs_devices->opened)
+               if (fs_devices->opened) {
+                       mutex_unlock(&fs_devices->device_list_mutex);
                        return ERR_PTR(-EBUSY);
+               }
 
                device = btrfs_alloc_device(NULL, &devid,
                                            disk_super->dev_item.uuid);
                if (IS_ERR(device)) {
+                       mutex_unlock(&fs_devices->device_list_mutex);
                        /* we can safely leave the fs_devices entry around */
                        return device;
                }
@@ -784,14 +789,13 @@ static noinline struct btrfs_device *device_list_add(const char *path,
                name = rcu_string_strdup(path, GFP_NOFS);
                if (!name) {
                        btrfs_free_device(device);
+                       mutex_unlock(&fs_devices->device_list_mutex);
                        return ERR_PTR(-ENOMEM);
                }
                rcu_assign_pointer(device->name, name);
 
-               mutex_lock(&fs_devices->device_list_mutex);
                list_add_rcu(&device->dev_list, &fs_devices->devices);
                fs_devices->num_devices++;
-               mutex_unlock(&fs_devices->device_list_mutex);
 
                device->fs_devices = fs_devices;
                *new_device_added = true;
@@ -838,12 +842,15 @@ static noinline struct btrfs_device *device_list_add(const char *path,
                         * with larger generation number or the last-in if
                         * generation are equal.
                         */
+                       mutex_unlock(&fs_devices->device_list_mutex);
                        return ERR_PTR(-EEXIST);
                }
 
                name = rcu_string_strdup(path, GFP_NOFS);
-               if (!name)
+               if (!name) {
+                       mutex_unlock(&fs_devices->device_list_mutex);
                        return ERR_PTR(-ENOMEM);
+               }
                rcu_string_free(device->name);
                rcu_assign_pointer(device->name, name);
                if (test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state)) {
@@ -863,6 +870,7 @@ static noinline struct btrfs_device *device_list_add(const char *path,
 
        fs_devices->total_devices = btrfs_super_num_devices(disk_super);
 
+       mutex_unlock(&fs_devices->device_list_mutex);
        return device;
 }