Btrfs: fill UUID tree initially
[linux-2.6-block.git] / fs / btrfs / disk-io.c
index 6b092a1c4e37bab47adb0e9fc35ae6ec3e6081f8..fa49e900216a0e9773d6c25e345b04e3c8807853 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/migrate.h>
 #include <linux/ratelimit.h>
 #include <linux/uuid.h>
+#include <linux/semaphore.h>
 #include <asm/unaligned.h>
 #include "compat.h"
 #include "ctree.h"
@@ -576,8 +577,9 @@ static noinline int check_leaf(struct btrfs_root *root,
        return 0;
 }
 
-static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
-                              struct extent_state *state, int mirror)
+static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
+                                     u64 phy_offset, struct page *page,
+                                     u64 start, u64 end, int mirror)
 {
        struct extent_io_tree *tree;
        u64 found_start;
@@ -1148,6 +1150,10 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
                return NULL;
 
        ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
+       if (ret) {
+               free_extent_buffer(buf);
+               return NULL;
+       }
        return buf;
 
 }
@@ -1413,11 +1419,11 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
        log_root->root_key.offset = root->root_key.objectid;
 
        inode_item = &log_root->root_item.inode;
-       inode_item->generation = cpu_to_le64(1);
-       inode_item->size = cpu_to_le64(3);
-       inode_item->nlink = cpu_to_le32(1);
-       inode_item->nbytes = cpu_to_le64(root->leafsize);
-       inode_item->mode = cpu_to_le32(S_IFDIR | 0755);
+       btrfs_set_stack_inode_generation(inode_item, 1);
+       btrfs_set_stack_inode_size(inode_item, 3);
+       btrfs_set_stack_inode_nlink(inode_item, 1);
+       btrfs_set_stack_inode_nbytes(inode_item, root->leafsize);
+       btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755);
 
        btrfs_set_root_node(&log_root->root_item, log_root->node);
 
@@ -1428,8 +1434,8 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
-                                       struct btrfs_key *key)
+static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
+                                              struct btrfs_key *key)
 {
        struct btrfs_root *root;
        struct btrfs_fs_info *fs_info = tree_root->fs_info;
@@ -1529,8 +1535,8 @@ fail:
        return ret;
 }
 
-struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
-                                       u64 root_id)
+static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
+                                              u64 root_id)
 {
        struct btrfs_root *root;
 
@@ -1581,6 +1587,9 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
        if (location->objectid == BTRFS_QUOTA_TREE_OBJECTID)
                return fs_info->quota_root ? fs_info->quota_root :
                                             ERR_PTR(-ENOENT);
+       if (location->objectid == BTRFS_UUID_TREE_OBJECTID)
+               return fs_info->uuid_root ? fs_info->uuid_root :
+                                           ERR_PTR(-ENOENT);
 again:
        root = btrfs_lookup_fs_root(fs_info, location->objectid);
        if (root)
@@ -1737,7 +1746,7 @@ static int transaction_kthread(void *arg)
 
        do {
                cannot_commit = false;
-               delay = HZ * 30;
+               delay = HZ * root->fs_info->commit_interval;
                mutex_lock(&root->fs_info->transaction_kthread_mutex);
 
                spin_lock(&root->fs_info->trans_lock);
@@ -1749,7 +1758,8 @@ static int transaction_kthread(void *arg)
 
                now = get_seconds();
                if (cur->state < TRANS_STATE_BLOCKED &&
-                   (now < cur->start_time || now - cur->start_time < 30)) {
+                   (now < cur->start_time ||
+                    now - cur->start_time < root->fs_info->commit_interval)) {
                        spin_unlock(&root->fs_info->trans_lock);
                        delay = HZ * 5;
                        goto sleep;
@@ -2038,6 +2048,12 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
                info->quota_root->node = NULL;
                info->quota_root->commit_root = NULL;
        }
+       if (info->uuid_root) {
+               free_extent_buffer(info->uuid_root->node);
+               free_extent_buffer(info->uuid_root->commit_root);
+               info->uuid_root->node = NULL;
+               info->uuid_root->commit_root = NULL;
+       }
        if (chunk_root) {
                free_extent_buffer(info->chunk_root->node);
                free_extent_buffer(info->chunk_root->commit_root);
@@ -2098,11 +2114,13 @@ int open_ctree(struct super_block *sb,
        struct btrfs_root *chunk_root;
        struct btrfs_root *dev_root;
        struct btrfs_root *quota_root;
+       struct btrfs_root *uuid_root;
        struct btrfs_root *log_tree_root;
        int ret;
        int err = -EINVAL;
        int num_backups_tried = 0;
        int backup_index = 0;
+       bool create_uuid_tree = false;
 
        tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info);
        chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info);
@@ -2189,6 +2207,7 @@ int open_ctree(struct super_block *sb,
        fs_info->defrag_inodes = RB_ROOT;
        fs_info->free_chunk_space = 0;
        fs_info->tree_mod_log = RB_ROOT;
+       fs_info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
 
        /* readahead state */
        INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT);
@@ -2270,6 +2289,7 @@ int open_ctree(struct super_block *sb,
 
 
        mutex_init(&fs_info->ordered_operations_mutex);
+       mutex_init(&fs_info->ordered_extent_flush_mutex);
        mutex_init(&fs_info->tree_log_mutex);
        mutex_init(&fs_info->chunk_mutex);
        mutex_init(&fs_info->transaction_kthread_mutex);
@@ -2278,6 +2298,7 @@ int open_ctree(struct super_block *sb,
        init_rwsem(&fs_info->extent_commit_sem);
        init_rwsem(&fs_info->cleanup_work_sem);
        init_rwsem(&fs_info->subvol_sem);
+       sema_init(&fs_info->uuid_tree_rescan_sem, 1);
        fs_info->dev_replace.lock_owner = 0;
        atomic_set(&fs_info->dev_replace.nesting_level, 0);
        mutex_init(&fs_info->dev_replace.lock_finishing_cancel_unmount);
@@ -2575,7 +2596,7 @@ int open_ctree(struct super_block *sb,
        sb->s_blocksize = sectorsize;
        sb->s_blocksize_bits = blksize_bits(sectorsize);
 
-       if (disk_super->magic != cpu_to_le64(BTRFS_MAGIC)) {
+       if (btrfs_super_magic(disk_super) != BTRFS_MAGIC) {
                printk(KERN_INFO "btrfs: valid FS not found on %s\n", sb->s_id);
                goto fail_sb_buffer;
        }
@@ -2696,6 +2717,18 @@ retry_root_backup:
                fs_info->quota_root = quota_root;
        }
 
+       location.objectid = BTRFS_UUID_TREE_OBJECTID;
+       uuid_root = btrfs_read_tree_root(tree_root, &location);
+       if (IS_ERR(uuid_root)) {
+               ret = PTR_ERR(uuid_root);
+               if (ret != -ENOENT)
+                       goto recovery_tree_root;
+               create_uuid_tree = true;
+       } else {
+               uuid_root->track_dirty = 1;
+               fs_info->uuid_root = uuid_root;
+       }
+
        fs_info->generation = generation;
        fs_info->last_trans_committed = generation;
 
@@ -2882,6 +2915,17 @@ retry_root_backup:
 
        btrfs_qgroup_rescan_resume(fs_info);
 
+       if (create_uuid_tree) {
+               pr_info("btrfs: creating UUID tree\n");
+               ret = btrfs_create_uuid_tree(fs_info);
+               if (ret) {
+                       pr_warn("btrfs: failed to create the UUID tree %d\n",
+                               ret);
+                       close_ctree(tree_root);
+                       return ret;
+               }
+       }
+
        return 0;
 
 fail_qgroup:
@@ -2983,15 +3027,17 @@ struct buffer_head *btrfs_read_dev_super(struct block_device *bdev)
         */
        for (i = 0; i < 1; i++) {
                bytenr = btrfs_sb_offset(i);
-               if (bytenr + 4096 >= i_size_read(bdev->bd_inode))
+               if (bytenr + BTRFS_SUPER_INFO_SIZE >=
+                                       i_size_read(bdev->bd_inode))
                        break;
-               bh = __bread(bdev, bytenr / 4096, 4096);
+               bh = __bread(bdev, bytenr / 4096,
+                                       BTRFS_SUPER_INFO_SIZE);
                if (!bh)
                        continue;
 
                super = (struct btrfs_super_block *)bh->b_data;
                if (btrfs_super_bytenr(super) != bytenr ||
-                   super->magic != cpu_to_le64(BTRFS_MAGIC)) {
+                   btrfs_super_magic(super) != BTRFS_MAGIC) {
                        brelse(bh);
                        continue;
                }
@@ -3510,6 +3556,11 @@ int close_ctree(struct btrfs_root *root)
        fs_info->closing = 1;
        smp_mb();
 
+       /* wait for the uuid_scan task to finish */
+       down(&fs_info->uuid_tree_rescan_sem);
+       /* avoid complains from lockdep et al., set sem back to initial state */
+       up(&fs_info->uuid_tree_rescan_sem);
+
        /* pause restriper - we want to resume on mount */
        btrfs_pause_balance(fs_info);
 
@@ -3744,8 +3795,8 @@ static void btrfs_destroy_all_ordered_extents(struct btrfs_fs_info *fs_info)
        spin_unlock(&fs_info->ordered_root_lock);
 }
 
-int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
-                              struct btrfs_root *root)
+static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
+                                     struct btrfs_root *root)
 {
        struct rb_node *node;
        struct btrfs_delayed_ref_root *delayed_refs;