aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/dev-replace.c
diff options
context:
space:
mode:
authorEryu Guan <guaneryu@gmail.com>2014-10-13 00:42:12 -0400
committerChris Mason <clm@fb.com>2014-11-20 20:14:28 -0500
commit2fc9f6baa24ac230166df41ed636224969523341 (patch)
tree41ea291cb5ab8d7d1eef3c4c5a49afddec266a1b /fs/btrfs/dev-replace.c
parent6b3a4d60dbf7a60b91d810498e8c212f26718efd (diff)
Btrfs: return failure if btrfs_dev_replace_finishing() failed
device replace could fail due to another running scrub process or any other errors btrfs_scrub_dev() may hit, but this failure doesn't get returned to userspace. The following steps could reproduce this issue mkfs -t btrfs -f /dev/sdb1 /dev/sdb2 mount /dev/sdb1 /mnt/btrfs while true; do btrfs scrub start -B /mnt/btrfs >/dev/null 2>&1; done & btrfs replace start -Bf /dev/sdb2 /dev/sdb3 /mnt/btrfs # if this replace succeeded, do the following and repeat until # you see this log in dmesg # BTRFS: btrfs_scrub_dev(/dev/sdb2, 2, /dev/sdb3) failed -115 #btrfs replace start -Bf /dev/sdb3 /dev/sdb2 /mnt/btrfs # once you see the error log in dmesg, check return value of # replace echo $? Introduce a new dev replace result BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS to catch -EINPROGRESS explicitly and return other errors directly to userspace. Signed-off-by: Eryu Guan <guaneryu@gmail.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/dev-replace.c')
-rw-r--r--fs/btrfs/dev-replace.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 6f662b34ba0e..971c061eb1ce 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -422,9 +422,15 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
422 &dev_replace->scrub_progress, 0, 1); 422 &dev_replace->scrub_progress, 0, 1);
423 423
424 ret = btrfs_dev_replace_finishing(root->fs_info, ret); 424 ret = btrfs_dev_replace_finishing(root->fs_info, ret);
425 WARN_ON(ret); 425 /* don't warn if EINPROGRESS, someone else might be running scrub */
426 if (ret == -EINPROGRESS) {
427 args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS;
428 ret = 0;
429 } else {
430 WARN_ON(ret);
431 }
426 432
427 return 0; 433 return ret;
428 434
429leave: 435leave:
430 dev_replace->srcdev = NULL; 436 dev_replace->srcdev = NULL;
@@ -542,7 +548,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
542 btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); 548 btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
543 mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); 549 mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
544 550
545 return 0; 551 return scrub_ret;
546 } 552 }
547 553
548 printk_in_rcu(KERN_INFO 554 printk_in_rcu(KERN_INFO