aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorStefan Behrens <sbehrens@giantdisaster.de>2012-11-05 12:29:28 -0500
committerJosef Bacik <jbacik@fusionio.com>2012-12-12 17:15:39 -0500
commit63a212abc2315972b245f93cb11ae3acf3c0b513 (patch)
tree65d9f4020795b6a3521bf0a94922a082ae4ede6f /fs/btrfs/volumes.c
parent5ac00addc7ac09110995fe967071d191b5981cc1 (diff)
Btrfs: disallow some operations on the device replace target device
This patch adds some code to disallow operations on the device that is used as the target for the device replace operation. Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c41
1 files changed, 32 insertions, 9 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 33ca36b37a6a..31f7af878d96 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -518,8 +518,9 @@ again:
518 /* This is the initialized path, it is safe to release the devices. */ 518 /* This is the initialized path, it is safe to release the devices. */
519 list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) { 519 list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
520 if (device->in_fs_metadata) { 520 if (device->in_fs_metadata) {
521 if (!latest_transid || 521 if (!device->is_tgtdev_for_dev_replace &&
522 device->generation > latest_transid) { 522 (!latest_transid ||
523 device->generation > latest_transid)) {
523 latest_devid = device->devid; 524 latest_devid = device->devid;
524 latest_transid = device->generation; 525 latest_transid = device->generation;
525 latest_bdev = device->bdev; 526 latest_bdev = device->bdev;
@@ -814,7 +815,7 @@ int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
814 815
815 *length = 0; 816 *length = 0;
816 817
817 if (start >= device->total_bytes) 818 if (start >= device->total_bytes || device->is_tgtdev_for_dev_replace)
818 return 0; 819 return 0;
819 820
820 path = btrfs_alloc_path(); 821 path = btrfs_alloc_path();
@@ -931,7 +932,7 @@ int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
931 max_hole_size = 0; 932 max_hole_size = 0;
932 hole_size = 0; 933 hole_size = 0;
933 934
934 if (search_start >= search_end) { 935 if (search_start >= search_end || device->is_tgtdev_for_dev_replace) {
935 ret = -ENOSPC; 936 ret = -ENOSPC;
936 goto error; 937 goto error;
937 } 938 }
@@ -1114,6 +1115,7 @@ int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
1114 struct btrfs_key key; 1115 struct btrfs_key key;
1115 1116
1116 WARN_ON(!device->in_fs_metadata); 1117 WARN_ON(!device->in_fs_metadata);
1118 WARN_ON(device->is_tgtdev_for_dev_replace);
1117 path = btrfs_alloc_path(); 1119 path = btrfs_alloc_path();
1118 if (!path) 1120 if (!path)
1119 return -ENOMEM; 1121 return -ENOMEM;
@@ -1375,7 +1377,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
1375 * is held. 1377 * is held.
1376 */ 1378 */
1377 list_for_each_entry(tmp, devices, dev_list) { 1379 list_for_each_entry(tmp, devices, dev_list) {
1378 if (tmp->in_fs_metadata && !tmp->bdev) { 1380 if (tmp->in_fs_metadata &&
1381 !tmp->is_tgtdev_for_dev_replace &&
1382 !tmp->bdev) {
1379 device = tmp; 1383 device = tmp;
1380 break; 1384 break;
1381 } 1385 }
@@ -1406,6 +1410,12 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
1406 } 1410 }
1407 } 1411 }
1408 1412
1413 if (device->is_tgtdev_for_dev_replace) {
1414 pr_err("btrfs: unable to remove the dev_replace target dev\n");
1415 ret = -EINVAL;
1416 goto error_brelse;
1417 }
1418
1409 if (device->writeable && root->fs_info->fs_devices->rw_devices == 1) { 1419 if (device->writeable && root->fs_info->fs_devices->rw_devices == 1) {
1410 printk(KERN_ERR "btrfs: unable to remove the only writeable " 1420 printk(KERN_ERR "btrfs: unable to remove the only writeable "
1411 "device\n"); 1421 "device\n");
@@ -1425,6 +1435,11 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
1425 if (ret) 1435 if (ret)
1426 goto error_undo; 1436 goto error_undo;
1427 1437
1438 /*
1439 * TODO: the superblock still includes this device in its num_devices
1440 * counter although write_all_supers() is not locked out. This
1441 * could give a filesystem state which requires a degraded mount.
1442 */
1428 ret = btrfs_rm_dev_item(root->fs_info->chunk_root, device); 1443 ret = btrfs_rm_dev_item(root->fs_info->chunk_root, device);
1429 if (ret) 1444 if (ret)
1430 goto error_undo; 1445 goto error_undo;
@@ -1808,6 +1823,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
1808 device->dev_root = root->fs_info->dev_root; 1823 device->dev_root = root->fs_info->dev_root;
1809 device->bdev = bdev; 1824 device->bdev = bdev;
1810 device->in_fs_metadata = 1; 1825 device->in_fs_metadata = 1;
1826 device->is_tgtdev_for_dev_replace = 0;
1811 device->mode = FMODE_EXCL; 1827 device->mode = FMODE_EXCL;
1812 set_blocksize(device->bdev, 4096); 1828 set_blocksize(device->bdev, 4096);
1813 1829
@@ -1971,7 +1987,8 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans,
1971 1987
1972 if (!device->writeable) 1988 if (!device->writeable)
1973 return -EACCES; 1989 return -EACCES;
1974 if (new_size <= device->total_bytes) 1990 if (new_size <= device->total_bytes ||
1991 device->is_tgtdev_for_dev_replace)
1975 return -EINVAL; 1992 return -EINVAL;
1976 1993
1977 btrfs_set_super_total_bytes(super_copy, old_total + diff); 1994 btrfs_set_super_total_bytes(super_copy, old_total + diff);
@@ -2600,7 +2617,8 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
2600 size_to_free = div_factor(old_size, 1); 2617 size_to_free = div_factor(old_size, 1);
2601 size_to_free = min(size_to_free, (u64)1 * 1024 * 1024); 2618 size_to_free = min(size_to_free, (u64)1 * 1024 * 1024);
2602 if (!device->writeable || 2619 if (!device->writeable ||
2603 device->total_bytes - device->bytes_used > size_to_free) 2620 device->total_bytes - device->bytes_used > size_to_free ||
2621 device->is_tgtdev_for_dev_replace)
2604 continue; 2622 continue;
2605 2623
2606 ret = btrfs_shrink_device(device, old_size - size_to_free); 2624 ret = btrfs_shrink_device(device, old_size - size_to_free);
@@ -3132,6 +3150,9 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
3132 u64 old_size = device->total_bytes; 3150 u64 old_size = device->total_bytes;
3133 u64 diff = device->total_bytes - new_size; 3151 u64 diff = device->total_bytes - new_size;
3134 3152
3153 if (device->is_tgtdev_for_dev_replace)
3154 return -EINVAL;
3155
3135 path = btrfs_alloc_path(); 3156 path = btrfs_alloc_path();
3136 if (!path) 3157 if (!path)
3137 return -ENOMEM; 3158 return -ENOMEM;
@@ -3401,7 +3422,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
3401 continue; 3422 continue;
3402 } 3423 }
3403 3424
3404 if (!device->in_fs_metadata) 3425 if (!device->in_fs_metadata ||
3426 device->is_tgtdev_for_dev_replace)
3405 continue; 3427 continue;
3406 3428
3407 if (device->total_bytes > device->bytes_used) 3429 if (device->total_bytes > device->bytes_used)
@@ -4612,6 +4634,7 @@ static void fill_device_from_item(struct extent_buffer *leaf,
4612 device->io_align = btrfs_device_io_align(leaf, dev_item); 4634 device->io_align = btrfs_device_io_align(leaf, dev_item);
4613 device->io_width = btrfs_device_io_width(leaf, dev_item); 4635 device->io_width = btrfs_device_io_width(leaf, dev_item);
4614 device->sector_size = btrfs_device_sector_size(leaf, dev_item); 4636 device->sector_size = btrfs_device_sector_size(leaf, dev_item);
4637 device->is_tgtdev_for_dev_replace = 0;
4615 4638
4616 ptr = (unsigned long)btrfs_device_uuid(dev_item); 4639 ptr = (unsigned long)btrfs_device_uuid(dev_item);
4617 read_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE); 4640 read_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
@@ -4722,7 +4745,7 @@ static int read_one_dev(struct btrfs_root *root,
4722 fill_device_from_item(leaf, dev_item, device); 4745 fill_device_from_item(leaf, dev_item, device);
4723 device->dev_root = root->fs_info->dev_root; 4746 device->dev_root = root->fs_info->dev_root;
4724 device->in_fs_metadata = 1; 4747 device->in_fs_metadata = 1;
4725 if (device->writeable) { 4748 if (device->writeable && !device->is_tgtdev_for_dev_replace) {
4726 device->fs_devices->total_rw_bytes += device->total_bytes; 4749 device->fs_devices->total_rw_bytes += device->total_bytes;
4727 spin_lock(&root->fs_info->free_chunk_lock); 4750 spin_lock(&root->fs_info->free_chunk_lock);
4728 root->fs_info->free_chunk_space += device->total_bytes - 4751 root->fs_info->free_chunk_space += device->total_bytes -