btrfs: Stop using call_rcu for device freeing
authorNikolay Borisov <nborisov@suse.com>
Wed, 27 Mar 2019 12:24:11 +0000 (14:24 +0200)
committerDavid Sterba <dsterba@suse.com>
Mon, 29 Apr 2019 17:02:37 +0000 (19:02 +0200)
btrfs_device structs are freed from RCU context since device iteration
is protected by RCU. Currently this is achieved by using call_rcu since
no blocking functions are called within btrfs_free_device. Future
refactoring of pending/pinned chunks will require calling sleeping
functions.

This patch is in preparation for these changes by simply switching from
RCU callbacks to explicit calls of synchronize_rcu and calling
btrfs_free_device directly. This is functionally equivalent, making sure
that there are no readers at that time.

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/volumes.c
fs/btrfs/volumes.h

index 66b8b49..2bde9e9 100644 (file)
@@ -1231,14 +1231,6 @@ again:
        mutex_unlock(&uuid_mutex);
 }
 
-static void free_device_rcu(struct rcu_head *head)
-{
-       struct btrfs_device *device;
-
-       device = container_of(head, struct btrfs_device, rcu);
-       btrfs_free_device(device);
-}
-
 static void btrfs_close_bdev(struct btrfs_device *device)
 {
        if (!device->bdev)
@@ -1286,7 +1278,8 @@ static void btrfs_close_one_device(struct btrfs_device *device)
        list_replace_rcu(&device->dev_list, &new_device->dev_list);
        new_device->fs_devices = device->fs_devices;
 
-       call_rcu(&device->rcu, free_device_rcu);
+       synchronize_rcu();
+       btrfs_free_device(device);
 }
 
 static int close_fs_devices(struct btrfs_fs_devices *fs_devices)
@@ -2243,7 +2236,8 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
                btrfs_scratch_superblocks(device->bdev, device->name->str);
 
        btrfs_close_bdev(device);
-       call_rcu(&device->rcu, free_device_rcu);
+       synchronize_rcu();
+       btrfs_free_device(device);
 
        if (cur_devices->open_devices == 0) {
                while (fs_devices) {
@@ -2311,7 +2305,8 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info,
        }
 
        btrfs_close_bdev(srcdev);
-       call_rcu(&srcdev->rcu, free_device_rcu);
+       synchronize_rcu();
+       btrfs_free_device(srcdev);
 
        /* if this is no devs we rather delete the fs_devices */
        if (!fs_devices->num_devices) {
@@ -2369,7 +2364,8 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev)
        btrfs_scratch_superblocks(tgtdev->bdev, tgtdev->name->str);
 
        btrfs_close_bdev(tgtdev);
-       call_rcu(&tgtdev->rcu, free_device_rcu);
+       synchronize_rcu();
+       btrfs_free_device(tgtdev);
 }
 
 static struct btrfs_device *btrfs_find_device_by_path(
index b9912b9..d3658a4 100644 (file)
@@ -118,7 +118,6 @@ struct btrfs_device {
        struct scrub_ctx *scrub_ctx;
 
        struct btrfs_work work;
-       struct rcu_head rcu;
 
        /* readahead state */
        atomic_t reada_in_flight;