aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/dev-replace.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/dev-replace.c')
-rw-r--r--fs/btrfs/dev-replace.c82
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);
429leave_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);