diff options
Diffstat (limited to 'fs/btrfs/dev-replace.c')
| -rw-r--r-- | fs/btrfs/dev-replace.c | 79 |
1 files changed, 71 insertions, 8 deletions
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 564c92638b20..9f2290509aca 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c | |||
| @@ -431,6 +431,35 @@ leave_no_lock: | |||
| 431 | return ret; | 431 | return ret; |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | /* | ||
| 435 | * blocked until all flighting bios are finished. | ||
| 436 | */ | ||
| 437 | static void btrfs_rm_dev_replace_blocked(struct btrfs_fs_info *fs_info) | ||
| 438 | { | ||
| 439 | s64 writers; | ||
| 440 | DEFINE_WAIT(wait); | ||
| 441 | |||
| 442 | set_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state); | ||
| 443 | do { | ||
| 444 | prepare_to_wait(&fs_info->replace_wait, &wait, | ||
| 445 | TASK_UNINTERRUPTIBLE); | ||
| 446 | writers = percpu_counter_sum(&fs_info->bio_counter); | ||
| 447 | if (writers) | ||
| 448 | schedule(); | ||
| 449 | finish_wait(&fs_info->replace_wait, &wait); | ||
| 450 | } while (writers); | ||
| 451 | } | ||
| 452 | |||
| 453 | /* | ||
| 454 | * we have removed target device, it is safe to allow new bios request. | ||
| 455 | */ | ||
| 456 | static void btrfs_rm_dev_replace_unblocked(struct btrfs_fs_info *fs_info) | ||
| 457 | { | ||
| 458 | clear_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state); | ||
| 459 | if (waitqueue_active(&fs_info->replace_wait)) | ||
| 460 | wake_up(&fs_info->replace_wait); | ||
| 461 | } | ||
| 462 | |||
| 434 | static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | 463 | static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, |
| 435 | int scrub_ret) | 464 | int scrub_ret) |
| 436 | { | 465 | { |
| @@ -458,17 +487,11 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 458 | src_device = dev_replace->srcdev; | 487 | src_device = dev_replace->srcdev; |
| 459 | btrfs_dev_replace_unlock(dev_replace); | 488 | btrfs_dev_replace_unlock(dev_replace); |
| 460 | 489 | ||
| 461 | /* replace old device with new one in mapping tree */ | ||
| 462 | if (!scrub_ret) | ||
| 463 | btrfs_dev_replace_update_device_in_mapping_tree(fs_info, | ||
| 464 | src_device, | ||
| 465 | tgt_device); | ||
| 466 | |||
| 467 | /* | 490 | /* |
| 468 | * flush all outstanding I/O and inode extent mappings before the | 491 | * flush all outstanding I/O and inode extent mappings before the |
| 469 | * copy operation is declared as being finished | 492 | * copy operation is declared as being finished |
| 470 | */ | 493 | */ |
| 471 | ret = btrfs_start_delalloc_roots(root->fs_info, 0); | 494 | ret = btrfs_start_delalloc_roots(root->fs_info, 0, -1); |
| 472 | if (ret) { | 495 | if (ret) { |
| 473 | mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); | 496 | mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); |
| 474 | return ret; | 497 | return ret; |
| @@ -484,6 +507,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 484 | WARN_ON(ret); | 507 | WARN_ON(ret); |
| 485 | 508 | ||
| 486 | /* keep away write_all_supers() during the finishing procedure */ | 509 | /* keep away write_all_supers() during the finishing procedure */ |
| 510 | mutex_lock(&root->fs_info->chunk_mutex); | ||
| 487 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | 511 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); |
| 488 | btrfs_dev_replace_lock(dev_replace); | 512 | btrfs_dev_replace_lock(dev_replace); |
| 489 | dev_replace->replace_state = | 513 | dev_replace->replace_state = |
| @@ -494,7 +518,12 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 494 | dev_replace->time_stopped = get_seconds(); | 518 | dev_replace->time_stopped = get_seconds(); |
| 495 | dev_replace->item_needs_writeback = 1; | 519 | dev_replace->item_needs_writeback = 1; |
| 496 | 520 | ||
| 497 | if (scrub_ret) { | 521 | /* replace old device with new one in mapping tree */ |
| 522 | if (!scrub_ret) { | ||
| 523 | btrfs_dev_replace_update_device_in_mapping_tree(fs_info, | ||
| 524 | src_device, | ||
| 525 | tgt_device); | ||
| 526 | } else { | ||
| 498 | printk_in_rcu(KERN_ERR | 527 | printk_in_rcu(KERN_ERR |
| 499 | "BTRFS: btrfs_scrub_dev(%s, %llu, %s) failed %d\n", | 528 | "BTRFS: btrfs_scrub_dev(%s, %llu, %s) failed %d\n", |
| 500 | src_device->missing ? "<missing disk>" : | 529 | src_device->missing ? "<missing disk>" : |
| @@ -503,6 +532,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 503 | rcu_str_deref(tgt_device->name), scrub_ret); | 532 | rcu_str_deref(tgt_device->name), scrub_ret); |
| 504 | btrfs_dev_replace_unlock(dev_replace); | 533 | btrfs_dev_replace_unlock(dev_replace); |
| 505 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | 534 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); |
| 535 | mutex_unlock(&root->fs_info->chunk_mutex); | ||
| 506 | if (tgt_device) | 536 | if (tgt_device) |
| 507 | btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); | 537 | btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); |
| 508 | mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); | 538 | mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); |
| @@ -532,8 +562,12 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 532 | fs_info->fs_devices->latest_bdev = tgt_device->bdev; | 562 | fs_info->fs_devices->latest_bdev = tgt_device->bdev; |
| 533 | list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); | 563 | list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); |
| 534 | 564 | ||
| 565 | btrfs_rm_dev_replace_blocked(fs_info); | ||
| 566 | |||
| 535 | btrfs_rm_dev_replace_srcdev(fs_info, src_device); | 567 | btrfs_rm_dev_replace_srcdev(fs_info, src_device); |
| 536 | 568 | ||
| 569 | btrfs_rm_dev_replace_unblocked(fs_info); | ||
| 570 | |||
| 537 | /* | 571 | /* |
| 538 | * this is again a consistent state where no dev_replace procedure | 572 | * this is again a consistent state where no dev_replace procedure |
| 539 | * is running, the target device is part of the filesystem, the | 573 | * is running, the target device is part of the filesystem, the |
| @@ -543,6 +577,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, | |||
| 543 | */ | 577 | */ |
| 544 | btrfs_dev_replace_unlock(dev_replace); | 578 | btrfs_dev_replace_unlock(dev_replace); |
| 545 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | 579 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); |
| 580 | mutex_unlock(&root->fs_info->chunk_mutex); | ||
| 546 | 581 | ||
| 547 | /* write back the superblocks */ | 582 | /* write back the superblocks */ |
| 548 | trans = btrfs_start_transaction(root, 0); | 583 | trans = btrfs_start_transaction(root, 0); |
| @@ -862,3 +897,31 @@ void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace) | |||
| 862 | mutex_unlock(&dev_replace->lock_management_lock); | 897 | mutex_unlock(&dev_replace->lock_management_lock); |
| 863 | } | 898 | } |
| 864 | } | 899 | } |
| 900 | |||
| 901 | void btrfs_bio_counter_inc_noblocked(struct btrfs_fs_info *fs_info) | ||
| 902 | { | ||
| 903 | percpu_counter_inc(&fs_info->bio_counter); | ||
| 904 | } | ||
| 905 | |||
| 906 | void btrfs_bio_counter_dec(struct btrfs_fs_info *fs_info) | ||
| 907 | { | ||
| 908 | percpu_counter_dec(&fs_info->bio_counter); | ||
| 909 | |||
| 910 | if (waitqueue_active(&fs_info->replace_wait)) | ||
| 911 | wake_up(&fs_info->replace_wait); | ||
| 912 | } | ||
| 913 | |||
| 914 | void btrfs_bio_counter_inc_blocked(struct btrfs_fs_info *fs_info) | ||
| 915 | { | ||
| 916 | DEFINE_WAIT(wait); | ||
| 917 | again: | ||
| 918 | percpu_counter_inc(&fs_info->bio_counter); | ||
| 919 | if (test_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state)) { | ||
| 920 | btrfs_bio_counter_dec(fs_info); | ||
| 921 | wait_event(fs_info->replace_wait, | ||
| 922 | !test_bit(BTRFS_FS_STATE_DEV_REPLACING, | ||
| 923 | &fs_info->fs_state)); | ||
| 924 | goto again; | ||
| 925 | } | ||
| 926 | |||
| 927 | } | ||
