aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/extent-tree.c3
-rw-r--r--fs/btrfs/ioctl.c8
-rw-r--r--fs/btrfs/scrub.c14
-rw-r--r--fs/btrfs/super.c3
-rw-r--r--fs/btrfs/volumes.c41
-rw-r--r--fs/btrfs/volumes.h1
7 files changed, 54 insertions, 18 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index e9dc78014f09..746cb6aa1f62 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3649,7 +3649,7 @@ int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
3649/* scrub.c */ 3649/* scrub.c */
3650int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, 3650int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
3651 u64 end, struct btrfs_scrub_progress *progress, 3651 u64 end, struct btrfs_scrub_progress *progress,
3652 int readonly); 3652 int readonly, int is_dev_replace);
3653void btrfs_scrub_pause(struct btrfs_root *root); 3653void btrfs_scrub_pause(struct btrfs_root *root);
3654void btrfs_scrub_pause_super(struct btrfs_root *root); 3654void btrfs_scrub_pause_super(struct btrfs_root *root);
3655void btrfs_scrub_continue(struct btrfs_root *root); 3655void btrfs_scrub_continue(struct btrfs_root *root);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index b4d438f6c2b3..98af8379895a 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -7468,7 +7468,8 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
7468 * check to make sure we can actually find a chunk with enough 7468 * check to make sure we can actually find a chunk with enough
7469 * space to fit our block group in. 7469 * space to fit our block group in.
7470 */ 7470 */
7471 if (device->total_bytes > device->bytes_used + min_free) { 7471 if (device->total_bytes > device->bytes_used + min_free &&
7472 !device->is_tgtdev_for_dev_replace) {
7472 ret = find_free_dev_extent(device, min_free, 7473 ret = find_free_dev_extent(device, min_free,
7473 &dev_offset, NULL); 7474 &dev_offset, NULL);
7474 if (!ret) 7475 if (!ret)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 26f46dad3b0e..e54b5e50c927 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1375,6 +1375,11 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
1375 } 1375 }
1376 } 1376 }
1377 1377
1378 if (device->is_tgtdev_for_dev_replace) {
1379 ret = -EINVAL;
1380 goto out_free;
1381 }
1382
1378 old_size = device->total_bytes; 1383 old_size = device->total_bytes;
1379 1384
1380 if (mod < 0) { 1385 if (mod < 0) {
@@ -3102,7 +3107,8 @@ static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg)
3102 return PTR_ERR(sa); 3107 return PTR_ERR(sa);
3103 3108
3104 ret = btrfs_scrub_dev(root->fs_info, sa->devid, sa->start, sa->end, 3109 ret = btrfs_scrub_dev(root->fs_info, sa->devid, sa->start, sa->end,
3105 &sa->progress, sa->flags & BTRFS_SCRUB_READONLY); 3110 &sa->progress, sa->flags & BTRFS_SCRUB_READONLY,
3111 0);
3106 3112
3107 if (copy_to_user(arg, sa, sizeof(*sa))) 3113 if (copy_to_user(arg, sa, sizeof(*sa)))
3108 ret = -EFAULT; 3114 ret = -EFAULT;
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 6cf23f4f7bb7..460e30bb1884 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -116,6 +116,9 @@ struct scrub_ctx {
116 u32 sectorsize; 116 u32 sectorsize;
117 u32 nodesize; 117 u32 nodesize;
118 u32 leafsize; 118 u32 leafsize;
119
120 int is_dev_replace;
121
119 /* 122 /*
120 * statistics 123 * statistics
121 */ 124 */
@@ -284,7 +287,7 @@ static noinline_for_stack void scrub_free_ctx(struct scrub_ctx *sctx)
284} 287}
285 288
286static noinline_for_stack 289static noinline_for_stack
287struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev) 290struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace)
288{ 291{
289 struct scrub_ctx *sctx; 292 struct scrub_ctx *sctx;
290 int i; 293 int i;
@@ -296,6 +299,7 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev)
296 sctx = kzalloc(sizeof(*sctx), GFP_NOFS); 299 sctx = kzalloc(sizeof(*sctx), GFP_NOFS);
297 if (!sctx) 300 if (!sctx)
298 goto nomem; 301 goto nomem;
302 sctx->is_dev_replace = is_dev_replace;
299 sctx->pages_per_bio = pages_per_bio; 303 sctx->pages_per_bio = pages_per_bio;
300 sctx->curr = -1; 304 sctx->curr = -1;
301 sctx->dev_root = dev->dev_root; 305 sctx->dev_root = dev->dev_root;
@@ -2293,7 +2297,7 @@ static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info)
2293 2297
2294int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, 2298int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
2295 u64 end, struct btrfs_scrub_progress *progress, 2299 u64 end, struct btrfs_scrub_progress *progress,
2296 int readonly) 2300 int readonly, int is_dev_replace)
2297{ 2301{
2298 struct scrub_ctx *sctx; 2302 struct scrub_ctx *sctx;
2299 int ret; 2303 int ret;
@@ -2356,14 +2360,14 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
2356 2360
2357 mutex_lock(&fs_info->fs_devices->device_list_mutex); 2361 mutex_lock(&fs_info->fs_devices->device_list_mutex);
2358 dev = btrfs_find_device(fs_info, devid, NULL, NULL); 2362 dev = btrfs_find_device(fs_info, devid, NULL, NULL);
2359 if (!dev || dev->missing) { 2363 if (!dev || (dev->missing && !is_dev_replace)) {
2360 mutex_unlock(&fs_info->fs_devices->device_list_mutex); 2364 mutex_unlock(&fs_info->fs_devices->device_list_mutex);
2361 scrub_workers_put(fs_info); 2365 scrub_workers_put(fs_info);
2362 return -ENODEV; 2366 return -ENODEV;
2363 } 2367 }
2364 mutex_lock(&fs_info->scrub_lock); 2368 mutex_lock(&fs_info->scrub_lock);
2365 2369
2366 if (!dev->in_fs_metadata) { 2370 if (!dev->in_fs_metadata || dev->is_tgtdev_for_dev_replace) {
2367 mutex_unlock(&fs_info->scrub_lock); 2371 mutex_unlock(&fs_info->scrub_lock);
2368 mutex_unlock(&fs_info->fs_devices->device_list_mutex); 2372 mutex_unlock(&fs_info->fs_devices->device_list_mutex);
2369 scrub_workers_put(fs_info); 2373 scrub_workers_put(fs_info);
@@ -2376,7 +2380,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
2376 scrub_workers_put(fs_info); 2380 scrub_workers_put(fs_info);
2377 return -EINPROGRESS; 2381 return -EINPROGRESS;
2378 } 2382 }
2379 sctx = scrub_setup_ctx(dev); 2383 sctx = scrub_setup_ctx(dev, is_dev_replace);
2380 if (IS_ERR(sctx)) { 2384 if (IS_ERR(sctx)) {
2381 mutex_unlock(&fs_info->scrub_lock); 2385 mutex_unlock(&fs_info->scrub_lock);
2382 mutex_unlock(&fs_info->fs_devices->device_list_mutex); 2386 mutex_unlock(&fs_info->fs_devices->device_list_mutex);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index ef2415896b06..837ad2d27853 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1354,7 +1354,8 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
1354 min_stripe_size = BTRFS_STRIPE_LEN; 1354 min_stripe_size = BTRFS_STRIPE_LEN;
1355 1355
1356 list_for_each_entry(device, &fs_devices->devices, dev_list) { 1356 list_for_each_entry(device, &fs_devices->devices, dev_list) {
1357 if (!device->in_fs_metadata || !device->bdev) 1357 if (!device->in_fs_metadata || !device->bdev ||
1358 device->is_tgtdev_for_dev_replace)
1358 continue; 1359 continue;
1359 1360
1360 avail_space = device->total_bytes - device->bytes_used; 1361 avail_space = device->total_bytes - device->bytes_used;
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 -
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 802e2ba02f09..8fd5a4d8acc8 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -50,6 +50,7 @@ struct btrfs_device {
50 int in_fs_metadata; 50 int in_fs_metadata;
51 int missing; 51 int missing;
52 int can_discard; 52 int can_discard;
53 int is_tgtdev_for_dev_replace;
53 54
54 spinlock_t io_lock; 55 spinlock_t io_lock;
55 56