diff options
Diffstat (limited to 'fs/btrfs/dev-replace.c')
| -rw-r--r-- | fs/btrfs/dev-replace.c | 82 |
1 files changed, 47 insertions, 35 deletions
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index eea26e1b2fda..6f662b34ba0e 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c | |||
| @@ -168,8 +168,12 @@ no_valid_dev_replace_entry_found: | |||
| 168 | dev_replace->srcdev->total_bytes; | 168 | dev_replace->srcdev->total_bytes; |
| 169 | dev_replace->tgtdev->disk_total_bytes = | 169 | dev_replace->tgtdev->disk_total_bytes = |
| 170 | dev_replace->srcdev->disk_total_bytes; | 170 | dev_replace->srcdev->disk_total_bytes; |
| 171 | dev_replace->tgtdev->commit_total_bytes = | ||
| 172 | dev_replace->srcdev->commit_total_bytes; | ||
| 171 | dev_replace->tgtdev->bytes_used = | 173 | dev_replace->tgtdev->bytes_used = |
| 172 | dev_replace->srcdev->bytes_used; | 174 | dev_replace->srcdev->bytes_used; |
| 175 | dev_replace->tgtdev->commit_bytes_used = | ||
| 176 | dev_replace->srcdev->commit_bytes_used; | ||
| 173 | } | 177 | } |
| 174 | dev_replace->tgtdev->is_tgtdev_for_dev_replace = 1; | 178 | dev_replace->tgtdev->is_tgtdev_for_dev_replace = 1; |
| 175 | btrfs_init_dev_replace_tgtdev_for_resume(fs_info, | 179 | btrfs_init_dev_replace_tgtdev_for_resume(fs_info, |
| @@ -329,30 +333,34 @@ int btrfs_dev_replace_start(struct btrfs_root *root, | |||
| 329 | args->start.tgtdev_name[0] == '\0') | 333 | args->start.tgtdev_name[0] == '\0') |
| 330 | return -EINVAL; | 334 | return -EINVAL; |
| 331 | 335 | ||
| 332 | mutex_lock(&fs_info->volume_mutex); | 336 | /* |
| 333 | ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name, | 337 | * Here we commit the transaction to make sure commit_total_bytes |
| 334 | &tgt_device); | 338 | * of all the devices are updated. |
| 335 | if (ret) { | 339 | */ |
| 336 | btrfs_err(fs_info, "target device %s is invalid!", | 340 | trans = btrfs_attach_transaction(root); |
| 337 | args->start.tgtdev_name); | 341 | if (!IS_ERR(trans)) { |
| 338 | mutex_unlock(&fs_info->volume_mutex); | 342 | ret = btrfs_commit_transaction(trans, root); |
| 339 | return -EINVAL; | 343 | if (ret) |
| 344 | return ret; | ||
| 345 | } else if (PTR_ERR(trans) != -ENOENT) { | ||
| 346 | return PTR_ERR(trans); | ||
| 340 | } | 347 | } |
| 341 | 348 | ||
| 349 | /* the disk copy procedure reuses the scrub code */ | ||
| 350 | mutex_lock(&fs_info->volume_mutex); | ||
| 342 | ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid, | 351 | ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid, |
| 343 | args->start.srcdev_name, | 352 | args->start.srcdev_name, |
| 344 | &src_device); | 353 | &src_device); |
| 345 | mutex_unlock(&fs_info->volume_mutex); | ||
| 346 | if (ret) { | 354 | if (ret) { |
| 347 | ret = -EINVAL; | 355 | mutex_unlock(&fs_info->volume_mutex); |
| 348 | goto leave_no_lock; | 356 | return ret; |
| 349 | } | 357 | } |
| 350 | 358 | ||
| 351 | if (tgt_device->total_bytes < src_device->total_bytes) { | 359 | ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name, |
| 352 | btrfs_err(fs_info, "target device is smaller than source device!"); | 360 | src_device, &tgt_device); |
| 353 | ret = -EINVAL; | 361 | mutex_unlock(&fs_info->volume_mutex); |
| 354 | goto leave_no_lock; | 362 | if (ret) |
| 355 | } | 363 | return ret; |
| 356 | 364 | ||
| 357 | btrfs_dev_replace_lock(dev_replace); | 365 | btrfs_dev_replace_lock(dev_replace); |
| 358 | switch (dev_replace->replace_state) { | 366 | switch (dev_replace->replace_state) { |
| @@ -380,10 +388,6 @@ int btrfs_dev_replace_start(struct btrfs_root *root, | |||
| 380 | src_device->devid, | 388 | src_device->devid, |
| 381 | rcu_str_deref(tgt_device->name)); | 389 | rcu_str_deref(tgt_device->name)); |
| 382 | 390 | ||
| 383 | tgt_device->total_bytes = src_device->total_bytes; | ||
| 384 | tgt_device->disk_total_bytes = src_device->disk_total_bytes; | ||
| 385 | tgt_device->bytes_used = src_device->bytes_used; | ||
| 386 | |||
| 387 | /* | 391 | /* |
| 388 | * from now on, the writes to the srcdev are all duplicated to | 392 | * from now on, the writes to the srcdev are all duplicated to |
| 389 | * go to the tgtdev as well (refer to btrfs_map_block()). | 393 | * go to the tgtdev as well (refer to btrfs_map_block()). |
| @@ -414,7 +418,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root, | |||
| 414 | 418 | ||
| 415 | /* the disk copy procedure reuses the scrub code */ | 419 | /* the disk copy procedure reuses the scrub code */ |
| 416 | ret = btrfs_scrub_dev(fs_info, src_device->devid, 0, | 420 | ret = btrfs_scrub_dev(fs_info, src_device->devid, 0, |
| 417 | src_device->total_bytes, | 421 | btrfs_device_get_total_bytes(src_device), |
| 418 | &dev_replace->scrub_progress, 0, 1); | 422 | &dev_replace->scrub_progress, 0, 1); |
| 419 | 423 | ||
| 420 | ret = btrfs_dev_replace_finishing(root->fs_info, ret); | 424 | ret = btrfs_dev_replace_finishing(root->fs_info, ret); |
| @@ -426,9 +430,7 @@ leave: | |||
| 426 | dev_replace->srcdev = NULL; | 430 | dev_replace->srcdev = NULL; |
| 427 | dev_replace->tgtdev = NULL; | 431 | dev_replace->tgtdev = NULL; |
| 428 | btrfs_dev_replace_unlock(dev_replace); | 432 | btrfs_dev_replace_unlock(dev_replace); |
| 429 | leave_no_lock: | 433 | btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); |
| 430 | if (tgt_device) | ||
| 431 | btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); | ||
| 432 | return ret; | 434 | return ret; |
| 433 | } | 435 | } |
| 434 | 436 | ||
| @@ -507,9 +509,10 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 507 | ret = btrfs_commit_transaction(trans, root); | 509 | ret = btrfs_commit_transaction(trans, root); |
| 508 | WARN_ON(ret); | 510 | WARN_ON(ret); |
| 509 | 511 | ||
| 512 | mutex_lock(&uuid_mutex); | ||
| 510 | /* keep away write_all_supers() during the finishing procedure */ | 513 | /* keep away write_all_supers() during the finishing procedure */ |
| 511 | mutex_lock(&root->fs_info->chunk_mutex); | ||
| 512 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | 514 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); |
| 515 | mutex_lock(&root->fs_info->chunk_mutex); | ||
| 513 | btrfs_dev_replace_lock(dev_replace); | 516 | btrfs_dev_replace_lock(dev_replace); |
| 514 | dev_replace->replace_state = | 517 | dev_replace->replace_state = |
| 515 | scrub_ret ? BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED | 518 | scrub_ret ? BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED |
| @@ -532,8 +535,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 532 | src_device->devid, | 535 | src_device->devid, |
| 533 | rcu_str_deref(tgt_device->name), scrub_ret); | 536 | rcu_str_deref(tgt_device->name), scrub_ret); |
| 534 | btrfs_dev_replace_unlock(dev_replace); | 537 | btrfs_dev_replace_unlock(dev_replace); |
| 535 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
| 536 | mutex_unlock(&root->fs_info->chunk_mutex); | 538 | mutex_unlock(&root->fs_info->chunk_mutex); |
| 539 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
| 540 | mutex_unlock(&uuid_mutex); | ||
| 537 | if (tgt_device) | 541 | if (tgt_device) |
| 538 | btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); | 542 | btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); |
| 539 | mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); | 543 | mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); |
| @@ -542,7 +546,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 542 | } | 546 | } |
| 543 | 547 | ||
| 544 | printk_in_rcu(KERN_INFO | 548 | printk_in_rcu(KERN_INFO |
| 545 | "BTRFS: dev_replace from %s (devid %llu) to %s) finished\n", | 549 | "BTRFS: dev_replace from %s (devid %llu) to %s finished\n", |
| 546 | src_device->missing ? "<missing disk>" : | 550 | src_device->missing ? "<missing disk>" : |
| 547 | rcu_str_deref(src_device->name), | 551 | rcu_str_deref(src_device->name), |
| 548 | src_device->devid, | 552 | src_device->devid, |
| @@ -550,23 +554,29 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 550 | tgt_device->is_tgtdev_for_dev_replace = 0; | 554 | tgt_device->is_tgtdev_for_dev_replace = 0; |
| 551 | tgt_device->devid = src_device->devid; | 555 | tgt_device->devid = src_device->devid; |
| 552 | src_device->devid = BTRFS_DEV_REPLACE_DEVID; | 556 | src_device->devid = BTRFS_DEV_REPLACE_DEVID; |
| 553 | tgt_device->bytes_used = src_device->bytes_used; | ||
| 554 | memcpy(uuid_tmp, tgt_device->uuid, sizeof(uuid_tmp)); | 557 | memcpy(uuid_tmp, tgt_device->uuid, sizeof(uuid_tmp)); |
| 555 | memcpy(tgt_device->uuid, src_device->uuid, sizeof(tgt_device->uuid)); | 558 | memcpy(tgt_device->uuid, src_device->uuid, sizeof(tgt_device->uuid)); |
| 556 | memcpy(src_device->uuid, uuid_tmp, sizeof(src_device->uuid)); | 559 | memcpy(src_device->uuid, uuid_tmp, sizeof(src_device->uuid)); |
| 557 | tgt_device->total_bytes = src_device->total_bytes; | 560 | btrfs_device_set_total_bytes(tgt_device, src_device->total_bytes); |
| 558 | tgt_device->disk_total_bytes = src_device->disk_total_bytes; | 561 | btrfs_device_set_disk_total_bytes(tgt_device, |
| 559 | tgt_device->bytes_used = src_device->bytes_used; | 562 | src_device->disk_total_bytes); |
| 563 | btrfs_device_set_bytes_used(tgt_device, src_device->bytes_used); | ||
| 564 | ASSERT(list_empty(&src_device->resized_list)); | ||
| 565 | tgt_device->commit_total_bytes = src_device->commit_total_bytes; | ||
| 566 | tgt_device->commit_bytes_used = src_device->bytes_used; | ||
| 560 | if (fs_info->sb->s_bdev == src_device->bdev) | 567 | if (fs_info->sb->s_bdev == src_device->bdev) |
| 561 | fs_info->sb->s_bdev = tgt_device->bdev; | 568 | fs_info->sb->s_bdev = tgt_device->bdev; |
| 562 | if (fs_info->fs_devices->latest_bdev == src_device->bdev) | 569 | if (fs_info->fs_devices->latest_bdev == src_device->bdev) |
| 563 | fs_info->fs_devices->latest_bdev = tgt_device->bdev; | 570 | fs_info->fs_devices->latest_bdev = tgt_device->bdev; |
| 564 | list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); | 571 | list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); |
| 572 | fs_info->fs_devices->rw_devices++; | ||
| 565 | 573 | ||
| 566 | /* replace the sysfs entry */ | 574 | /* replace the sysfs entry */ |
| 567 | btrfs_kobj_rm_device(fs_info, src_device); | 575 | btrfs_kobj_rm_device(fs_info, src_device); |
| 568 | btrfs_kobj_add_device(fs_info, tgt_device); | 576 | btrfs_kobj_add_device(fs_info, tgt_device); |
| 569 | 577 | ||
| 578 | btrfs_dev_replace_unlock(dev_replace); | ||
| 579 | |||
| 570 | btrfs_rm_dev_replace_blocked(fs_info); | 580 | btrfs_rm_dev_replace_blocked(fs_info); |
| 571 | 581 | ||
| 572 | btrfs_rm_dev_replace_srcdev(fs_info, src_device); | 582 | btrfs_rm_dev_replace_srcdev(fs_info, src_device); |
| @@ -580,9 +590,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 580 | * superblock is scratched out so that it is no longer marked to | 590 | * superblock is scratched out so that it is no longer marked to |
| 581 | * belong to this filesystem. | 591 | * belong to this filesystem. |
| 582 | */ | 592 | */ |
| 583 | btrfs_dev_replace_unlock(dev_replace); | ||
| 584 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
| 585 | mutex_unlock(&root->fs_info->chunk_mutex); | 593 | mutex_unlock(&root->fs_info->chunk_mutex); |
| 594 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
| 595 | mutex_unlock(&uuid_mutex); | ||
| 586 | 596 | ||
| 587 | /* write back the superblocks */ | 597 | /* write back the superblocks */ |
| 588 | trans = btrfs_start_transaction(root, 0); | 598 | trans = btrfs_start_transaction(root, 0); |
| @@ -643,6 +653,7 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, | |||
| 643 | struct btrfs_ioctl_dev_replace_args *args) | 653 | struct btrfs_ioctl_dev_replace_args *args) |
| 644 | { | 654 | { |
| 645 | struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; | 655 | struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; |
| 656 | struct btrfs_device *srcdev; | ||
| 646 | 657 | ||
| 647 | btrfs_dev_replace_lock(dev_replace); | 658 | btrfs_dev_replace_lock(dev_replace); |
| 648 | /* even if !dev_replace_is_valid, the values are good enough for | 659 | /* even if !dev_replace_is_valid, the values are good enough for |
| @@ -665,8 +676,9 @@ void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, | |||
| 665 | break; | 676 | break; |
| 666 | case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: | 677 | case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: |
| 667 | case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: | 678 | case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: |
| 679 | srcdev = dev_replace->srcdev; | ||
| 668 | args->status.progress_1000 = div64_u64(dev_replace->cursor_left, | 680 | args->status.progress_1000 = div64_u64(dev_replace->cursor_left, |
| 669 | div64_u64(dev_replace->srcdev->total_bytes, 1000)); | 681 | div64_u64(btrfs_device_get_total_bytes(srcdev), 1000)); |
| 670 | break; | 682 | break; |
| 671 | } | 683 | } |
| 672 | btrfs_dev_replace_unlock(dev_replace); | 684 | btrfs_dev_replace_unlock(dev_replace); |
| @@ -825,7 +837,7 @@ static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info) | |||
| 825 | 837 | ||
| 826 | ret = btrfs_scrub_dev(fs_info, dev_replace->srcdev->devid, | 838 | ret = btrfs_scrub_dev(fs_info, dev_replace->srcdev->devid, |
| 827 | dev_replace->committed_cursor_left, | 839 | dev_replace->committed_cursor_left, |
| 828 | dev_replace->srcdev->total_bytes, | 840 | btrfs_device_get_total_bytes(dev_replace->srcdev), |
| 829 | &dev_replace->scrub_progress, 0, 1); | 841 | &dev_replace->scrub_progress, 0, 1); |
| 830 | ret = btrfs_dev_replace_finishing(fs_info, ret); | 842 | ret = btrfs_dev_replace_finishing(fs_info, ret); |
| 831 | WARN_ON(ret); | 843 | WARN_ON(ret); |
