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.c101
1 files changed, 45 insertions, 56 deletions
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 26bcb487f958..85f12e6e28d2 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -44,9 +44,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
44 struct btrfs_fs_info *fs_info, 44 struct btrfs_fs_info *fs_info,
45 struct btrfs_device *srcdev, 45 struct btrfs_device *srcdev,
46 struct btrfs_device *tgtdev); 46 struct btrfs_device *tgtdev);
47static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid,
48 char *srcdev_name,
49 struct btrfs_device **device);
50static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info); 47static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info);
51static int btrfs_dev_replace_kthread(void *data); 48static int btrfs_dev_replace_kthread(void *data);
52static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info); 49static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info);
@@ -305,8 +302,8 @@ void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info)
305 dev_replace->cursor_left_last_write_of_item; 302 dev_replace->cursor_left_last_write_of_item;
306} 303}
307 304
308int btrfs_dev_replace_start(struct btrfs_root *root, 305int btrfs_dev_replace_start(struct btrfs_root *root, char *tgtdev_name,
309 struct btrfs_ioctl_dev_replace_args *args) 306 u64 srcdevid, char *srcdev_name, int read_src)
310{ 307{
311 struct btrfs_trans_handle *trans; 308 struct btrfs_trans_handle *trans;
312 struct btrfs_fs_info *fs_info = root->fs_info; 309 struct btrfs_fs_info *fs_info = root->fs_info;
@@ -315,29 +312,16 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
315 struct btrfs_device *tgt_device = NULL; 312 struct btrfs_device *tgt_device = NULL;
316 struct btrfs_device *src_device = NULL; 313 struct btrfs_device *src_device = NULL;
317 314
318 switch (args->start.cont_reading_from_srcdev_mode) {
319 case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS:
320 case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID:
321 break;
322 default:
323 return -EINVAL;
324 }
325
326 if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') ||
327 args->start.tgtdev_name[0] == '\0')
328 return -EINVAL;
329
330 /* the disk copy procedure reuses the scrub code */ 315 /* the disk copy procedure reuses the scrub code */
331 mutex_lock(&fs_info->volume_mutex); 316 mutex_lock(&fs_info->volume_mutex);
332 ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid, 317 ret = btrfs_find_device_by_devspec(root, srcdevid,
333 args->start.srcdev_name, 318 srcdev_name, &src_device);
334 &src_device);
335 if (ret) { 319 if (ret) {
336 mutex_unlock(&fs_info->volume_mutex); 320 mutex_unlock(&fs_info->volume_mutex);
337 return ret; 321 return ret;
338 } 322 }
339 323
340 ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name, 324 ret = btrfs_init_dev_replace_tgtdev(root, tgtdev_name,
341 src_device, &tgt_device); 325 src_device, &tgt_device);
342 mutex_unlock(&fs_info->volume_mutex); 326 mutex_unlock(&fs_info->volume_mutex);
343 if (ret) 327 if (ret)
@@ -364,18 +348,17 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
364 break; 348 break;
365 case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: 349 case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
366 case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: 350 case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
367 args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED; 351 ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED;
368 goto leave; 352 goto leave;
369 } 353 }
370 354
371 dev_replace->cont_reading_from_srcdev_mode = 355 dev_replace->cont_reading_from_srcdev_mode = read_src;
372 args->start.cont_reading_from_srcdev_mode;
373 WARN_ON(!src_device); 356 WARN_ON(!src_device);
374 dev_replace->srcdev = src_device; 357 dev_replace->srcdev = src_device;
375 WARN_ON(!tgt_device); 358 WARN_ON(!tgt_device);
376 dev_replace->tgtdev = tgt_device; 359 dev_replace->tgtdev = tgt_device;
377 360
378 btrfs_info_in_rcu(root->fs_info, 361 btrfs_info_in_rcu(fs_info,
379 "dev_replace from %s (devid %llu) to %s started", 362 "dev_replace from %s (devid %llu) to %s started",
380 src_device->missing ? "<missing disk>" : 363 src_device->missing ? "<missing disk>" :
381 rcu_str_deref(src_device->name), 364 rcu_str_deref(src_device->name),
@@ -396,14 +379,13 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
396 dev_replace->item_needs_writeback = 1; 379 dev_replace->item_needs_writeback = 1;
397 atomic64_set(&dev_replace->num_write_errors, 0); 380 atomic64_set(&dev_replace->num_write_errors, 0);
398 atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0); 381 atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0);
399 args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
400 btrfs_dev_replace_unlock(dev_replace, 1); 382 btrfs_dev_replace_unlock(dev_replace, 1);
401 383
402 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);
403 if (ret) 385 if (ret)
404 btrfs_err(root->fs_info, "kobj add dev failed %d\n", ret); 386 btrfs_err(fs_info, "kobj add dev failed %d\n", ret);
405 387
406 btrfs_wait_ordered_roots(root->fs_info, -1); 388 btrfs_wait_ordered_roots(root->fs_info, -1, 0, (u64)-1);
407 389
408 /* force writing the updated state information to disk */ 390 /* force writing the updated state information to disk */
409 trans = btrfs_start_transaction(root, 0); 391 trans = btrfs_start_transaction(root, 0);
@@ -421,11 +403,9 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
421 btrfs_device_get_total_bytes(src_device), 403 btrfs_device_get_total_bytes(src_device),
422 &dev_replace->scrub_progress, 0, 1); 404 &dev_replace->scrub_progress, 0, 1);
423 405
424 ret = btrfs_dev_replace_finishing(root->fs_info, ret); 406 ret = btrfs_dev_replace_finishing(fs_info, ret);
425 /* don't warn if EINPROGRESS, someone else might be running scrub */
426 if (ret == -EINPROGRESS) { 407 if (ret == -EINPROGRESS) {
427 args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS; 408 ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS;
428 ret = 0;
429 } else { 409 } else {
430 WARN_ON(ret); 410 WARN_ON(ret);
431 } 411 }
@@ -440,6 +420,35 @@ leave:
440 return ret; 420 return ret;
441} 421}
442 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
443/* 452/*
444 * blocked until all flighting bios are finished. 453 * blocked until all flighting bios are finished.
445 */ 454 */
@@ -495,7 +504,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
495 mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); 504 mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
496 return ret; 505 return ret;
497 } 506 }
498 btrfs_wait_ordered_roots(root->fs_info, -1); 507 btrfs_wait_ordered_roots(root->fs_info, -1, 0, (u64)-1);
499 508
500 trans = btrfs_start_transaction(root, 0); 509 trans = btrfs_start_transaction(root, 0);
501 if (IS_ERR(trans)) { 510 if (IS_ERR(trans)) {
@@ -560,10 +569,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
560 ASSERT(list_empty(&src_device->resized_list)); 569 ASSERT(list_empty(&src_device->resized_list));
561 tgt_device->commit_total_bytes = src_device->commit_total_bytes; 570 tgt_device->commit_total_bytes = src_device->commit_total_bytes;
562 tgt_device->commit_bytes_used = src_device->bytes_used; 571 tgt_device->commit_bytes_used = src_device->bytes_used;
563 if (fs_info->sb->s_bdev == src_device->bdev) 572
564 fs_info->sb->s_bdev = tgt_device->bdev; 573 btrfs_assign_next_active_device(fs_info, src_device, tgt_device);
565 if (fs_info->fs_devices->latest_bdev == src_device->bdev) 574
566 fs_info->fs_devices->latest_bdev = tgt_device->bdev;
567 list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); 575 list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);
568 fs_info->fs_devices->rw_devices++; 576 fs_info->fs_devices->rw_devices++;
569 577
@@ -626,25 +634,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
626 write_unlock(&em_tree->lock); 634 write_unlock(&em_tree->lock);
627} 635}
628 636
629static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid,
630 char *srcdev_name,
631 struct btrfs_device **device)
632{
633 int ret;
634
635 if (srcdevid) {
636 ret = 0;
637 *device = btrfs_find_device(root->fs_info, srcdevid, NULL,
638 NULL);
639 if (!*device)
640 ret = -ENOENT;
641 } else {
642 ret = btrfs_find_device_missing_or_by_path(root, srcdev_name,
643 device);
644 }
645 return ret;
646}
647
648void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, 637void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
649 struct btrfs_ioctl_dev_replace_args *args) 638 struct btrfs_ioctl_dev_replace_args *args)
650{ 639{