aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/dev-replace.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/dev-replace.c')
-rw-r--r--fs/btrfs/dev-replace.c58
1 files changed, 37 insertions, 21 deletions
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 1a3d24592859..5aebedf12b5f 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -302,8 +302,8 @@ void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info)
302 dev_replace->cursor_left_last_write_of_item; 302 dev_replace->cursor_left_last_write_of_item;
303} 303}
304 304
305int btrfs_dev_replace_start(struct btrfs_root *root, 305int btrfs_dev_replace_start(struct btrfs_root *root, char *tgtdev_name,
306 struct btrfs_ioctl_dev_replace_args *args) 306 u64 srcdevid, char *srcdev_name, int read_src)
307{ 307{
308 struct btrfs_trans_handle *trans; 308 struct btrfs_trans_handle *trans;
309 struct btrfs_fs_info *fs_info = root->fs_info; 309 struct btrfs_fs_info *fs_info = root->fs_info;
@@ -312,25 +312,16 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
312 struct btrfs_device *tgt_device = NULL; 312 struct btrfs_device *tgt_device = NULL;
313 struct btrfs_device *src_device = NULL; 313 struct btrfs_device *src_device = NULL;
314 314
315 switch (args->start.cont_reading_from_srcdev_mode) {
316 case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS:
317 case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID:
318 break;
319 default:
320 return -EINVAL;
321 }
322
323 /* the disk copy procedure reuses the scrub code */ 315 /* the disk copy procedure reuses the scrub code */
324 mutex_lock(&fs_info->volume_mutex); 316 mutex_lock(&fs_info->volume_mutex);
325 ret = btrfs_find_device_by_devspec(root, args->start.srcdevid, 317 ret = btrfs_find_device_by_devspec(root, srcdevid,
326 args->start.srcdev_name, 318 srcdev_name, &src_device);
327 &src_device);
328 if (ret) { 319 if (ret) {
329 mutex_unlock(&fs_info->volume_mutex); 320 mutex_unlock(&fs_info->volume_mutex);
330 return ret; 321 return ret;
331 } 322 }
332 323
333 ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name, 324 ret = btrfs_init_dev_replace_tgtdev(root, tgtdev_name,
334 src_device, &tgt_device); 325 src_device, &tgt_device);
335 mutex_unlock(&fs_info->volume_mutex); 326 mutex_unlock(&fs_info->volume_mutex);
336 if (ret) 327 if (ret)
@@ -357,12 +348,11 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
357 break; 348 break;
358 case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: 349 case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
359 case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: 350 case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
360 args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED; 351 ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED;
361 goto leave; 352 goto leave;
362 } 353 }
363 354
364 dev_replace->cont_reading_from_srcdev_mode = 355 dev_replace->cont_reading_from_srcdev_mode = read_src;
365 args->start.cont_reading_from_srcdev_mode;
366 WARN_ON(!src_device); 356 WARN_ON(!src_device);
367 dev_replace->srcdev = src_device; 357 dev_replace->srcdev = src_device;
368 WARN_ON(!tgt_device); 358 WARN_ON(!tgt_device);
@@ -389,7 +379,6 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
389 dev_replace->item_needs_writeback = 1; 379 dev_replace->item_needs_writeback = 1;
390 atomic64_set(&dev_replace->num_write_errors, 0); 380 atomic64_set(&dev_replace->num_write_errors, 0);
391 atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0); 381 atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0);
392 args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
393 btrfs_dev_replace_unlock(dev_replace, 1); 382 btrfs_dev_replace_unlock(dev_replace, 1);
394 383
395 ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device); 384 ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device);
@@ -415,10 +404,8 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
415 &dev_replace->scrub_progress, 0, 1); 404 &dev_replace->scrub_progress, 0, 1);
416 405
417 ret = btrfs_dev_replace_finishing(fs_info, ret); 406 ret = btrfs_dev_replace_finishing(fs_info, ret);
418 /* don't warn if EINPROGRESS, someone else might be running scrub */
419 if (ret == -EINPROGRESS) { 407 if (ret == -EINPROGRESS) {
420 args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS; 408 ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS;
421 ret = 0;
422 } else { 409 } else {
423 WARN_ON(ret); 410 WARN_ON(ret);
424 } 411 }
@@ -433,6 +420,35 @@ leave:
433 return ret; 420 return ret;
434} 421}
435 422
423int btrfs_dev_replace_by_ioctl(struct btrfs_root *root,
424 struct btrfs_ioctl_dev_replace_args *args)
425{
426 int ret;
427
428 switch (args->start.cont_reading_from_srcdev_mode) {
429 case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS:
430 case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID:
431 break;
432 default:
433 return -EINVAL;
434 }
435
436 if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') ||
437 args->start.tgtdev_name[0] == '\0')
438 return -EINVAL;
439
440 ret = btrfs_dev_replace_start(root, args->start.tgtdev_name,
441 args->start.srcdevid,
442 args->start.srcdev_name,
443 args->start.cont_reading_from_srcdev_mode);
444 args->result = ret;
445 /* don't warn if EINPROGRESS, someone else might be running scrub */
446 if (ret == BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS)
447 ret = 0;
448
449 return ret;
450}
451
436/* 452/*
437 * blocked until all flighting bios are finished. 453 * blocked until all flighting bios are finished.
438 */ 454 */