diff options
Diffstat (limited to 'fs/btrfs/dev-replace.c')
| -rw-r--r-- | fs/btrfs/dev-replace.c | 80 |
1 files changed, 44 insertions, 36 deletions
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 5fe1ca8abc70..7c655f9a7a50 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c | |||
| @@ -388,7 +388,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, | |||
| 388 | if (ret) | 388 | if (ret) |
| 389 | btrfs_err(fs_info, "kobj add dev failed %d", ret); | 389 | btrfs_err(fs_info, "kobj add dev failed %d", ret); |
| 390 | 390 | ||
| 391 | btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1); | 391 | btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1); |
| 392 | 392 | ||
| 393 | /* force writing the updated state information to disk */ | 393 | /* force writing the updated state information to disk */ |
| 394 | trans = btrfs_start_transaction(root, 0); | 394 | trans = btrfs_start_transaction(root, 0); |
| @@ -507,7 +507,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 507 | mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); | 507 | mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); |
| 508 | return ret; | 508 | return ret; |
| 509 | } | 509 | } |
| 510 | btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1); | 510 | btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1); |
| 511 | 511 | ||
| 512 | trans = btrfs_start_transaction(root, 0); | 512 | trans = btrfs_start_transaction(root, 0); |
| 513 | if (IS_ERR(trans)) { | 513 | if (IS_ERR(trans)) { |
| @@ -639,11 +639,39 @@ static void btrfs_dev_replace_update_device_in_mapping_tree( | |||
| 639 | write_unlock(&em_tree->lock); | 639 | write_unlock(&em_tree->lock); |
| 640 | } | 640 | } |
| 641 | 641 | ||
| 642 | /* | ||
| 643 | * Read progress of device replace status according to the state and last | ||
| 644 | * stored position. The value format is the same as for | ||
| 645 | * btrfs_dev_replace::progress_1000 | ||
| 646 | */ | ||
| 647 | static u64 btrfs_dev_replace_progress(struct btrfs_fs_info *fs_info) | ||
| 648 | { | ||
| 649 | struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; | ||
| 650 | u64 ret = 0; | ||
| 651 | |||
| 652 | switch (dev_replace->replace_state) { | ||
| 653 | case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: | ||
| 654 | case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: | ||
| 655 | ret = 0; | ||
| 656 | break; | ||
| 657 | case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: | ||
| 658 | ret = 1000; | ||
| 659 | break; | ||
| 660 | case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: | ||
| 661 | case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: | ||
| 662 | ret = div64_u64(dev_replace->cursor_left, | ||
| 663 | div_u64(btrfs_device_get_total_bytes( | ||
| 664 | dev_replace->srcdev), 1000)); | ||
| 665 | break; | ||
| 666 | } | ||
| 667 | |||
| 668 | return ret; | ||
| 669 | } | ||
| 670 | |||
| 642 | void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, | 671 | void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, |
| 643 | struct btrfs_ioctl_dev_replace_args *args) | 672 | struct btrfs_ioctl_dev_replace_args *args) |
| 644 | { | 673 | { |
| 645 | struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; | 674 | struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; |
| 646 | struct btrfs_device *srcdev; | ||
| 647 | 675 | ||
| 648 | btrfs_dev_replace_lock(dev_replace, 0); | 676 | btrfs_dev_replace_lock(dev_replace, 0); |
| 649 | /* even if !dev_replace_is_valid, the values are good enough for | 677 | /* even if !dev_replace_is_valid, the values are good enough for |
| @@ -656,21 +684,7 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, | |||
| 656 | atomic64_read(&dev_replace->num_write_errors); | 684 | atomic64_read(&dev_replace->num_write_errors); |
| 657 | args->status.num_uncorrectable_read_errors = | 685 | args->status.num_uncorrectable_read_errors = |
| 658 | atomic64_read(&dev_replace->num_uncorrectable_read_errors); | 686 | atomic64_read(&dev_replace->num_uncorrectable_read_errors); |
| 659 | switch (dev_replace->replace_state) { | 687 | args->status.progress_1000 = btrfs_dev_replace_progress(fs_info); |
| 660 | case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: | ||
| 661 | case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: | ||
| 662 | args->status.progress_1000 = 0; | ||
| 663 | break; | ||
| 664 | case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: | ||
| 665 | args->status.progress_1000 = 1000; | ||
| 666 | break; | ||
| 667 | case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: | ||
| 668 | case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: | ||
| 669 | srcdev = dev_replace->srcdev; | ||
| 670 | args->status.progress_1000 = div64_u64(dev_replace->cursor_left, | ||
| 671 | div_u64(btrfs_device_get_total_bytes(srcdev), 1000)); | ||
| 672 | break; | ||
| 673 | } | ||
| 674 | btrfs_dev_replace_unlock(dev_replace, 0); | 688 | btrfs_dev_replace_unlock(dev_replace, 0); |
| 675 | } | 689 | } |
| 676 | 690 | ||
| @@ -690,7 +704,7 @@ static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info) | |||
| 690 | u64 result; | 704 | u64 result; |
| 691 | int ret; | 705 | int ret; |
| 692 | 706 | ||
| 693 | if (fs_info->sb->s_flags & MS_RDONLY) | 707 | if (sb_rdonly(fs_info->sb)) |
| 694 | return -EROFS; | 708 | return -EROFS; |
| 695 | 709 | ||
| 696 | mutex_lock(&dev_replace->lock_finishing_cancel_unmount); | 710 | mutex_lock(&dev_replace->lock_finishing_cancel_unmount); |
| @@ -795,25 +809,19 @@ static int btrfs_dev_replace_kthread(void *data) | |||
| 795 | { | 809 | { |
| 796 | struct btrfs_fs_info *fs_info = data; | 810 | struct btrfs_fs_info *fs_info = data; |
| 797 | struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; | 811 | struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; |
| 798 | struct btrfs_ioctl_dev_replace_args *status_args; | ||
| 799 | u64 progress; | 812 | u64 progress; |
| 800 | 813 | ||
| 801 | status_args = kzalloc(sizeof(*status_args), GFP_KERNEL); | 814 | progress = btrfs_dev_replace_progress(fs_info); |
| 802 | if (status_args) { | 815 | progress = div_u64(progress, 10); |
| 803 | btrfs_dev_replace_status(fs_info, status_args); | 816 | btrfs_info_in_rcu(fs_info, |
| 804 | progress = status_args->status.progress_1000; | 817 | "continuing dev_replace from %s (devid %llu) to %s @%u%%", |
| 805 | kfree(status_args); | 818 | dev_replace->srcdev->missing ? "<missing disk>" |
| 806 | progress = div_u64(progress, 10); | 819 | : rcu_str_deref(dev_replace->srcdev->name), |
| 807 | btrfs_info_in_rcu(fs_info, | 820 | dev_replace->srcdev->devid, |
| 808 | "continuing dev_replace from %s (devid %llu) to %s @%u%%", | 821 | dev_replace->tgtdev ? rcu_str_deref(dev_replace->tgtdev->name) |
| 809 | dev_replace->srcdev->missing ? "<missing disk>" : | 822 | : "<missing target disk>", |
| 810 | rcu_str_deref(dev_replace->srcdev->name), | 823 | (unsigned int)progress); |
| 811 | dev_replace->srcdev->devid, | 824 | |
| 812 | dev_replace->tgtdev ? | ||
| 813 | rcu_str_deref(dev_replace->tgtdev->name) : | ||
| 814 | "<missing target disk>", | ||
| 815 | (unsigned int)progress); | ||
| 816 | } | ||
| 817 | btrfs_dev_replace_continue_on_mount(fs_info); | 825 | btrfs_dev_replace_continue_on_mount(fs_info); |
| 818 | clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); | 826 | clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); |
| 819 | 827 | ||
