diff options
author | Eryu Guan <guaneryu@gmail.com> | 2014-10-13 00:42:12 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-11-20 20:14:28 -0500 |
commit | 2fc9f6baa24ac230166df41ed636224969523341 (patch) | |
tree | 41ea291cb5ab8d7d1eef3c4c5a49afddec266a1b /fs/btrfs/dev-replace.c | |
parent | 6b3a4d60dbf7a60b91d810498e8c212f26718efd (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.c | 12 |
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 | ||
429 | leave: | 435 | leave: |
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 |