Btrfs: Add root tree pointer transaction ids
authorYan Zheng <zheng.yan@oracle.com>
Wed, 29 Oct 2008 18:49:05 +0000 (14:49 -0400)
committerChris Mason <chris.mason@oracle.com>
Wed, 29 Oct 2008 18:49:05 +0000 (14:49 -0400)
This patch adds transaction IDs to root tree pointers.
Transaction IDs in tree pointers are compared with the
generation numbers in block headers when reading root
blocks of trees. This can detect some types of IO errors.

Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/ioctl.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c

index fdba4f1b634ee45231a0f9baf594dbab4a23f208..0621ab90b1a502bc82f829922a75238b598cb292 100644 (file)
@@ -297,6 +297,7 @@ struct btrfs_super_block {
        __le32 leafsize;
        __le32 stripesize;
        __le32 sys_chunk_array_size;
+       __le64 chunk_root_generation;
        u8 root_level;
        u8 chunk_root_level;
        u8 log_root_level;
@@ -448,6 +449,7 @@ struct btrfs_dir_item {
 
 struct btrfs_root_item {
        struct btrfs_inode_item inode;
+       __le64 generation;
        __le64 root_dirid;
        __le64 bytenr;
        __le64 byte_limit;
@@ -1396,10 +1398,14 @@ static inline int btrfs_is_leaf(struct extent_buffer *eb)
 }
 
 /* struct btrfs_root_item */
+BTRFS_SETGET_FUNCS(disk_root_generation, struct btrfs_root_item,
+                  generation, 64);
 BTRFS_SETGET_FUNCS(disk_root_refs, struct btrfs_root_item, refs, 32);
 BTRFS_SETGET_FUNCS(disk_root_bytenr, struct btrfs_root_item, bytenr, 64);
 BTRFS_SETGET_FUNCS(disk_root_level, struct btrfs_root_item, level, 8);
 
+BTRFS_SETGET_STACK_FUNCS(root_generation, struct btrfs_root_item,
+                        generation, 64);
 BTRFS_SETGET_STACK_FUNCS(root_bytenr, struct btrfs_root_item, bytenr, 64);
 BTRFS_SETGET_STACK_FUNCS(root_level, struct btrfs_root_item, level, 8);
 BTRFS_SETGET_STACK_FUNCS(root_dirid, struct btrfs_root_item, root_dirid, 64);
@@ -1416,6 +1422,8 @@ BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,
 BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64);
 BTRFS_SETGET_STACK_FUNCS(super_sys_array_size,
                         struct btrfs_super_block, sys_chunk_array_size, 32);
+BTRFS_SETGET_STACK_FUNCS(super_chunk_root_generation,
+                        struct btrfs_super_block, chunk_root_generation, 64);
 BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block,
                         root_level, 8);
 BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block,
index d1137d7ea8d4d73a3e6c7b210d3781f818187925..94b4e50f6b2cbadf1726f2856dab15678c6f0a5e 100644 (file)
@@ -832,6 +832,7 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
 {
        int ret;
        u32 blocksize;
+       u64 generation;
 
        __setup_root(tree_root->nodesize, tree_root->leafsize,
                     tree_root->sectorsize, tree_root->stripesize,
@@ -840,9 +841,10 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
                                   &root->root_item, &root->root_key);
        BUG_ON(ret);
 
+       generation = btrfs_root_generation(&root->root_item);
        blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
        root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
-                                    blocksize, 0);
+                                    blocksize, generation);
        BUG_ON(!root->node);
        return 0;
 }
@@ -929,6 +931,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
        struct btrfs_path *path;
        struct extent_buffer *l;
        u64 highest_inode;
+       u64 generation;
        u32 blocksize;
        int ret = 0;
 
@@ -970,9 +973,10 @@ out:
                kfree(root);
                return ERR_PTR(ret);
        }
+       generation = btrfs_root_generation(&root->root_item);
        blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
        root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
-                                    blocksize, 0);
+                                    blocksize, generation);
        BUG_ON(!root->node);
 insert:
        if (location->objectid != BTRFS_TREE_LOG_OBJECTID) {
@@ -1357,6 +1361,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        u32 leafsize;
        u32 blocksize;
        u32 stripesize;
+       u64 generation;
        struct buffer_head *bh;
        struct btrfs_root *extent_root = kzalloc(sizeof(struct btrfs_root),
                                                 GFP_NOFS);
@@ -1596,13 +1601,14 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
        blocksize = btrfs_level_size(tree_root,
                                     btrfs_super_chunk_root_level(disk_super));
+       generation = btrfs_super_chunk_root_generation(disk_super);
 
        __setup_root(nodesize, leafsize, sectorsize, stripesize,
                     chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID);
 
        chunk_root->node = read_tree_block(chunk_root,
                                           btrfs_super_chunk_root(disk_super),
-                                          blocksize, 0);
+                                          blocksize, generation);
        BUG_ON(!chunk_root->node);
 
        read_extent_buffer(chunk_root->node, fs_info->chunk_tree_uuid,
@@ -1618,11 +1624,11 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
        blocksize = btrfs_level_size(tree_root,
                                     btrfs_super_root_level(disk_super));
-
+       generation = btrfs_super_generation(disk_super);
 
        tree_root->node = read_tree_block(tree_root,
                                          btrfs_super_root(disk_super),
-                                         blocksize, 0);
+                                         blocksize, generation);
        if (!tree_root->node)
                goto fail_sb_buffer;
 
@@ -1672,15 +1678,16 @@ struct btrfs_root *open_ctree(struct super_block *sb,
                             log_tree_root, fs_info, BTRFS_TREE_LOG_OBJECTID);
 
                log_tree_root->node = read_tree_block(tree_root, bytenr,
-                                                     blocksize, 0);
+                                                     blocksize,
+                                                     generation + 1);
                ret = btrfs_recover_log_trees(log_tree_root);
                BUG_ON(ret);
        }
+       fs_info->last_trans_committed = btrfs_super_generation(disk_super);
 
        ret = btrfs_cleanup_reloc_trees(tree_root);
        BUG_ON(ret);
 
-       fs_info->last_trans_committed = btrfs_super_generation(disk_super);
        return tree_root;
 
 fail_cleaner:
index 564260872c7eb35af4670c3a71435b84d82fbd1b..155c8dc56a2253f26c857995a6649c75602a68ad 100644 (file)
@@ -4428,6 +4428,7 @@ static int noinline init_reloc_tree(struct btrfs_trans_handle *trans,
        btrfs_set_root_refs(root_item, 0);
        btrfs_set_root_bytenr(root_item, eb->start);
        btrfs_set_root_level(root_item, btrfs_header_level(eb));
+       btrfs_set_root_generation(root_item, trans->transid);
 
        btrfs_tree_unlock(eb);
        free_extent_buffer(eb);
index 1136ce2febcc150e9895e7815cec20573a221653..fd3c8b5676c13ba1114a38ab5125208fc7022b0d 100644 (file)
@@ -108,6 +108,7 @@ static noinline int create_subvol(struct btrfs_root *root,
        inode_item->mode = cpu_to_le32(S_IFDIR | 0755);
 
        btrfs_set_root_bytenr(&root_item, leaf->start);
+       btrfs_set_root_generation(&root_item, trans->transid);
        btrfs_set_root_level(&root_item, 0);
        btrfs_set_root_refs(&root_item, 1);
        btrfs_set_root_used(&root_item, 0);
index 48b455fdaac5e08305ec82605da6f644d69362a5..924af6f2aeac719688c118aac33620d5be607c09 100644 (file)
@@ -439,6 +439,7 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
                                       root->node->start);
                btrfs_set_root_level(&root->root_item,
                                     btrfs_header_level(root->node));
+               btrfs_set_root_generation(&root->root_item, trans->transid);
                ret = btrfs_update_root(trans, tree_root,
                                        &root->root_key,
                                        &root->root_item);
@@ -456,6 +457,12 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct list_head *next;
+       struct extent_buffer *eb;
+
+       eb = btrfs_lock_root_node(fs_info->tree_root);
+       btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb, 0);
+       btrfs_tree_unlock(eb);
+       free_extent_buffer(eb);
 
        while(!list_empty(&fs_info->dirty_cowonly_roots)) {
                next = fs_info->dirty_cowonly_roots.next;
@@ -559,6 +566,9 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
                                              root->node->start);
                        btrfs_set_root_level(&root->root_item,
                                             btrfs_header_level(root->node));
+                       btrfs_set_root_generation(&root->root_item,
+                                                 root->root_key.offset);
+
                        err = btrfs_insert_root(trans, root->fs_info->tree_root,
                                                &root->root_key,
                                                &root->root_item);
@@ -756,6 +766,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
 
        btrfs_set_root_bytenr(new_root_item, tmp->start);
        btrfs_set_root_level(new_root_item, btrfs_header_level(tmp));
+       btrfs_set_root_generation(new_root_item, trans->transid);
        ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
                                new_root_item);
        btrfs_tree_unlock(tmp);
@@ -946,6 +957,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                                   chunk_root->node->start);
        btrfs_set_super_chunk_root_level(&root->fs_info->super_copy,
                                         btrfs_header_level(chunk_root->node));
+       btrfs_set_super_chunk_root_generation(&root->fs_info->super_copy,
+                               btrfs_header_generation(chunk_root->node));
 
        if (!root->fs_info->log_root_recovering) {
                btrfs_set_super_log_root(&root->fs_info->super_copy, 0);
index 835daed5561f5c96b8f9cb244c20f1975ff3f73b..e0201c3a7dc9d8bff6b56e199017a82a881ed506 100644 (file)
@@ -117,6 +117,7 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
        inode_item->mode = cpu_to_le32(S_IFDIR | 0755);
 
        btrfs_set_root_bytenr(&root_item, leaf->start);
+       btrfs_set_root_generation(&root_item, trans->transid);
        btrfs_set_root_level(&root_item, 0);
        btrfs_set_root_refs(&root_item, 0);
        btrfs_set_root_used(&root_item, 0);
@@ -2065,6 +2066,7 @@ static int update_log_root(struct btrfs_trans_handle *trans,
                return 0;
 
        btrfs_set_root_bytenr(&log->root_item, log->node->start);
+       btrfs_set_root_generation(&log->root_item, trans->transid);
        btrfs_set_root_level(&log->root_item, btrfs_header_level(log->node));
        ret = btrfs_update_root(trans, log->fs_info->log_root_tree,
                                &log->root_key, &log->root_item);