|
@@ -36,6 +36,7 @@
|
|
|
#include "check-integrity.h"
|
|
|
#include "rcu-string.h"
|
|
|
#include "math.h"
|
|
|
+#include "dev-replace.h"
|
|
|
|
|
|
static int init_first_rw_device(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root,
|
|
@@ -505,7 +506,8 @@ error:
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
}
|
|
|
|
|
|
-void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
|
|
|
+void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info,
|
|
|
+ struct btrfs_fs_devices *fs_devices, int step)
|
|
|
{
|
|
|
struct btrfs_device *device, *next;
|
|
|
|
|
@@ -528,6 +530,21 @@ again:
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
+ if (device->devid == BTRFS_DEV_REPLACE_DEVID) {
|
|
|
+ /*
|
|
|
+ * In the first step, keep the device which has
|
|
|
+ * the correct fsid and the devid that is used
|
|
|
+ * for the dev_replace procedure.
|
|
|
+ * In the second step, the dev_replace state is
|
|
|
+ * read from the device tree and it is known
|
|
|
+ * whether the procedure is really active or
|
|
|
+ * not, which means whether this device is
|
|
|
+ * used or whether it should be removed.
|
|
|
+ */
|
|
|
+ if (step == 0 || device->is_tgtdev_for_dev_replace) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
if (device->bdev) {
|
|
|
blkdev_put(device->bdev, device->mode);
|
|
|
device->bdev = NULL;
|
|
@@ -536,7 +553,8 @@ again:
|
|
|
if (device->writeable) {
|
|
|
list_del_init(&device->dev_alloc_list);
|
|
|
device->writeable = 0;
|
|
|
- fs_devices->rw_devices--;
|
|
|
+ if (!device->is_tgtdev_for_dev_replace)
|
|
|
+ fs_devices->rw_devices--;
|
|
|
}
|
|
|
list_del_init(&device->dev_list);
|
|
|
fs_devices->num_devices--;
|
|
@@ -594,7 +612,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
|
|
|
if (device->bdev)
|
|
|
fs_devices->open_devices--;
|
|
|
|
|
|
- if (device->writeable) {
|
|
|
+ if (device->writeable && !device->is_tgtdev_for_dev_replace) {
|
|
|
list_del_init(&device->dev_alloc_list);
|
|
|
fs_devices->rw_devices--;
|
|
|
}
|
|
@@ -718,7 +736,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
|
|
|
fs_devices->rotating = 1;
|
|
|
|
|
|
fs_devices->open_devices++;
|
|
|
- if (device->writeable) {
|
|
|
+ if (device->writeable && !device->is_tgtdev_for_dev_replace) {
|
|
|
fs_devices->rw_devices++;
|
|
|
list_add(&device->dev_alloc_list,
|
|
|
&fs_devices->alloc_list);
|
|
@@ -1350,16 +1368,22 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
|
|
|
root->fs_info->avail_system_alloc_bits |
|
|
|
root->fs_info->avail_metadata_alloc_bits;
|
|
|
|
|
|
- if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) &&
|
|
|
- root->fs_info->fs_devices->num_devices <= 4) {
|
|
|
+ num_devices = root->fs_info->fs_devices->num_devices;
|
|
|
+ btrfs_dev_replace_lock(&root->fs_info->dev_replace);
|
|
|
+ if (btrfs_dev_replace_is_ongoing(&root->fs_info->dev_replace)) {
|
|
|
+ WARN_ON(num_devices < 1);
|
|
|
+ num_devices--;
|
|
|
+ }
|
|
|
+ btrfs_dev_replace_unlock(&root->fs_info->dev_replace);
|
|
|
+
|
|
|
+ if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) && num_devices <= 4) {
|
|
|
printk(KERN_ERR "btrfs: unable to go below four devices "
|
|
|
"on raid10\n");
|
|
|
ret = -EINVAL;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) &&
|
|
|
- root->fs_info->fs_devices->num_devices <= 2) {
|
|
|
+ if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) && num_devices <= 2) {
|
|
|
printk(KERN_ERR "btrfs: unable to go below two "
|
|
|
"devices on raid1\n");
|
|
|
ret = -EINVAL;
|
|
@@ -2935,6 +2959,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
|
|
|
u64 allowed;
|
|
|
int mixed = 0;
|
|
|
int ret;
|
|
|
+ u64 num_devices;
|
|
|
|
|
|
if (btrfs_fs_closing(fs_info) ||
|
|
|
atomic_read(&fs_info->balance_pause_req) ||
|
|
@@ -2963,10 +2988,17 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ num_devices = fs_info->fs_devices->num_devices;
|
|
|
+ btrfs_dev_replace_lock(&fs_info->dev_replace);
|
|
|
+ if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) {
|
|
|
+ BUG_ON(num_devices < 1);
|
|
|
+ num_devices--;
|
|
|
+ }
|
|
|
+ btrfs_dev_replace_unlock(&fs_info->dev_replace);
|
|
|
allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
|
|
|
- if (fs_info->fs_devices->num_devices == 1)
|
|
|
+ if (num_devices == 1)
|
|
|
allowed |= BTRFS_BLOCK_GROUP_DUP;
|
|
|
- else if (fs_info->fs_devices->num_devices < 4)
|
|
|
+ else if (num_devices < 4)
|
|
|
allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1);
|
|
|
else
|
|
|
allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
|
|
@@ -3591,6 +3623,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
|
|
|
devices_info[ndevs].total_avail = total_avail;
|
|
|
devices_info[ndevs].dev = device;
|
|
|
++ndevs;
|
|
|
+ WARN_ON(ndevs > fs_devices->rw_devices);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -4773,6 +4806,7 @@ static void fill_device_from_item(struct extent_buffer *leaf,
|
|
|
device->io_align = btrfs_device_io_align(leaf, dev_item);
|
|
|
device->io_width = btrfs_device_io_width(leaf, dev_item);
|
|
|
device->sector_size = btrfs_device_sector_size(leaf, dev_item);
|
|
|
+ WARN_ON(device->devid == BTRFS_DEV_REPLACE_DEVID);
|
|
|
device->is_tgtdev_for_dev_replace = 0;
|
|
|
|
|
|
ptr = (unsigned long)btrfs_device_uuid(dev_item);
|