aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorStefan Behrens <sbehrens@giantdisaster.de>2013-08-15 11:11:23 -0400
committerChris Mason <chris.mason@fusionio.com>2013-09-01 08:15:58 -0400
commit70f801754728017ebc909d603c69255dc1e6f06f (patch)
treef4af464776a17b130686cb85a98adbeb6083d43c /fs/btrfs/volumes.c
parent26432799c902b76e87f68f5c88f2146a78ba84af (diff)
Btrfs: check UUID tree during mount if required
If the filesystem was mounted with an old kernel that was not aware of the UUID tree, this is detected by looking at the uuid_tree_generation field of the superblock (similar to how the free space cache is doing it). If a mismatch is detected at mount time, a thread is started that does two things: 1. Iterate through the UUID tree, check each entry, delete those entries that are not valid anymore (i.e., the subvol does not exist anymore or the value changed). 2. Iterate through the root tree, for each found subvolume, add the UUID tree entries for the subvolume (if they are not already there). This mechanism is also used to handle and repair errors that happened during the initial creation and filling of the tree. The update of the uuid_tree_generation field (which indicates that the state of the UUID tree is up to date) is blocked until all create and repair operations are successfully completed. Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de> Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c83
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 */
3575static 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
3609out:
3610 return ret;
3611}
3612
3613static 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
3566int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info) 3632int 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
3674int 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.