aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorStefan Behrens <sbehrens@giantdisaster.de>2013-08-15 11:11:21 -0400
committerChris Mason <chris.mason@fusionio.com>2013-09-01 08:15:56 -0400
commit803b2f54fb4faf6d76fca43e59bcc555d9713cd4 (patch)
treef5e5c56d186aa1829aaedb652756ec8f4644e05b /fs/btrfs/volumes.c
parentdd5f9615fc5c5e8d3751aab3a17b92768fb1ce70 (diff)
Btrfs: fill UUID tree initially
When the UUID tree is initially created, a task is spawned that walks through the root tree. For each found subvolume root_item, the uuid and received_uuid entries in the UUID tree are added. This is such a quick operation so that in case somebody wants to unmount the filesystem while the task is still running, the unmount is delayed until the UUID tree building task is finished. 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.c151
1 files changed, 150 insertions, 1 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index e084218c09d2..4066803fe765 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -26,6 +26,7 @@
26#include <linux/ratelimit.h> 26#include <linux/ratelimit.h>
27#include <linux/kthread.h> 27#include <linux/kthread.h>
28#include <linux/raid/pq.h> 28#include <linux/raid/pq.h>
29#include <linux/semaphore.h>
29#include <asm/div64.h> 30#include <asm/div64.h>
30#include "compat.h" 31#include "compat.h"
31#include "ctree.h" 32#include "ctree.h"
@@ -3429,11 +3430,146 @@ int btrfs_cancel_balance(struct btrfs_fs_info *fs_info)
3429 return 0; 3430 return 0;
3430} 3431}
3431 3432
3433static int btrfs_uuid_scan_kthread(void *data)
3434{
3435 struct btrfs_fs_info *fs_info = data;
3436 struct btrfs_root *root = fs_info->tree_root;
3437 struct btrfs_key key;
3438 struct btrfs_key max_key;
3439 struct btrfs_path *path = NULL;
3440 int ret = 0;
3441 struct extent_buffer *eb;
3442 int slot;
3443 struct btrfs_root_item root_item;
3444 u32 item_size;
3445 struct btrfs_trans_handle *trans;
3446
3447 path = btrfs_alloc_path();
3448 if (!path) {
3449 ret = -ENOMEM;
3450 goto out;
3451 }
3452
3453 key.objectid = 0;
3454 key.type = BTRFS_ROOT_ITEM_KEY;
3455 key.offset = 0;
3456
3457 max_key.objectid = (u64)-1;
3458 max_key.type = BTRFS_ROOT_ITEM_KEY;
3459 max_key.offset = (u64)-1;
3460
3461 path->keep_locks = 1;
3462
3463 while (1) {
3464 ret = btrfs_search_forward(root, &key, &max_key, path, 0);
3465 if (ret) {
3466 if (ret > 0)
3467 ret = 0;
3468 break;
3469 }
3470
3471 if (key.type != BTRFS_ROOT_ITEM_KEY ||
3472 (key.objectid < BTRFS_FIRST_FREE_OBJECTID &&
3473 key.objectid != BTRFS_FS_TREE_OBJECTID) ||
3474 key.objectid > BTRFS_LAST_FREE_OBJECTID)
3475 goto skip;
3476
3477 eb = path->nodes[0];
3478 slot = path->slots[0];
3479 item_size = btrfs_item_size_nr(eb, slot);
3480 if (item_size < sizeof(root_item))
3481 goto skip;
3482
3483 trans = NULL;
3484 read_extent_buffer(eb, &root_item,
3485 btrfs_item_ptr_offset(eb, slot),
3486 (int)sizeof(root_item));
3487 if (btrfs_root_refs(&root_item) == 0)
3488 goto skip;
3489 if (!btrfs_is_empty_uuid(root_item.uuid)) {
3490 /*
3491 * 1 - subvol uuid item
3492 * 1 - received_subvol uuid item
3493 */
3494 trans = btrfs_start_transaction(fs_info->uuid_root, 2);
3495 if (IS_ERR(trans)) {
3496 ret = PTR_ERR(trans);
3497 break;
3498 }
3499 ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root,
3500 root_item.uuid,
3501 BTRFS_UUID_KEY_SUBVOL,
3502 key.objectid);
3503 if (ret < 0) {
3504 pr_warn("btrfs: uuid_tree_add failed %d\n",
3505 ret);
3506 btrfs_end_transaction(trans,
3507 fs_info->uuid_root);
3508 break;
3509 }
3510 }
3511
3512 if (!btrfs_is_empty_uuid(root_item.received_uuid)) {
3513 if (!trans) {
3514 /* 1 - received_subvol uuid item */
3515 trans = btrfs_start_transaction(
3516 fs_info->uuid_root, 1);
3517 if (IS_ERR(trans)) {
3518 ret = PTR_ERR(trans);
3519 break;
3520 }
3521 }
3522 ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root,
3523 root_item.received_uuid,
3524 BTRFS_UUID_KEY_RECEIVED_SUBVOL,
3525 key.objectid);
3526 if (ret < 0) {
3527 pr_warn("btrfs: uuid_tree_add failed %d\n",
3528 ret);
3529 btrfs_end_transaction(trans,
3530 fs_info->uuid_root);
3531 break;
3532 }
3533 }
3534
3535 if (trans) {
3536 ret = btrfs_end_transaction(trans, fs_info->uuid_root);
3537 if (ret)
3538 break;
3539 }
3540
3541skip:
3542 btrfs_release_path(path);
3543 if (key.offset < (u64)-1) {
3544 key.offset++;
3545 } else if (key.type < BTRFS_ROOT_ITEM_KEY) {
3546 key.offset = 0;
3547 key.type = BTRFS_ROOT_ITEM_KEY;
3548 } else if (key.objectid < (u64)-1) {
3549 key.offset = 0;
3550 key.type = BTRFS_ROOT_ITEM_KEY;
3551 key.objectid++;
3552 } else {
3553 break;
3554 }
3555 cond_resched();
3556 }
3557
3558out:
3559 btrfs_free_path(path);
3560 if (ret)
3561 pr_warn("btrfs: btrfs_uuid_scan_kthread failed %d\n", ret);
3562 up(&fs_info->uuid_tree_rescan_sem);
3563 return 0;
3564}
3565
3432int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info) 3566int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info)
3433{ 3567{
3434 struct btrfs_trans_handle *trans; 3568 struct btrfs_trans_handle *trans;
3435 struct btrfs_root *tree_root = fs_info->tree_root; 3569 struct btrfs_root *tree_root = fs_info->tree_root;
3436 struct btrfs_root *uuid_root; 3570 struct btrfs_root *uuid_root;
3571 struct task_struct *task;
3572 int ret;
3437 3573
3438 /* 3574 /*
3439 * 1 - root node 3575 * 1 - root node
@@ -3453,8 +3589,21 @@ int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info)
3453 3589
3454 fs_info->uuid_root = uuid_root; 3590 fs_info->uuid_root = uuid_root;
3455 3591
3456 return btrfs_commit_transaction(trans, tree_root); 3592 ret = btrfs_commit_transaction(trans, tree_root);
3593 if (ret)
3594 return ret;
3595
3596 down(&fs_info->uuid_tree_rescan_sem);
3597 task = kthread_run(btrfs_uuid_scan_kthread, fs_info, "btrfs-uuid");
3598 if (IS_ERR(task)) {
3599 pr_warn("btrfs: failed to start uuid_scan task\n");
3600 up(&fs_info->uuid_tree_rescan_sem);
3601 return PTR_ERR(task);
3602 }
3603
3604 return 0;
3457} 3605}
3606
3458/* 3607/*
3459 * shrinking a device means finding all of the device extents past 3608 * shrinking a device means finding all of the device extents past
3460 * the new size, and then following the back refs to the chunks. 3609 * the new size, and then following the back refs to the chunks.