diff options
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 4066803fe765..75bdea6bf188 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -3559,10 +3559,76 @@ out: | |||
3559 | btrfs_free_path(path); | 3559 | btrfs_free_path(path); |
3560 | if (ret) | 3560 | if (ret) |
3561 | pr_warn("btrfs: btrfs_uuid_scan_kthread failed %d\n", ret); | 3561 | pr_warn("btrfs: btrfs_uuid_scan_kthread failed %d\n", ret); |
3562 | else | ||
3563 | fs_info->update_uuid_tree_gen = 1; | ||
3562 | up(&fs_info->uuid_tree_rescan_sem); | 3564 | up(&fs_info->uuid_tree_rescan_sem); |
3563 | return 0; | 3565 | return 0; |
3564 | } | 3566 | } |
3565 | 3567 | ||
3568 | /* | ||
3569 | * Callback for btrfs_uuid_tree_iterate(). | ||
3570 | * returns: | ||
3571 | * 0 check succeeded, the entry is not outdated. | ||
3572 | * < 0 if an error occured. | ||
3573 | * > 0 if the check failed, which means the caller shall remove the entry. | ||
3574 | */ | ||
3575 | static int btrfs_check_uuid_tree_entry(struct btrfs_fs_info *fs_info, | ||
3576 | u8 *uuid, u8 type, u64 subid) | ||
3577 | { | ||
3578 | struct btrfs_key key; | ||
3579 | int ret = 0; | ||
3580 | struct btrfs_root *subvol_root; | ||
3581 | |||
3582 | if (type != BTRFS_UUID_KEY_SUBVOL && | ||
3583 | type != BTRFS_UUID_KEY_RECEIVED_SUBVOL) | ||
3584 | goto out; | ||
3585 | |||
3586 | key.objectid = subid; | ||
3587 | key.type = BTRFS_ROOT_ITEM_KEY; | ||
3588 | key.offset = (u64)-1; | ||
3589 | subvol_root = btrfs_read_fs_root_no_name(fs_info, &key); | ||
3590 | if (IS_ERR(subvol_root)) { | ||
3591 | ret = PTR_ERR(subvol_root); | ||
3592 | if (ret == -ENOENT) | ||
3593 | ret = 1; | ||
3594 | goto out; | ||
3595 | } | ||
3596 | |||
3597 | switch (type) { | ||
3598 | case BTRFS_UUID_KEY_SUBVOL: | ||
3599 | if (memcmp(uuid, subvol_root->root_item.uuid, BTRFS_UUID_SIZE)) | ||
3600 | ret = 1; | ||
3601 | break; | ||
3602 | case BTRFS_UUID_KEY_RECEIVED_SUBVOL: | ||
3603 | if (memcmp(uuid, subvol_root->root_item.received_uuid, | ||
3604 | BTRFS_UUID_SIZE)) | ||
3605 | ret = 1; | ||
3606 | break; | ||
3607 | } | ||
3608 | |||
3609 | out: | ||
3610 | return ret; | ||
3611 | } | ||
3612 | |||
3613 | static int btrfs_uuid_rescan_kthread(void *data) | ||
3614 | { | ||
3615 | struct btrfs_fs_info *fs_info = (struct btrfs_fs_info *)data; | ||
3616 | int ret; | ||
3617 | |||
3618 | /* | ||
3619 | * 1st step is to iterate through the existing UUID tree and | ||
3620 | * to delete all entries that contain outdated data. | ||
3621 | * 2nd step is to add all missing entries to the UUID tree. | ||
3622 | */ | ||
3623 | ret = btrfs_uuid_tree_iterate(fs_info, btrfs_check_uuid_tree_entry); | ||
3624 | if (ret < 0) { | ||
3625 | pr_warn("btrfs: iterating uuid_tree failed %d\n", ret); | ||
3626 | up(&fs_info->uuid_tree_rescan_sem); | ||
3627 | return ret; | ||
3628 | } | ||
3629 | return btrfs_uuid_scan_kthread(data); | ||
3630 | } | ||
3631 | |||
3566 | int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info) | 3632 | int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info) |
3567 | { | 3633 | { |
3568 | struct btrfs_trans_handle *trans; | 3634 | struct btrfs_trans_handle *trans; |
@@ -3596,6 +3662,7 @@ int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info) | |||
3596 | down(&fs_info->uuid_tree_rescan_sem); | 3662 | down(&fs_info->uuid_tree_rescan_sem); |
3597 | task = kthread_run(btrfs_uuid_scan_kthread, fs_info, "btrfs-uuid"); | 3663 | task = kthread_run(btrfs_uuid_scan_kthread, fs_info, "btrfs-uuid"); |
3598 | if (IS_ERR(task)) { | 3664 | if (IS_ERR(task)) { |
3665 | /* fs_info->update_uuid_tree_gen remains 0 in all error case */ | ||
3599 | pr_warn("btrfs: failed to start uuid_scan task\n"); | 3666 | pr_warn("btrfs: failed to start uuid_scan task\n"); |
3600 | up(&fs_info->uuid_tree_rescan_sem); | 3667 | up(&fs_info->uuid_tree_rescan_sem); |
3601 | return PTR_ERR(task); | 3668 | return PTR_ERR(task); |
@@ -3604,6 +3671,22 @@ int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info) | |||
3604 | return 0; | 3671 | return 0; |
3605 | } | 3672 | } |
3606 | 3673 | ||
3674 | int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info) | ||
3675 | { | ||
3676 | struct task_struct *task; | ||
3677 | |||
3678 | down(&fs_info->uuid_tree_rescan_sem); | ||
3679 | task = kthread_run(btrfs_uuid_rescan_kthread, fs_info, "btrfs-uuid"); | ||
3680 | if (IS_ERR(task)) { | ||
3681 | /* fs_info->update_uuid_tree_gen remains 0 in all error case */ | ||
3682 | pr_warn("btrfs: failed to start uuid_rescan task\n"); | ||
3683 | up(&fs_info->uuid_tree_rescan_sem); | ||
3684 | return PTR_ERR(task); | ||
3685 | } | ||
3686 | |||
3687 | return 0; | ||
3688 | } | ||
3689 | |||
3607 | /* | 3690 | /* |
3608 | * shrinking a device means finding all of the device extents past | 3691 | * shrinking a device means finding all of the device extents past |
3609 | * the new size, and then following the back refs to the chunks. | 3692 | * the new size, and then following the back refs to the chunks. |