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); |