diff options
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 54 |
1 files changed, 44 insertions, 10 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5777e6a9aab1..a4e0963bf457 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "check-integrity.h" | 36 | #include "check-integrity.h" |
37 | #include "rcu-string.h" | 37 | #include "rcu-string.h" |
38 | #include "math.h" | 38 | #include "math.h" |
39 | #include "dev-replace.h" | ||
39 | 40 | ||
40 | static int init_first_rw_device(struct btrfs_trans_handle *trans, | 41 | static int init_first_rw_device(struct btrfs_trans_handle *trans, |
41 | struct btrfs_root *root, | 42 | struct btrfs_root *root, |
@@ -505,7 +506,8 @@ error: | |||
505 | return ERR_PTR(-ENOMEM); | 506 | return ERR_PTR(-ENOMEM); |
506 | } | 507 | } |
507 | 508 | ||
508 | void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices) | 509 | void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info, |
510 | struct btrfs_fs_devices *fs_devices, int step) | ||
509 | { | 511 | { |
510 | struct btrfs_device *device, *next; | 512 | struct btrfs_device *device, *next; |
511 | 513 | ||
@@ -528,6 +530,21 @@ again: | |||
528 | continue; | 530 | continue; |
529 | } | 531 | } |
530 | 532 | ||
533 | if (device->devid == BTRFS_DEV_REPLACE_DEVID) { | ||
534 | /* | ||
535 | * In the first step, keep the device which has | ||
536 | * the correct fsid and the devid that is used | ||
537 | * for the dev_replace procedure. | ||
538 | * In the second step, the dev_replace state is | ||
539 | * read from the device tree and it is known | ||
540 | * whether the procedure is really active or | ||
541 | * not, which means whether this device is | ||
542 | * used or whether it should be removed. | ||
543 | */ | ||
544 | if (step == 0 || device->is_tgtdev_for_dev_replace) { | ||
545 | continue; | ||
546 | } | ||
547 | } | ||
531 | if (device->bdev) { | 548 | if (device->bdev) { |
532 | blkdev_put(device->bdev, device->mode); | 549 | blkdev_put(device->bdev, device->mode); |
533 | device->bdev = NULL; | 550 | device->bdev = NULL; |
@@ -536,7 +553,8 @@ again: | |||
536 | if (device->writeable) { | 553 | if (device->writeable) { |
537 | list_del_init(&device->dev_alloc_list); | 554 | list_del_init(&device->dev_alloc_list); |
538 | device->writeable = 0; | 555 | device->writeable = 0; |
539 | fs_devices->rw_devices--; | 556 | if (!device->is_tgtdev_for_dev_replace) |
557 | fs_devices->rw_devices--; | ||
540 | } | 558 | } |
541 | list_del_init(&device->dev_list); | 559 | list_del_init(&device->dev_list); |
542 | fs_devices->num_devices--; | 560 | fs_devices->num_devices--; |
@@ -594,7 +612,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) | |||
594 | if (device->bdev) | 612 | if (device->bdev) |
595 | fs_devices->open_devices--; | 613 | fs_devices->open_devices--; |
596 | 614 | ||
597 | if (device->writeable) { | 615 | if (device->writeable && !device->is_tgtdev_for_dev_replace) { |
598 | list_del_init(&device->dev_alloc_list); | 616 | list_del_init(&device->dev_alloc_list); |
599 | fs_devices->rw_devices--; | 617 | fs_devices->rw_devices--; |
600 | } | 618 | } |
@@ -718,7 +736,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, | |||
718 | fs_devices->rotating = 1; | 736 | fs_devices->rotating = 1; |
719 | 737 | ||
720 | fs_devices->open_devices++; | 738 | fs_devices->open_devices++; |
721 | if (device->writeable) { | 739 | if (device->writeable && !device->is_tgtdev_for_dev_replace) { |
722 | fs_devices->rw_devices++; | 740 | fs_devices->rw_devices++; |
723 | list_add(&device->dev_alloc_list, | 741 | list_add(&device->dev_alloc_list, |
724 | &fs_devices->alloc_list); | 742 | &fs_devices->alloc_list); |
@@ -1350,16 +1368,22 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
1350 | root->fs_info->avail_system_alloc_bits | | 1368 | root->fs_info->avail_system_alloc_bits | |
1351 | root->fs_info->avail_metadata_alloc_bits; | 1369 | root->fs_info->avail_metadata_alloc_bits; |
1352 | 1370 | ||
1353 | if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) && | 1371 | num_devices = root->fs_info->fs_devices->num_devices; |
1354 | root->fs_info->fs_devices->num_devices <= 4) { | 1372 | btrfs_dev_replace_lock(&root->fs_info->dev_replace); |
1373 | if (btrfs_dev_replace_is_ongoing(&root->fs_info->dev_replace)) { | ||
1374 | WARN_ON(num_devices < 1); | ||
1375 | num_devices--; | ||
1376 | } | ||
1377 | btrfs_dev_replace_unlock(&root->fs_info->dev_replace); | ||
1378 | |||
1379 | if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) && num_devices <= 4) { | ||
1355 | printk(KERN_ERR "btrfs: unable to go below four devices " | 1380 | printk(KERN_ERR "btrfs: unable to go below four devices " |
1356 | "on raid10\n"); | 1381 | "on raid10\n"); |
1357 | ret = -EINVAL; | 1382 | ret = -EINVAL; |
1358 | goto out; | 1383 | goto out; |
1359 | } | 1384 | } |
1360 | 1385 | ||
1361 | if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) && | 1386 | if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) && num_devices <= 2) { |
1362 | root->fs_info->fs_devices->num_devices <= 2) { | ||
1363 | printk(KERN_ERR "btrfs: unable to go below two " | 1387 | printk(KERN_ERR "btrfs: unable to go below two " |
1364 | "devices on raid1\n"); | 1388 | "devices on raid1\n"); |
1365 | ret = -EINVAL; | 1389 | ret = -EINVAL; |
@@ -2935,6 +2959,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl, | |||
2935 | u64 allowed; | 2959 | u64 allowed; |
2936 | int mixed = 0; | 2960 | int mixed = 0; |
2937 | int ret; | 2961 | int ret; |
2962 | u64 num_devices; | ||
2938 | 2963 | ||
2939 | if (btrfs_fs_closing(fs_info) || | 2964 | if (btrfs_fs_closing(fs_info) || |
2940 | atomic_read(&fs_info->balance_pause_req) || | 2965 | atomic_read(&fs_info->balance_pause_req) || |
@@ -2963,10 +2988,17 @@ int btrfs_balance(struct btrfs_balance_control *bctl, | |||
2963 | } | 2988 | } |
2964 | } | 2989 | } |
2965 | 2990 | ||
2991 | num_devices = fs_info->fs_devices->num_devices; | ||
2992 | btrfs_dev_replace_lock(&fs_info->dev_replace); | ||
2993 | if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) { | ||
2994 | BUG_ON(num_devices < 1); | ||
2995 | num_devices--; | ||
2996 | } | ||
2997 | btrfs_dev_replace_unlock(&fs_info->dev_replace); | ||
2966 | allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE; | 2998 | allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE; |
2967 | if (fs_info->fs_devices->num_devices == 1) | 2999 | if (num_devices == 1) |
2968 | allowed |= BTRFS_BLOCK_GROUP_DUP; | 3000 | allowed |= BTRFS_BLOCK_GROUP_DUP; |
2969 | else if (fs_info->fs_devices->num_devices < 4) | 3001 | else if (num_devices < 4) |
2970 | allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1); | 3002 | allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1); |
2971 | else | 3003 | else |
2972 | allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | | 3004 | allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | |
@@ -3591,6 +3623,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
3591 | devices_info[ndevs].total_avail = total_avail; | 3623 | devices_info[ndevs].total_avail = total_avail; |
3592 | devices_info[ndevs].dev = device; | 3624 | devices_info[ndevs].dev = device; |
3593 | ++ndevs; | 3625 | ++ndevs; |
3626 | WARN_ON(ndevs > fs_devices->rw_devices); | ||
3594 | } | 3627 | } |
3595 | 3628 | ||
3596 | /* | 3629 | /* |
@@ -4773,6 +4806,7 @@ static void fill_device_from_item(struct extent_buffer *leaf, | |||
4773 | device->io_align = btrfs_device_io_align(leaf, dev_item); | 4806 | device->io_align = btrfs_device_io_align(leaf, dev_item); |
4774 | device->io_width = btrfs_device_io_width(leaf, dev_item); | 4807 | device->io_width = btrfs_device_io_width(leaf, dev_item); |
4775 | device->sector_size = btrfs_device_sector_size(leaf, dev_item); | 4808 | device->sector_size = btrfs_device_sector_size(leaf, dev_item); |
4809 | WARN_ON(device->devid == BTRFS_DEV_REPLACE_DEVID); | ||
4776 | device->is_tgtdev_for_dev_replace = 0; | 4810 | device->is_tgtdev_for_dev_replace = 0; |
4777 | 4811 | ||
4778 | ptr = (unsigned long)btrfs_device_uuid(dev_item); | 4812 | ptr = (unsigned long)btrfs_device_uuid(dev_item); |