diff options
| -rw-r--r-- | fs/btrfs/dev-replace.c | 99 | ||||
| -rw-r--r-- | fs/btrfs/dev-replace.h | 4 | ||||
| -rw-r--r-- | fs/btrfs/ioctl.c | 60 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 379 | ||||
| -rw-r--r-- | fs/btrfs/volumes.h | 9 | ||||
| -rw-r--r-- | include/uapi/linux/btrfs.h | 15 |
6 files changed, 324 insertions, 242 deletions
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 26bcb487f958..1f193f742f21 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); |
| 47 | static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid, | ||
| 48 | char *srcdev_name, | ||
| 49 | struct btrfs_device **device); | ||
| 50 | static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info); | 47 | static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info); |
| 51 | static int btrfs_dev_replace_kthread(void *data); | 48 | static int btrfs_dev_replace_kthread(void *data); |
| 52 | static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info); | 49 | static 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 | ||
| 308 | int btrfs_dev_replace_start(struct btrfs_root *root, | 305 | int 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(fs_info, -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 | ||
| 423 | int 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 | */ |
| @@ -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 | ||
| 629 | static 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 | |||
| 648 | void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, | 637 | void 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 | { |
diff --git a/fs/btrfs/dev-replace.h b/fs/btrfs/dev-replace.h index 29e3ef5f96bd..e922b42d91df 100644 --- a/fs/btrfs/dev-replace.h +++ b/fs/btrfs/dev-replace.h | |||
| @@ -25,8 +25,10 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info); | |||
| 25 | int btrfs_run_dev_replace(struct btrfs_trans_handle *trans, | 25 | int btrfs_run_dev_replace(struct btrfs_trans_handle *trans, |
| 26 | struct btrfs_fs_info *fs_info); | 26 | struct btrfs_fs_info *fs_info); |
| 27 | void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info); | 27 | void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info); |
| 28 | int btrfs_dev_replace_start(struct btrfs_root *root, | 28 | int btrfs_dev_replace_by_ioctl(struct btrfs_root *root, |
| 29 | struct btrfs_ioctl_dev_replace_args *args); | 29 | struct btrfs_ioctl_dev_replace_args *args); |
| 30 | int btrfs_dev_replace_start(struct btrfs_root *root, char *tgtdev_name, | ||
| 31 | u64 srcdevid, char *srcdev_name, int read_src); | ||
| 30 | void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, | 32 | void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, |
| 31 | struct btrfs_ioctl_dev_replace_args *args); | 33 | struct btrfs_ioctl_dev_replace_args *args); |
| 32 | int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info, | 34 | int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info, |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index b0ccb3b03d94..aa97dfe8ae70 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -2676,6 +2676,60 @@ out: | |||
| 2676 | return ret; | 2676 | return ret; |
| 2677 | } | 2677 | } |
| 2678 | 2678 | ||
| 2679 | static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) | ||
| 2680 | { | ||
| 2681 | struct btrfs_root *root = BTRFS_I(file_inode(file))->root; | ||
| 2682 | struct btrfs_ioctl_vol_args_v2 *vol_args; | ||
| 2683 | int ret; | ||
| 2684 | |||
| 2685 | if (!capable(CAP_SYS_ADMIN)) | ||
| 2686 | return -EPERM; | ||
| 2687 | |||
| 2688 | ret = mnt_want_write_file(file); | ||
| 2689 | if (ret) | ||
| 2690 | return ret; | ||
| 2691 | |||
| 2692 | vol_args = memdup_user(arg, sizeof(*vol_args)); | ||
| 2693 | if (IS_ERR(vol_args)) { | ||
| 2694 | ret = PTR_ERR(vol_args); | ||
| 2695 | goto err_drop; | ||
| 2696 | } | ||
| 2697 | |||
| 2698 | /* Check for compatibility reject unknown flags */ | ||
| 2699 | if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED) | ||
| 2700 | return -EOPNOTSUPP; | ||
| 2701 | |||
| 2702 | if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, | ||
| 2703 | 1)) { | ||
| 2704 | ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; | ||
| 2705 | goto out; | ||
| 2706 | } | ||
| 2707 | |||
| 2708 | mutex_lock(&root->fs_info->volume_mutex); | ||
| 2709 | if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) { | ||
| 2710 | ret = btrfs_rm_device(root, NULL, vol_args->devid); | ||
| 2711 | } else { | ||
| 2712 | vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; | ||
| 2713 | ret = btrfs_rm_device(root, vol_args->name, 0); | ||
| 2714 | } | ||
| 2715 | mutex_unlock(&root->fs_info->volume_mutex); | ||
| 2716 | atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); | ||
| 2717 | |||
| 2718 | if (!ret) { | ||
| 2719 | if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) | ||
| 2720 | btrfs_info(root->fs_info, "device deleted: id %llu", | ||
| 2721 | vol_args->devid); | ||
| 2722 | else | ||
| 2723 | btrfs_info(root->fs_info, "device deleted: %s", | ||
| 2724 | vol_args->name); | ||
| 2725 | } | ||
| 2726 | out: | ||
| 2727 | kfree(vol_args); | ||
| 2728 | err_drop: | ||
| 2729 | mnt_drop_write_file(file); | ||
| 2730 | return ret; | ||
| 2731 | } | ||
| 2732 | |||
| 2679 | static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) | 2733 | static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) |
| 2680 | { | 2734 | { |
| 2681 | struct btrfs_root *root = BTRFS_I(file_inode(file))->root; | 2735 | struct btrfs_root *root = BTRFS_I(file_inode(file))->root; |
| @@ -2703,7 +2757,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) | |||
| 2703 | 2757 | ||
| 2704 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 2758 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
| 2705 | mutex_lock(&root->fs_info->volume_mutex); | 2759 | mutex_lock(&root->fs_info->volume_mutex); |
| 2706 | ret = btrfs_rm_device(root, vol_args->name); | 2760 | ret = btrfs_rm_device(root, vol_args->name, 0); |
| 2707 | mutex_unlock(&root->fs_info->volume_mutex); | 2761 | mutex_unlock(&root->fs_info->volume_mutex); |
| 2708 | 2762 | ||
| 2709 | if (!ret) | 2763 | if (!ret) |
| @@ -4387,7 +4441,7 @@ static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg) | |||
| 4387 | 1)) { | 4441 | 1)) { |
| 4388 | ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; | 4442 | ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; |
| 4389 | } else { | 4443 | } else { |
| 4390 | ret = btrfs_dev_replace_start(root, p); | 4444 | ret = btrfs_dev_replace_by_ioctl(root, p); |
| 4391 | atomic_set( | 4445 | atomic_set( |
| 4392 | &root->fs_info->mutually_exclusive_operation_running, | 4446 | &root->fs_info->mutually_exclusive_operation_running, |
| 4393 | 0); | 4447 | 0); |
| @@ -5480,6 +5534,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
| 5480 | return btrfs_ioctl_add_dev(root, argp); | 5534 | return btrfs_ioctl_add_dev(root, argp); |
| 5481 | case BTRFS_IOC_RM_DEV: | 5535 | case BTRFS_IOC_RM_DEV: |
| 5482 | return btrfs_ioctl_rm_dev(file, argp); | 5536 | return btrfs_ioctl_rm_dev(file, argp); |
| 5537 | case BTRFS_IOC_RM_DEV_V2: | ||
| 5538 | return btrfs_ioctl_rm_dev_v2(file, argp); | ||
| 5483 | case BTRFS_IOC_FS_INFO: | 5539 | case BTRFS_IOC_FS_INFO: |
| 5484 | return btrfs_ioctl_fs_info(root, argp); | 5540 | return btrfs_ioctl_fs_info(root, argp); |
| 5485 | case BTRFS_IOC_DEV_INFO: | 5541 | case BTRFS_IOC_DEV_INFO: |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index dff515a134cd..e0290303bb35 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
| @@ -118,6 +118,21 @@ const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES] = { | |||
| 118 | [BTRFS_RAID_RAID6] = BTRFS_BLOCK_GROUP_RAID6, | 118 | [BTRFS_RAID_RAID6] = BTRFS_BLOCK_GROUP_RAID6, |
| 119 | }; | 119 | }; |
| 120 | 120 | ||
| 121 | /* | ||
| 122 | * Table to convert BTRFS_RAID_* to the error code if minimum number of devices | ||
| 123 | * condition is not met. Zero means there's no corresponding | ||
| 124 | * BTRFS_ERROR_DEV_*_NOT_MET value. | ||
| 125 | */ | ||
| 126 | const int btrfs_raid_mindev_error[BTRFS_NR_RAID_TYPES] = { | ||
| 127 | [BTRFS_RAID_RAID10] = BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET, | ||
| 128 | [BTRFS_RAID_RAID1] = BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET, | ||
| 129 | [BTRFS_RAID_DUP] = 0, | ||
| 130 | [BTRFS_RAID_RAID0] = 0, | ||
| 131 | [BTRFS_RAID_SINGLE] = 0, | ||
| 132 | [BTRFS_RAID_RAID5] = BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET, | ||
| 133 | [BTRFS_RAID_RAID6] = BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET, | ||
| 134 | }; | ||
| 135 | |||
| 121 | static int init_first_rw_device(struct btrfs_trans_handle *trans, | 136 | static int init_first_rw_device(struct btrfs_trans_handle *trans, |
| 122 | struct btrfs_root *root, | 137 | struct btrfs_root *root, |
| 123 | struct btrfs_device *device); | 138 | struct btrfs_device *device); |
| @@ -699,7 +714,8 @@ static noinline int device_list_add(const char *path, | |||
| 699 | * if there is new btrfs on an already registered device, | 714 | * if there is new btrfs on an already registered device, |
| 700 | * then remove the stale device entry. | 715 | * then remove the stale device entry. |
| 701 | */ | 716 | */ |
| 702 | btrfs_free_stale_device(device); | 717 | if (ret > 0) |
| 718 | btrfs_free_stale_device(device); | ||
| 703 | 719 | ||
| 704 | *fs_devices_ret = fs_devices; | 720 | *fs_devices_ret = fs_devices; |
| 705 | 721 | ||
| @@ -988,6 +1004,56 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, | |||
| 988 | return ret; | 1004 | return ret; |
| 989 | } | 1005 | } |
| 990 | 1006 | ||
| 1007 | void btrfs_release_disk_super(struct page *page) | ||
| 1008 | { | ||
| 1009 | kunmap(page); | ||
| 1010 | put_page(page); | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr, | ||
| 1014 | struct page **page, struct btrfs_super_block **disk_super) | ||
| 1015 | { | ||
| 1016 | void *p; | ||
| 1017 | pgoff_t index; | ||
| 1018 | |||
| 1019 | /* make sure our super fits in the device */ | ||
| 1020 | if (bytenr + PAGE_SIZE >= i_size_read(bdev->bd_inode)) | ||
| 1021 | return 1; | ||
| 1022 | |||
| 1023 | /* make sure our super fits in the page */ | ||
| 1024 | if (sizeof(**disk_super) > PAGE_SIZE) | ||
| 1025 | return 1; | ||
| 1026 | |||
| 1027 | /* make sure our super doesn't straddle pages on disk */ | ||
| 1028 | index = bytenr >> PAGE_SHIFT; | ||
| 1029 | if ((bytenr + sizeof(**disk_super) - 1) >> PAGE_SHIFT != index) | ||
| 1030 | return 1; | ||
| 1031 | |||
| 1032 | /* pull in the page with our super */ | ||
| 1033 | *page = read_cache_page_gfp(bdev->bd_inode->i_mapping, | ||
| 1034 | index, GFP_KERNEL); | ||
| 1035 | |||
| 1036 | if (IS_ERR_OR_NULL(*page)) | ||
| 1037 | return 1; | ||
| 1038 | |||
| 1039 | p = kmap(*page); | ||
| 1040 | |||
| 1041 | /* align our pointer to the offset of the super block */ | ||
| 1042 | *disk_super = p + (bytenr & ~PAGE_MASK); | ||
| 1043 | |||
| 1044 | if (btrfs_super_bytenr(*disk_super) != bytenr || | ||
| 1045 | btrfs_super_magic(*disk_super) != BTRFS_MAGIC) { | ||
| 1046 | btrfs_release_disk_super(*page); | ||
| 1047 | return 1; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | if ((*disk_super)->label[0] && | ||
| 1051 | (*disk_super)->label[BTRFS_LABEL_SIZE - 1]) | ||
| 1052 | (*disk_super)->label[BTRFS_LABEL_SIZE - 1] = '\0'; | ||
| 1053 | |||
| 1054 | return 0; | ||
| 1055 | } | ||
| 1056 | |||
| 991 | /* | 1057 | /* |
| 992 | * Look for a btrfs signature on a device. This may be called out of the mount path | 1058 | * Look for a btrfs signature on a device. This may be called out of the mount path |
| 993 | * and we are not allowed to call set_blocksize during the scan. The superblock | 1059 | * and we are not allowed to call set_blocksize during the scan. The superblock |
| @@ -999,13 +1065,11 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, | |||
| 999 | struct btrfs_super_block *disk_super; | 1065 | struct btrfs_super_block *disk_super; |
| 1000 | struct block_device *bdev; | 1066 | struct block_device *bdev; |
| 1001 | struct page *page; | 1067 | struct page *page; |
| 1002 | void *p; | ||
| 1003 | int ret = -EINVAL; | 1068 | int ret = -EINVAL; |
| 1004 | u64 devid; | 1069 | u64 devid; |
| 1005 | u64 transid; | 1070 | u64 transid; |
| 1006 | u64 total_devices; | 1071 | u64 total_devices; |
| 1007 | u64 bytenr; | 1072 | u64 bytenr; |
| 1008 | pgoff_t index; | ||
| 1009 | 1073 | ||
| 1010 | /* | 1074 | /* |
| 1011 | * we would like to check all the supers, but that would make | 1075 | * we would like to check all the supers, but that would make |
| @@ -1018,41 +1082,14 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, | |||
| 1018 | mutex_lock(&uuid_mutex); | 1082 | mutex_lock(&uuid_mutex); |
| 1019 | 1083 | ||
| 1020 | bdev = blkdev_get_by_path(path, flags, holder); | 1084 | bdev = blkdev_get_by_path(path, flags, holder); |
| 1021 | |||
| 1022 | if (IS_ERR(bdev)) { | 1085 | if (IS_ERR(bdev)) { |
| 1023 | ret = PTR_ERR(bdev); | 1086 | ret = PTR_ERR(bdev); |
| 1024 | goto error; | 1087 | goto error; |
| 1025 | } | 1088 | } |
| 1026 | 1089 | ||
| 1027 | /* make sure our super fits in the device */ | 1090 | if (btrfs_read_disk_super(bdev, bytenr, &page, &disk_super)) |
| 1028 | if (bytenr + PAGE_SIZE >= i_size_read(bdev->bd_inode)) | ||
| 1029 | goto error_bdev_put; | ||
| 1030 | |||
| 1031 | /* make sure our super fits in the page */ | ||
| 1032 | if (sizeof(*disk_super) > PAGE_SIZE) | ||
| 1033 | goto error_bdev_put; | 1091 | goto error_bdev_put; |
| 1034 | 1092 | ||
| 1035 | /* make sure our super doesn't straddle pages on disk */ | ||
| 1036 | index = bytenr >> PAGE_SHIFT; | ||
| 1037 | if ((bytenr + sizeof(*disk_super) - 1) >> PAGE_SHIFT != index) | ||
| 1038 | goto error_bdev_put; | ||
| 1039 | |||
| 1040 | /* pull in the page with our super */ | ||
| 1041 | page = read_cache_page_gfp(bdev->bd_inode->i_mapping, | ||
| 1042 | index, GFP_NOFS); | ||
| 1043 | |||
| 1044 | if (IS_ERR_OR_NULL(page)) | ||
| 1045 | goto error_bdev_put; | ||
| 1046 | |||
| 1047 | p = kmap(page); | ||
| 1048 | |||
| 1049 | /* align our pointer to the offset of the super block */ | ||
| 1050 | disk_super = p + (bytenr & ~PAGE_MASK); | ||
| 1051 | |||
| 1052 | if (btrfs_super_bytenr(disk_super) != bytenr || | ||
| 1053 | btrfs_super_magic(disk_super) != BTRFS_MAGIC) | ||
| 1054 | goto error_unmap; | ||
| 1055 | |||
| 1056 | devid = btrfs_stack_device_id(&disk_super->dev_item); | 1093 | devid = btrfs_stack_device_id(&disk_super->dev_item); |
| 1057 | transid = btrfs_super_generation(disk_super); | 1094 | transid = btrfs_super_generation(disk_super); |
| 1058 | total_devices = btrfs_super_num_devices(disk_super); | 1095 | total_devices = btrfs_super_num_devices(disk_super); |
| @@ -1060,8 +1097,6 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, | |||
| 1060 | ret = device_list_add(path, disk_super, devid, fs_devices_ret); | 1097 | ret = device_list_add(path, disk_super, devid, fs_devices_ret); |
| 1061 | if (ret > 0) { | 1098 | if (ret > 0) { |
| 1062 | if (disk_super->label[0]) { | 1099 | if (disk_super->label[0]) { |
| 1063 | if (disk_super->label[BTRFS_LABEL_SIZE - 1]) | ||
| 1064 | disk_super->label[BTRFS_LABEL_SIZE - 1] = '\0'; | ||
| 1065 | printk(KERN_INFO "BTRFS: device label %s ", disk_super->label); | 1100 | printk(KERN_INFO "BTRFS: device label %s ", disk_super->label); |
| 1066 | } else { | 1101 | } else { |
| 1067 | printk(KERN_INFO "BTRFS: device fsid %pU ", disk_super->fsid); | 1102 | printk(KERN_INFO "BTRFS: device fsid %pU ", disk_super->fsid); |
| @@ -1073,9 +1108,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, | |||
| 1073 | if (!ret && fs_devices_ret) | 1108 | if (!ret && fs_devices_ret) |
| 1074 | (*fs_devices_ret)->total_devices = total_devices; | 1109 | (*fs_devices_ret)->total_devices = total_devices; |
| 1075 | 1110 | ||
| 1076 | error_unmap: | 1111 | btrfs_release_disk_super(page); |
| 1077 | kunmap(page); | ||
| 1078 | put_page(page); | ||
| 1079 | 1112 | ||
| 1080 | error_bdev_put: | 1113 | error_bdev_put: |
| 1081 | blkdev_put(bdev, flags); | 1114 | blkdev_put(bdev, flags); |
| @@ -1688,32 +1721,92 @@ out: | |||
| 1688 | return ret; | 1721 | return ret; |
| 1689 | } | 1722 | } |
| 1690 | 1723 | ||
| 1691 | int btrfs_rm_device(struct btrfs_root *root, char *device_path) | 1724 | /* |
| 1725 | * Verify that @num_devices satisfies the RAID profile constraints in the whole | ||
| 1726 | * filesystem. It's up to the caller to adjust that number regarding eg. device | ||
| 1727 | * replace. | ||
| 1728 | */ | ||
| 1729 | static int btrfs_check_raid_min_devices(struct btrfs_fs_info *fs_info, | ||
| 1730 | u64 num_devices) | ||
| 1731 | { | ||
| 1732 | u64 all_avail; | ||
| 1733 | unsigned seq; | ||
| 1734 | int i; | ||
| 1735 | |||
| 1736 | do { | ||
| 1737 | seq = read_seqbegin(&fs_info->profiles_lock); | ||
| 1738 | |||
| 1739 | all_avail = fs_info->avail_data_alloc_bits | | ||
| 1740 | fs_info->avail_system_alloc_bits | | ||
| 1741 | fs_info->avail_metadata_alloc_bits; | ||
| 1742 | } while (read_seqretry(&fs_info->profiles_lock, seq)); | ||
| 1743 | |||
| 1744 | for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) { | ||
| 1745 | if (!(all_avail & btrfs_raid_group[i])) | ||
| 1746 | continue; | ||
| 1747 | |||
| 1748 | if (num_devices < btrfs_raid_array[i].devs_min) { | ||
| 1749 | int ret = btrfs_raid_mindev_error[i]; | ||
| 1750 | |||
| 1751 | if (ret) | ||
| 1752 | return ret; | ||
| 1753 | } | ||
| 1754 | } | ||
| 1755 | |||
| 1756 | return 0; | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | struct btrfs_device *btrfs_find_next_active_device(struct btrfs_fs_devices *fs_devs, | ||
| 1760 | struct btrfs_device *device) | ||
| 1692 | { | 1761 | { |
| 1693 | struct btrfs_device *device; | ||
| 1694 | struct btrfs_device *next_device; | 1762 | struct btrfs_device *next_device; |
| 1695 | struct block_device *bdev; | 1763 | |
| 1696 | struct buffer_head *bh = NULL; | 1764 | list_for_each_entry(next_device, &fs_devs->devices, dev_list) { |
| 1697 | struct btrfs_super_block *disk_super; | 1765 | if (next_device != device && |
| 1766 | !next_device->missing && next_device->bdev) | ||
| 1767 | return next_device; | ||
| 1768 | } | ||
| 1769 | |||
| 1770 | return NULL; | ||
| 1771 | } | ||
| 1772 | |||
| 1773 | /* | ||
| 1774 | * Helper function to check if the given device is part of s_bdev / latest_bdev | ||
| 1775 | * and replace it with the provided or the next active device, in the context | ||
| 1776 | * where this function called, there should be always be another device (or | ||
| 1777 | * this_dev) which is active. | ||
| 1778 | */ | ||
| 1779 | void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info, | ||
| 1780 | struct btrfs_device *device, struct btrfs_device *this_dev) | ||
| 1781 | { | ||
| 1782 | struct btrfs_device *next_device; | ||
| 1783 | |||
| 1784 | if (this_dev) | ||
| 1785 | next_device = this_dev; | ||
| 1786 | else | ||
| 1787 | next_device = btrfs_find_next_active_device(fs_info->fs_devices, | ||
| 1788 | device); | ||
| 1789 | ASSERT(next_device); | ||
| 1790 | |||
| 1791 | if (fs_info->sb->s_bdev && | ||
| 1792 | (fs_info->sb->s_bdev == device->bdev)) | ||
| 1793 | fs_info->sb->s_bdev = next_device->bdev; | ||
| 1794 | |||
| 1795 | if (fs_info->fs_devices->latest_bdev == device->bdev) | ||
| 1796 | fs_info->fs_devices->latest_bdev = next_device->bdev; | ||
| 1797 | } | ||
| 1798 | |||
| 1799 | int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid) | ||
| 1800 | { | ||
| 1801 | struct btrfs_device *device; | ||
| 1698 | struct btrfs_fs_devices *cur_devices; | 1802 | struct btrfs_fs_devices *cur_devices; |
| 1699 | u64 all_avail; | ||
| 1700 | u64 devid; | ||
| 1701 | u64 num_devices; | 1803 | u64 num_devices; |
| 1702 | u8 *dev_uuid; | ||
| 1703 | unsigned seq; | ||
| 1704 | int ret = 0; | 1804 | int ret = 0; |
| 1705 | bool clear_super = false; | 1805 | bool clear_super = false; |
| 1806 | char *dev_name = NULL; | ||
| 1706 | 1807 | ||
| 1707 | mutex_lock(&uuid_mutex); | 1808 | mutex_lock(&uuid_mutex); |
| 1708 | 1809 | ||
| 1709 | do { | ||
| 1710 | seq = read_seqbegin(&root->fs_info->profiles_lock); | ||
| 1711 | |||
| 1712 | all_avail = root->fs_info->avail_data_alloc_bits | | ||
| 1713 | root->fs_info->avail_system_alloc_bits | | ||
| 1714 | root->fs_info->avail_metadata_alloc_bits; | ||
| 1715 | } while (read_seqretry(&root->fs_info->profiles_lock, seq)); | ||
| 1716 | |||
| 1717 | num_devices = root->fs_info->fs_devices->num_devices; | 1810 | num_devices = root->fs_info->fs_devices->num_devices; |
| 1718 | btrfs_dev_replace_lock(&root->fs_info->dev_replace, 0); | 1811 | btrfs_dev_replace_lock(&root->fs_info->dev_replace, 0); |
| 1719 | if (btrfs_dev_replace_is_ongoing(&root->fs_info->dev_replace)) { | 1812 | if (btrfs_dev_replace_is_ongoing(&root->fs_info->dev_replace)) { |
| @@ -1722,78 +1815,23 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
| 1722 | } | 1815 | } |
| 1723 | btrfs_dev_replace_unlock(&root->fs_info->dev_replace, 0); | 1816 | btrfs_dev_replace_unlock(&root->fs_info->dev_replace, 0); |
| 1724 | 1817 | ||
| 1725 | if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) && num_devices <= 4) { | 1818 | ret = btrfs_check_raid_min_devices(root->fs_info, num_devices - 1); |
| 1726 | ret = BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET; | 1819 | if (ret) |
| 1727 | goto out; | ||
| 1728 | } | ||
| 1729 | |||
| 1730 | if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) && num_devices <= 2) { | ||
| 1731 | ret = BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET; | ||
| 1732 | goto out; | 1820 | goto out; |
| 1733 | } | ||
| 1734 | 1821 | ||
| 1735 | if ((all_avail & BTRFS_BLOCK_GROUP_RAID5) && | 1822 | ret = btrfs_find_device_by_devspec(root, devid, device_path, |
| 1736 | root->fs_info->fs_devices->rw_devices <= 2) { | 1823 | &device); |
| 1737 | ret = BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET; | 1824 | if (ret) |
| 1738 | goto out; | ||
| 1739 | } | ||
| 1740 | if ((all_avail & BTRFS_BLOCK_GROUP_RAID6) && | ||
| 1741 | root->fs_info->fs_devices->rw_devices <= 3) { | ||
| 1742 | ret = BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET; | ||
| 1743 | goto out; | 1825 | goto out; |
| 1744 | } | ||
| 1745 | |||
| 1746 | if (strcmp(device_path, "missing") == 0) { | ||
| 1747 | struct list_head *devices; | ||
| 1748 | struct btrfs_device *tmp; | ||
| 1749 | |||
| 1750 | device = NULL; | ||
| 1751 | devices = &root->fs_info->fs_devices->devices; | ||
| 1752 | /* | ||
| 1753 | * It is safe to read the devices since the volume_mutex | ||
| 1754 | * is held. | ||
| 1755 | */ | ||
| 1756 | list_for_each_entry(tmp, devices, dev_list) { | ||
| 1757 | if (tmp->in_fs_metadata && | ||
| 1758 | !tmp->is_tgtdev_for_dev_replace && | ||
| 1759 | !tmp->bdev) { | ||
| 1760 | device = tmp; | ||
| 1761 | break; | ||
| 1762 | } | ||
| 1763 | } | ||
| 1764 | bdev = NULL; | ||
| 1765 | bh = NULL; | ||
| 1766 | disk_super = NULL; | ||
| 1767 | if (!device) { | ||
| 1768 | ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND; | ||
| 1769 | goto out; | ||
| 1770 | } | ||
| 1771 | } else { | ||
| 1772 | ret = btrfs_get_bdev_and_sb(device_path, | ||
| 1773 | FMODE_WRITE | FMODE_EXCL, | ||
| 1774 | root->fs_info->bdev_holder, 0, | ||
| 1775 | &bdev, &bh); | ||
| 1776 | if (ret) | ||
| 1777 | goto out; | ||
| 1778 | disk_super = (struct btrfs_super_block *)bh->b_data; | ||
| 1779 | devid = btrfs_stack_device_id(&disk_super->dev_item); | ||
| 1780 | dev_uuid = disk_super->dev_item.uuid; | ||
| 1781 | device = btrfs_find_device(root->fs_info, devid, dev_uuid, | ||
| 1782 | disk_super->fsid); | ||
| 1783 | if (!device) { | ||
| 1784 | ret = -ENOENT; | ||
| 1785 | goto error_brelse; | ||
| 1786 | } | ||
| 1787 | } | ||
| 1788 | 1826 | ||
| 1789 | if (device->is_tgtdev_for_dev_replace) { | 1827 | if (device->is_tgtdev_for_dev_replace) { |
| 1790 | ret = BTRFS_ERROR_DEV_TGT_REPLACE; | 1828 | ret = BTRFS_ERROR_DEV_TGT_REPLACE; |
| 1791 | goto error_brelse; | 1829 | goto out; |
| 1792 | } | 1830 | } |
| 1793 | 1831 | ||
| 1794 | if (device->writeable && root->fs_info->fs_devices->rw_devices == 1) { | 1832 | if (device->writeable && root->fs_info->fs_devices->rw_devices == 1) { |
| 1795 | ret = BTRFS_ERROR_DEV_ONLY_WRITABLE; | 1833 | ret = BTRFS_ERROR_DEV_ONLY_WRITABLE; |
| 1796 | goto error_brelse; | 1834 | goto out; |
| 1797 | } | 1835 | } |
| 1798 | 1836 | ||
| 1799 | if (device->writeable) { | 1837 | if (device->writeable) { |
| @@ -1801,6 +1839,11 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
| 1801 | list_del_init(&device->dev_alloc_list); | 1839 | list_del_init(&device->dev_alloc_list); |
| 1802 | device->fs_devices->rw_devices--; | 1840 | device->fs_devices->rw_devices--; |
| 1803 | unlock_chunks(root); | 1841 | unlock_chunks(root); |
| 1842 | dev_name = kstrdup(device->name->str, GFP_KERNEL); | ||
| 1843 | if (!dev_name) { | ||
| 1844 | ret = -ENOMEM; | ||
| 1845 | goto error_undo; | ||
| 1846 | } | ||
| 1804 | clear_super = true; | 1847 | clear_super = true; |
| 1805 | } | 1848 | } |
| 1806 | 1849 | ||
| @@ -1842,12 +1885,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
| 1842 | if (device->missing) | 1885 | if (device->missing) |
| 1843 | device->fs_devices->missing_devices--; | 1886 | device->fs_devices->missing_devices--; |
| 1844 | 1887 | ||
| 1845 | next_device = list_entry(root->fs_info->fs_devices->devices.next, | 1888 | btrfs_assign_next_active_device(root->fs_info, device, NULL); |
| 1846 | struct btrfs_device, dev_list); | ||
| 1847 | if (device->bdev == root->fs_info->sb->s_bdev) | ||
| 1848 | root->fs_info->sb->s_bdev = next_device->bdev; | ||
| 1849 | if (device->bdev == root->fs_info->fs_devices->latest_bdev) | ||
| 1850 | root->fs_info->fs_devices->latest_bdev = next_device->bdev; | ||
| 1851 | 1889 | ||
| 1852 | if (device->bdev) { | 1890 | if (device->bdev) { |
| 1853 | device->fs_devices->open_devices--; | 1891 | device->fs_devices->open_devices--; |
| @@ -1883,63 +1921,23 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
| 1883 | * at this point, the device is zero sized. We want to | 1921 | * at this point, the device is zero sized. We want to |
| 1884 | * remove it from the devices list and zero out the old super | 1922 | * remove it from the devices list and zero out the old super |
| 1885 | */ | 1923 | */ |
| 1886 | if (clear_super && disk_super) { | 1924 | if (clear_super) { |
| 1887 | u64 bytenr; | 1925 | struct block_device *bdev; |
| 1888 | int i; | 1926 | |
| 1889 | 1927 | bdev = blkdev_get_by_path(dev_name, FMODE_READ | FMODE_EXCL, | |
| 1890 | /* make sure this device isn't detected as part of | 1928 | root->fs_info->bdev_holder); |
| 1891 | * the FS anymore | 1929 | if (!IS_ERR(bdev)) { |
| 1892 | */ | 1930 | btrfs_scratch_superblocks(bdev, dev_name); |
| 1893 | memset(&disk_super->magic, 0, sizeof(disk_super->magic)); | 1931 | blkdev_put(bdev, FMODE_READ | FMODE_EXCL); |
| 1894 | set_buffer_dirty(bh); | ||
| 1895 | sync_dirty_buffer(bh); | ||
| 1896 | |||
| 1897 | /* clear the mirror copies of super block on the disk | ||
| 1898 | * being removed, 0th copy is been taken care above and | ||
| 1899 | * the below would take of the rest | ||
| 1900 | */ | ||
| 1901 | for (i = 1; i < BTRFS_SUPER_MIRROR_MAX; i++) { | ||
| 1902 | bytenr = btrfs_sb_offset(i); | ||
| 1903 | if (bytenr + BTRFS_SUPER_INFO_SIZE >= | ||
| 1904 | i_size_read(bdev->bd_inode)) | ||
| 1905 | break; | ||
| 1906 | |||
| 1907 | brelse(bh); | ||
| 1908 | bh = __bread(bdev, bytenr / 4096, | ||
| 1909 | BTRFS_SUPER_INFO_SIZE); | ||
| 1910 | if (!bh) | ||
| 1911 | continue; | ||
| 1912 | |||
| 1913 | disk_super = (struct btrfs_super_block *)bh->b_data; | ||
| 1914 | |||
| 1915 | if (btrfs_super_bytenr(disk_super) != bytenr || | ||
| 1916 | btrfs_super_magic(disk_super) != BTRFS_MAGIC) { | ||
| 1917 | continue; | ||
| 1918 | } | ||
| 1919 | memset(&disk_super->magic, 0, | ||
| 1920 | sizeof(disk_super->magic)); | ||
| 1921 | set_buffer_dirty(bh); | ||
| 1922 | sync_dirty_buffer(bh); | ||
| 1923 | } | 1932 | } |
| 1924 | } | 1933 | } |
| 1925 | 1934 | ||
| 1926 | ret = 0; | ||
| 1927 | |||
| 1928 | if (bdev) { | ||
| 1929 | /* Notify udev that device has changed */ | ||
| 1930 | btrfs_kobject_uevent(bdev, KOBJ_CHANGE); | ||
| 1931 | |||
| 1932 | /* Update ctime/mtime for device path for libblkid */ | ||
| 1933 | update_dev_time(device_path); | ||
| 1934 | } | ||
| 1935 | |||
| 1936 | error_brelse: | ||
| 1937 | brelse(bh); | ||
| 1938 | if (bdev) | ||
| 1939 | blkdev_put(bdev, FMODE_READ | FMODE_EXCL); | ||
| 1940 | out: | 1935 | out: |
| 1936 | kfree(dev_name); | ||
| 1937 | |||
| 1941 | mutex_unlock(&uuid_mutex); | 1938 | mutex_unlock(&uuid_mutex); |
| 1942 | return ret; | 1939 | return ret; |
| 1940 | |||
| 1943 | error_undo: | 1941 | error_undo: |
| 1944 | if (device->writeable) { | 1942 | if (device->writeable) { |
| 1945 | lock_chunks(root); | 1943 | lock_chunks(root); |
| @@ -1948,7 +1946,7 @@ error_undo: | |||
| 1948 | device->fs_devices->rw_devices++; | 1946 | device->fs_devices->rw_devices++; |
| 1949 | unlock_chunks(root); | 1947 | unlock_chunks(root); |
| 1950 | } | 1948 | } |
| 1951 | goto error_brelse; | 1949 | goto out; |
| 1952 | } | 1950 | } |
| 1953 | 1951 | ||
| 1954 | void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info, | 1952 | void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info, |
| @@ -2017,8 +2015,6 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info, | |||
| 2017 | void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, | 2015 | void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, |
| 2018 | struct btrfs_device *tgtdev) | 2016 | struct btrfs_device *tgtdev) |
| 2019 | { | 2017 | { |
| 2020 | struct btrfs_device *next_device; | ||
| 2021 | |||
| 2022 | mutex_lock(&uuid_mutex); | 2018 | mutex_lock(&uuid_mutex); |
| 2023 | WARN_ON(!tgtdev); | 2019 | WARN_ON(!tgtdev); |
| 2024 | mutex_lock(&fs_info->fs_devices->device_list_mutex); | 2020 | mutex_lock(&fs_info->fs_devices->device_list_mutex); |
| @@ -2030,12 +2026,8 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, | |||
| 2030 | 2026 | ||
| 2031 | fs_info->fs_devices->num_devices--; | 2027 | fs_info->fs_devices->num_devices--; |
| 2032 | 2028 | ||
| 2033 | next_device = list_entry(fs_info->fs_devices->devices.next, | 2029 | btrfs_assign_next_active_device(fs_info, tgtdev, NULL); |
| 2034 | struct btrfs_device, dev_list); | 2030 | |
| 2035 | if (tgtdev->bdev == fs_info->sb->s_bdev) | ||
| 2036 | fs_info->sb->s_bdev = next_device->bdev; | ||
| 2037 | if (tgtdev->bdev == fs_info->fs_devices->latest_bdev) | ||
| 2038 | fs_info->fs_devices->latest_bdev = next_device->bdev; | ||
| 2039 | list_del_rcu(&tgtdev->dev_list); | 2031 | list_del_rcu(&tgtdev->dev_list); |
| 2040 | 2032 | ||
| 2041 | mutex_unlock(&fs_info->fs_devices->device_list_mutex); | 2033 | mutex_unlock(&fs_info->fs_devices->device_list_mutex); |
| @@ -2110,6 +2102,31 @@ int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, | |||
| 2110 | } | 2102 | } |
| 2111 | 2103 | ||
| 2112 | /* | 2104 | /* |
| 2105 | * Lookup a device given by device id, or the path if the id is 0. | ||
| 2106 | */ | ||
| 2107 | int btrfs_find_device_by_devspec(struct btrfs_root *root, u64 devid, | ||
| 2108 | char *devpath, | ||
| 2109 | struct btrfs_device **device) | ||
| 2110 | { | ||
| 2111 | int ret; | ||
| 2112 | |||
| 2113 | if (devid) { | ||
| 2114 | ret = 0; | ||
| 2115 | *device = btrfs_find_device(root->fs_info, devid, NULL, | ||
| 2116 | NULL); | ||
| 2117 | if (!*device) | ||
| 2118 | ret = -ENOENT; | ||
| 2119 | } else { | ||
| 2120 | if (!devpath || !devpath[0]) | ||
| 2121 | return -EINVAL; | ||
| 2122 | |||
| 2123 | ret = btrfs_find_device_missing_or_by_path(root, devpath, | ||
| 2124 | device); | ||
| 2125 | } | ||
| 2126 | return ret; | ||
| 2127 | } | ||
| 2128 | |||
| 2129 | /* | ||
| 2113 | * does all the dirty work required for changing file system's UUID. | 2130 | * does all the dirty work required for changing file system's UUID. |
| 2114 | */ | 2131 | */ |
| 2115 | static int btrfs_prepare_sprout(struct btrfs_root *root) | 2132 | static int btrfs_prepare_sprout(struct btrfs_root *root) |
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 7507be74f7da..19f6bb861640 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
| @@ -340,7 +340,7 @@ struct btrfs_raid_attr { | |||
| 340 | }; | 340 | }; |
| 341 | 341 | ||
| 342 | extern const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES]; | 342 | extern const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES]; |
| 343 | 343 | extern const int btrfs_raid_mindev_error[BTRFS_NR_RAID_TYPES]; | |
| 344 | extern const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES]; | 344 | extern const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES]; |
| 345 | 345 | ||
| 346 | struct map_lookup { | 346 | struct map_lookup { |
| @@ -445,13 +445,18 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, | |||
| 445 | struct btrfs_fs_devices **fs_devices_ret); | 445 | struct btrfs_fs_devices **fs_devices_ret); |
| 446 | int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); | 446 | int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); |
| 447 | void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices, int step); | 447 | void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices, int step); |
| 448 | void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info, | ||
| 449 | struct btrfs_device *device, struct btrfs_device *this_dev); | ||
| 448 | int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, | 450 | int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, |
| 449 | char *device_path, | 451 | char *device_path, |
| 450 | struct btrfs_device **device); | 452 | struct btrfs_device **device); |
| 453 | int btrfs_find_device_by_devspec(struct btrfs_root *root, u64 devid, | ||
| 454 | char *devpath, | ||
| 455 | struct btrfs_device **device); | ||
| 451 | struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, | 456 | struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, |
| 452 | const u64 *devid, | 457 | const u64 *devid, |
| 453 | const u8 *uuid); | 458 | const u8 *uuid); |
| 454 | int btrfs_rm_device(struct btrfs_root *root, char *device_path); | 459 | int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid); |
| 455 | void btrfs_cleanup_fs_uuids(void); | 460 | void btrfs_cleanup_fs_uuids(void); |
| 456 | int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len); | 461 | int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len); |
| 457 | int btrfs_grow_device(struct btrfs_trans_handle *trans, | 462 | int btrfs_grow_device(struct btrfs_trans_handle *trans, |
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index dea893199257..3975e683af72 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h | |||
| @@ -36,6 +36,14 @@ struct btrfs_ioctl_vol_args { | |||
| 36 | #define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) | 36 | #define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) |
| 37 | #define BTRFS_SUBVOL_RDONLY (1ULL << 1) | 37 | #define BTRFS_SUBVOL_RDONLY (1ULL << 1) |
| 38 | #define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2) | 38 | #define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2) |
| 39 | #define BTRFS_DEVICE_SPEC_BY_ID (1ULL << 3) | ||
| 40 | |||
| 41 | #define BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED \ | ||
| 42 | (BTRFS_SUBVOL_CREATE_ASYNC | \ | ||
| 43 | BTRFS_SUBVOL_RDONLY | \ | ||
| 44 | BTRFS_SUBVOL_QGROUP_INHERIT | \ | ||
| 45 | BTRFS_DEVICE_SPEC_BY_ID) | ||
| 46 | |||
| 39 | #define BTRFS_FSID_SIZE 16 | 47 | #define BTRFS_FSID_SIZE 16 |
| 40 | #define BTRFS_UUID_SIZE 16 | 48 | #define BTRFS_UUID_SIZE 16 |
| 41 | #define BTRFS_UUID_UNPARSED_SIZE 37 | 49 | #define BTRFS_UUID_UNPARSED_SIZE 37 |
| @@ -76,7 +84,10 @@ struct btrfs_ioctl_vol_args_v2 { | |||
| 76 | }; | 84 | }; |
| 77 | __u64 unused[4]; | 85 | __u64 unused[4]; |
| 78 | }; | 86 | }; |
| 79 | char name[BTRFS_SUBVOL_NAME_MAX + 1]; | 87 | union { |
| 88 | char name[BTRFS_SUBVOL_NAME_MAX + 1]; | ||
| 89 | u64 devid; | ||
| 90 | }; | ||
| 80 | }; | 91 | }; |
| 81 | 92 | ||
| 82 | /* | 93 | /* |
| @@ -659,5 +670,7 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) | |||
| 659 | struct btrfs_ioctl_feature_flags[2]) | 670 | struct btrfs_ioctl_feature_flags[2]) |
| 660 | #define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ | 671 | #define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ |
| 661 | struct btrfs_ioctl_feature_flags[3]) | 672 | struct btrfs_ioctl_feature_flags[3]) |
| 673 | #define BTRFS_IOC_RM_DEV_V2 _IOW(BTRFS_IOCTL_MAGIC, 58, \ | ||
| 674 | struct btrfs_ioctl_vol_args_v2) | ||
| 662 | 675 | ||
| 663 | #endif /* _UAPI_LINUX_BTRFS_H */ | 676 | #endif /* _UAPI_LINUX_BTRFS_H */ |
