From 24e0474b59538cdb9d2b7318ec7c7ae9f6faf85d Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Sat, 13 Feb 2016 10:01:35 +0800 Subject: btrfs: create helper btrfs_find_device_by_user_input() The patch renames btrfs_dev_replace_find_srcdev() to btrfs_find_device_by_user_input() and moves it to volumes.c, so that delete device can use it. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) (limited to 'fs/btrfs/dev-replace.c') diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 26bcb487f958..7ad8ae994ca0 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -44,9 +44,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree( struct btrfs_fs_info *fs_info, struct btrfs_device *srcdev, struct btrfs_device *tgtdev); -static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid, - char *srcdev_name, - struct btrfs_device **device); static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info); static int btrfs_dev_replace_kthread(void *data); static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info); @@ -329,7 +326,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root, /* the disk copy procedure reuses the scrub code */ mutex_lock(&fs_info->volume_mutex); - ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid, + ret = btrfs_find_device_by_user_input(root, args->start.srcdevid, args->start.srcdev_name, &src_device); if (ret) { @@ -626,25 +623,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree( write_unlock(&em_tree->lock); } -static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid, - char *srcdev_name, - struct btrfs_device **device) -{ - int ret; - - if (srcdevid) { - ret = 0; - *device = btrfs_find_device(root->fs_info, srcdevid, NULL, - NULL); - if (!*device) - ret = -ENOENT; - } else { - ret = btrfs_find_device_missing_or_by_path(root, srcdev_name, - device); - } - return ret; -} - void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, struct btrfs_ioctl_dev_replace_args *args) { -- cgit v1.2.3-70-g09d2 From b3d1b1532ff9620ff5dba891a96f3e912005eb10 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Sat, 13 Feb 2016 10:01:37 +0800 Subject: btrfs: enhance btrfs_find_device_by_user_input() to check device path The operation of device replace and device delete follows same steps upto some depth with in btrfs kernel, however they don't share codes. This enhancement will help replace and delete to share codes. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 4 ---- fs/btrfs/volumes.c | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'fs/btrfs/dev-replace.c') diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 7ad8ae994ca0..fdd2880707df 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -320,10 +320,6 @@ int btrfs_dev_replace_start(struct btrfs_root *root, return -EINVAL; } - if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') || - args->start.tgtdev_name[0] == '\0') - return -EINVAL; - /* the disk copy procedure reuses the scrub code */ mutex_lock(&fs_info->volume_mutex); ret = btrfs_find_device_by_user_input(root, args->start.srcdevid, diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 40bbe0a2715b..d74260567bea 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2113,6 +2113,9 @@ int btrfs_find_device_by_user_input(struct btrfs_root *root, u64 srcdevid, if (!*device) ret = -ENOENT; } else { + if (!srcdev_name || !srcdev_name[0]) + return -EINVAL; + ret = btrfs_find_device_missing_or_by_path(root, srcdev_name, device); } -- cgit v1.2.3-70-g09d2 From 5c5c0df05deaebcdcc9bb31bdca3812a7c22230f Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 15 Feb 2016 16:39:55 +0100 Subject: btrfs: rename btrfs_find_device_by_user_input For clarity how we are going to find the device, let's call it a device specifier, devspec for short. Also rename the arguments that are a leftover from previous function purpose. Reviewed-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 2 +- fs/btrfs/volumes.c | 17 ++++++++++------- fs/btrfs/volumes.h | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) (limited to 'fs/btrfs/dev-replace.c') diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index fdd2880707df..b7f5f4aa6e86 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -322,7 +322,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root, /* the disk copy procedure reuses the scrub code */ mutex_lock(&fs_info->volume_mutex); - ret = btrfs_find_device_by_user_input(root, args->start.srcdevid, + ret = btrfs_find_device_by_devspec(root, args->start.srcdevid, args->start.srcdev_name, &src_device); if (ret) { diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 055fbebea199..e43b01e438b1 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1780,7 +1780,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid) if (ret) goto out; - ret = btrfs_find_device_by_user_input(root, devid, device_path, + ret = btrfs_find_device_by_devspec(root, devid, device_path, &device); if (ret) goto out; @@ -2065,23 +2065,26 @@ int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, } } -int btrfs_find_device_by_user_input(struct btrfs_root *root, u64 srcdevid, - char *srcdev_name, +/* + * Lookup a device given by device id, or the path if the id is 0. + */ +int btrfs_find_device_by_devspec(struct btrfs_root *root, u64 devid, + char *devpath, struct btrfs_device **device) { int ret; - if (srcdevid) { + if (devid) { ret = 0; - *device = btrfs_find_device(root->fs_info, srcdevid, NULL, + *device = btrfs_find_device(root->fs_info, devid, NULL, NULL); if (!*device) ret = -ENOENT; } else { - if (!srcdev_name || !srcdev_name[0]) + if (!devpath || !devpath[0]) return -EINVAL; - ret = btrfs_find_device_missing_or_by_path(root, srcdev_name, + ret = btrfs_find_device_missing_or_by_path(root, devpath, device); } return ret; diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index a13a538cb01e..febdb7bc9370 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -448,8 +448,8 @@ void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices, int step); int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, char *device_path, struct btrfs_device **device); -int btrfs_find_device_by_user_input(struct btrfs_root *root, u64 srcdevid, - char *srcdev_name, +int btrfs_find_device_by_devspec(struct btrfs_root *root, u64 devid, + char *devpath, struct btrfs_device **device); struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, const u64 *devid, -- cgit v1.2.3-70-g09d2 From fc23c246d72d21385be115305d1cb85fcc34acad Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Thu, 24 Mar 2016 18:48:12 +0800 Subject: btrfs: use fs_info directly Local variable fs_info, contains root->fs_info, use it. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs/btrfs/dev-replace.c') diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index b7f5f4aa6e86..1a3d24592859 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -368,7 +368,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root, WARN_ON(!tgt_device); dev_replace->tgtdev = tgt_device; - btrfs_info_in_rcu(root->fs_info, + btrfs_info_in_rcu(fs_info, "dev_replace from %s (devid %llu) to %s started", src_device->missing ? "" : rcu_str_deref(src_device->name), @@ -394,9 +394,9 @@ int btrfs_dev_replace_start(struct btrfs_root *root, ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device); if (ret) - btrfs_err(root->fs_info, "kobj add dev failed %d\n", ret); + btrfs_err(fs_info, "kobj add dev failed %d\n", ret); - btrfs_wait_ordered_roots(root->fs_info, -1); + btrfs_wait_ordered_roots(fs_info, -1); /* force writing the updated state information to disk */ trans = btrfs_start_transaction(root, 0); @@ -414,7 +414,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root, btrfs_device_get_total_bytes(src_device), &dev_replace->scrub_progress, 0, 1); - ret = btrfs_dev_replace_finishing(root->fs_info, ret); + ret = btrfs_dev_replace_finishing(fs_info, ret); /* don't warn if EINPROGRESS, someone else might be running scrub */ if (ret == -EINPROGRESS) { args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS; -- cgit v1.2.3-70-g09d2 From b5255456c529155730c837f8cfcea47e8feb85ca Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Thu, 24 Mar 2016 18:48:14 +0800 Subject: btrfs: refactor btrfs_dev_replace_start for reuse A refactor patch, and avoids user input verification in the btrfs_dev_replace_start(), and so this function can be reused. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 58 ++++++++++++++++++++++++++++++++------------------ fs/btrfs/dev-replace.h | 4 +++- fs/btrfs/ioctl.c | 2 +- 3 files changed, 41 insertions(+), 23 deletions(-) (limited to 'fs/btrfs/dev-replace.c') diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 1a3d24592859..5aebedf12b5f 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -302,8 +302,8 @@ void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info) dev_replace->cursor_left_last_write_of_item; } -int btrfs_dev_replace_start(struct btrfs_root *root, - struct btrfs_ioctl_dev_replace_args *args) +int btrfs_dev_replace_start(struct btrfs_root *root, char *tgtdev_name, + u64 srcdevid, char *srcdev_name, int read_src) { struct btrfs_trans_handle *trans; struct btrfs_fs_info *fs_info = root->fs_info; @@ -312,25 +312,16 @@ int btrfs_dev_replace_start(struct btrfs_root *root, struct btrfs_device *tgt_device = NULL; struct btrfs_device *src_device = NULL; - switch (args->start.cont_reading_from_srcdev_mode) { - case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS: - case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID: - break; - default: - return -EINVAL; - } - /* the disk copy procedure reuses the scrub code */ mutex_lock(&fs_info->volume_mutex); - ret = btrfs_find_device_by_devspec(root, args->start.srcdevid, - args->start.srcdev_name, - &src_device); + ret = btrfs_find_device_by_devspec(root, srcdevid, + srcdev_name, &src_device); if (ret) { mutex_unlock(&fs_info->volume_mutex); return ret; } - ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name, + ret = btrfs_init_dev_replace_tgtdev(root, tgtdev_name, src_device, &tgt_device); mutex_unlock(&fs_info->volume_mutex); if (ret) @@ -357,12 +348,11 @@ int btrfs_dev_replace_start(struct btrfs_root *root, break; case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: - args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED; + ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED; goto leave; } - dev_replace->cont_reading_from_srcdev_mode = - args->start.cont_reading_from_srcdev_mode; + dev_replace->cont_reading_from_srcdev_mode = read_src; WARN_ON(!src_device); dev_replace->srcdev = src_device; WARN_ON(!tgt_device); @@ -389,7 +379,6 @@ int btrfs_dev_replace_start(struct btrfs_root *root, dev_replace->item_needs_writeback = 1; atomic64_set(&dev_replace->num_write_errors, 0); atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0); - args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR; btrfs_dev_replace_unlock(dev_replace, 1); ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device); @@ -415,10 +404,8 @@ int btrfs_dev_replace_start(struct btrfs_root *root, &dev_replace->scrub_progress, 0, 1); ret = btrfs_dev_replace_finishing(fs_info, ret); - /* don't warn if EINPROGRESS, someone else might be running scrub */ if (ret == -EINPROGRESS) { - args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS; - ret = 0; + ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS; } else { WARN_ON(ret); } @@ -433,6 +420,35 @@ leave: return ret; } +int btrfs_dev_replace_by_ioctl(struct btrfs_root *root, + struct btrfs_ioctl_dev_replace_args *args) +{ + int ret; + + switch (args->start.cont_reading_from_srcdev_mode) { + case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS: + case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID: + break; + default: + return -EINVAL; + } + + if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') || + args->start.tgtdev_name[0] == '\0') + return -EINVAL; + + ret = btrfs_dev_replace_start(root, args->start.tgtdev_name, + args->start.srcdevid, + args->start.srcdev_name, + args->start.cont_reading_from_srcdev_mode); + args->result = ret; + /* don't warn if EINPROGRESS, someone else might be running scrub */ + if (ret == BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS) + ret = 0; + + return ret; +} + /* * blocked until all flighting bios are finished. */ diff --git a/fs/btrfs/dev-replace.h b/fs/btrfs/dev-replace.h index 29e3ef5f96bd..e922b42d91df 100644 --- a/fs/btrfs/dev-replace.h +++ b/fs/btrfs/dev-replace.h @@ -25,8 +25,10 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info); int btrfs_run_dev_replace(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info); void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info); -int btrfs_dev_replace_start(struct btrfs_root *root, +int btrfs_dev_replace_by_ioctl(struct btrfs_root *root, struct btrfs_ioctl_dev_replace_args *args); +int btrfs_dev_replace_start(struct btrfs_root *root, char *tgtdev_name, + u64 srcdevid, char *srcdev_name, int read_src); void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, struct btrfs_ioctl_dev_replace_args *args); int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info, diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 65903ec5e1c0..36b1ed223509 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -4430,7 +4430,7 @@ static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg) 1)) { ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; } else { - ret = btrfs_dev_replace_start(root, p); + ret = btrfs_dev_replace_by_ioctl(root, p); atomic_set( &root->fs_info->mutually_exclusive_operation_running, 0); -- cgit v1.2.3-70-g09d2 From 8ed01abe7da6af62f2089da9a4c1fe839dc638f5 Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Thu, 14 Apr 2016 18:24:10 +0800 Subject: btrfs: s_bdev is not null after missing replace Yauhen reported in the ML that s_bdev is null at mount, and s_bdev gets updated to some device when missing device is replaced, as because bdev is null for missing device, things gets matched up. Fix this by checking if s_bdev is set. I didn't want to completely remove updating s_bdev because the future multi device support at vfs layer may need it. Signed-off-by: Anand Jain Reported-by: Yauhen Kharuzhy Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 3 ++- fs/btrfs/volumes.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'fs/btrfs/dev-replace.c') diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 5aebedf12b5f..c93eec9ca433 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -569,7 +569,8 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, ASSERT(list_empty(&src_device->resized_list)); tgt_device->commit_total_bytes = src_device->commit_total_bytes; tgt_device->commit_bytes_used = src_device->bytes_used; - if (fs_info->sb->s_bdev == src_device->bdev) + if (fs_info->sb->s_bdev && + (fs_info->sb->s_bdev == src_device->bdev)) fs_info->sb->s_bdev = tgt_device->bdev; if (fs_info->fs_devices->latest_bdev == src_device->bdev) fs_info->fs_devices->latest_bdev = tgt_device->bdev; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index e43b01e438b1..41bc384f3483 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1848,7 +1848,8 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid) next_device = list_entry(root->fs_info->fs_devices->devices.next, struct btrfs_device, dev_list); - if (device->bdev == root->fs_info->sb->s_bdev) + if (root->fs_info->sb->s_bdev && + (root->fs_info->sb->s_bdev == device->bdev)) root->fs_info->sb->s_bdev = next_device->bdev; if (device->bdev == root->fs_info->fs_devices->latest_bdev) root->fs_info->fs_devices->latest_bdev = next_device->bdev; @@ -1996,7 +1997,8 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, next_device = list_entry(fs_info->fs_devices->devices.next, struct btrfs_device, dev_list); - if (tgtdev->bdev == fs_info->sb->s_bdev) + if (fs_info->sb->s_bdev && + (tgtdev->bdev == fs_info->sb->s_bdev)) fs_info->sb->s_bdev = next_device->bdev; if (tgtdev->bdev == fs_info->fs_devices->latest_bdev) fs_info->fs_devices->latest_bdev = next_device->bdev; -- cgit v1.2.3-70-g09d2 From 88acff64c621aaeee2a4fe0ed124c77358069bce Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 3 May 2016 17:44:43 +0800 Subject: btrfs: cleanup assigning next active device with a check Creates helper fucntion as needed by the device delete and replace operations. Also now it checks if the next device being assigned is an active device. Signed-off-by: Anand Jain Signed-off-by: David Sterba --- fs/btrfs/dev-replace.c | 8 +++---- fs/btrfs/volumes.c | 60 ++++++++++++++++++++++++++++++++++++-------------- fs/btrfs/volumes.h | 2 ++ 3 files changed, 48 insertions(+), 22 deletions(-) (limited to 'fs/btrfs/dev-replace.c') diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index c93eec9ca433..1f193f742f21 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -569,11 +569,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, ASSERT(list_empty(&src_device->resized_list)); tgt_device->commit_total_bytes = src_device->commit_total_bytes; tgt_device->commit_bytes_used = src_device->bytes_used; - if (fs_info->sb->s_bdev && - (fs_info->sb->s_bdev == src_device->bdev)) - fs_info->sb->s_bdev = tgt_device->bdev; - if (fs_info->fs_devices->latest_bdev == src_device->bdev) - fs_info->fs_devices->latest_bdev = tgt_device->bdev; + + btrfs_assign_next_active_device(fs_info, src_device, tgt_device); + list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); fs_info->fs_devices->rw_devices++; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 41bc384f3483..3fb0786060dd 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1756,10 +1756,49 @@ static int btrfs_check_raid_min_devices(struct btrfs_fs_info *fs_info, return 0; } +struct btrfs_device *btrfs_find_next_active_device(struct btrfs_fs_devices *fs_devs, + struct btrfs_device *device) +{ + struct btrfs_device *next_device; + + list_for_each_entry(next_device, &fs_devs->devices, dev_list) { + if (next_device != device && + !next_device->missing && next_device->bdev) + return next_device; + } + + return NULL; +} + +/* + * Helper function to check if the given device is part of s_bdev / latest_bdev + * and replace it with the provided or the next active device, in the context + * where this function called, there should be always be another device (or + * this_dev) which is active. + */ +void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info, + struct btrfs_device *device, struct btrfs_device *this_dev) +{ + struct btrfs_device *next_device; + + if (this_dev) + next_device = this_dev; + else + next_device = btrfs_find_next_active_device(fs_info->fs_devices, + device); + ASSERT(next_device); + + if (fs_info->sb->s_bdev && + (fs_info->sb->s_bdev == device->bdev)) + fs_info->sb->s_bdev = next_device->bdev; + + if (fs_info->fs_devices->latest_bdev == device->bdev) + fs_info->fs_devices->latest_bdev = next_device->bdev; +} + int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid) { struct btrfs_device *device; - struct btrfs_device *next_device; struct btrfs_fs_devices *cur_devices; u64 num_devices; int ret = 0; @@ -1846,13 +1885,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid) if (device->missing) device->fs_devices->missing_devices--; - next_device = list_entry(root->fs_info->fs_devices->devices.next, - struct btrfs_device, dev_list); - if (root->fs_info->sb->s_bdev && - (root->fs_info->sb->s_bdev == device->bdev)) - root->fs_info->sb->s_bdev = next_device->bdev; - if (device->bdev == root->fs_info->fs_devices->latest_bdev) - root->fs_info->fs_devices->latest_bdev = next_device->bdev; + btrfs_assign_next_active_device(root->fs_info, device, NULL); if (device->bdev) { device->fs_devices->open_devices--; @@ -1981,8 +2014,6 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info, void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, struct btrfs_device *tgtdev) { - struct btrfs_device *next_device; - mutex_lock(&uuid_mutex); WARN_ON(!tgtdev); mutex_lock(&fs_info->fs_devices->device_list_mutex); @@ -1995,13 +2026,8 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, } fs_info->fs_devices->num_devices--; - next_device = list_entry(fs_info->fs_devices->devices.next, - struct btrfs_device, dev_list); - if (fs_info->sb->s_bdev && - (tgtdev->bdev == fs_info->sb->s_bdev)) - fs_info->sb->s_bdev = next_device->bdev; - if (tgtdev->bdev == fs_info->fs_devices->latest_bdev) - fs_info->fs_devices->latest_bdev = next_device->bdev; + btrfs_assign_next_active_device(fs_info, tgtdev, NULL); + list_del_rcu(&tgtdev->dev_list); call_rcu(&tgtdev->rcu, free_device); diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index febdb7bc9370..7038017bf93b 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -445,6 +445,8 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, struct btrfs_fs_devices **fs_devices_ret); int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices, int step); +void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info, + struct btrfs_device *device, struct btrfs_device *this_dev); int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, char *device_path, struct btrfs_device **device); -- cgit v1.2.3-70-g09d2