Reorder the flags field in struct btrfs_header and record a flag on writeout
authorChris Mason <chris.mason@oracle.com>
Tue, 1 Apr 2008 15:21:32 +0000 (11:21 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:01 +0000 (11:04 -0400)
This allows detection of blocks that have already been written in the
running transaction so they can be recowed instead of modified again.
It is step one in trusting the transid field of the block pointers.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c

index 70b6ddfe15a18d172cb8e6e5a109cc1c550ab314..6ba5394834bef19a172ba7e19776ecc4da42fa78 100644 (file)
@@ -124,6 +124,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
        btrfs_set_header_bytenr(cow, cow->start);
        btrfs_set_header_generation(cow, trans->transid);
        btrfs_set_header_owner(cow, new_root_objectid);
+       btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
 
        WARN_ON(btrfs_header_generation(buf) > trans->transid);
        ret = btrfs_inc_ref(trans, new_root, buf);
@@ -183,6 +184,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
        btrfs_set_header_bytenr(cow, cow->start);
        btrfs_set_header_generation(cow, trans->transid);
        btrfs_set_header_owner(cow, root->root_key.objectid);
+       btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
 
        WARN_ON(btrfs_header_generation(buf) > trans->transid);
        if (btrfs_header_generation(buf) != trans->transid) {
@@ -245,11 +247,14 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
        }
 
        header_trans = btrfs_header_generation(buf);
-       if (header_trans == trans->transid) {
+       spin_lock(&root->fs_info->hash_lock);
+       if (header_trans == trans->transid &&
+           !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
                *cow_ret = buf;
+               spin_unlock(&root->fs_info->hash_lock);
                return 0;
        }
-
+       spin_unlock(&root->fs_info->hash_lock);
        search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1);
        ret = __btrfs_cow_block(trans, root, buf, parent,
                                 parent_slot, cow_ret, search_start, 0);
@@ -1494,6 +1499,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
        btrfs_set_header_bytenr(split, split->start);
        btrfs_set_header_generation(split, trans->transid);
        btrfs_set_header_owner(split, root->root_key.objectid);
+       btrfs_set_header_flags(split, 0);
        write_extent_buffer(split, root->fs_info->fsid,
                            (unsigned long)btrfs_header_fsid(split),
                            BTRFS_FSID_SIZE);
index fec96ba7c23b6fc91459295457e66036096e2947..67d533cf8f47385f2d36f016f8525e3fa6bfb2a6 100644 (file)
@@ -193,6 +193,8 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
 }
 
 #define BTRFS_FSID_SIZE 16
+#define BTRFS_HEADER_FLAG_WRITTEN (1 << 0)
+
 /*
  * every tree block (leaf or node) starts with this header.
  */
@@ -200,10 +202,10 @@ struct btrfs_header {
        u8 csum[BTRFS_CSUM_SIZE];
        u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
        __le64 bytenr; /* which block this node is supposed to live in */
+       __le64 flags;
        __le64 generation;
        __le64 owner;
        __le32 nritems;
-       __le16 flags;
        u8 level;
 } __attribute__ ((__packed__));
 
@@ -229,9 +231,10 @@ struct btrfs_header {
  */
 struct btrfs_super_block {
        u8 csum[BTRFS_CSUM_SIZE];
-       /* the first 3 fields must match struct btrfs_header */
+       /* the first 4 fields must match struct btrfs_header */
        u8 fsid[16];    /* FS specific uuid */
        __le64 bytenr; /* this block number */
+       __le64 flags;
        __le64 magic;
        __le64 generation;
        __le64 root;
@@ -1045,9 +1048,28 @@ BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header,
                          generation, 64);
 BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64);
 BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32);
-BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 16);
+BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64);
 BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8);
 
+static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag)
+{
+       return (btrfs_header_flags(eb) & flag) == flag;
+}
+
+static inline int btrfs_set_header_flag(struct extent_buffer *eb, u64 flag)
+{
+       u64 flags = btrfs_header_flags(eb);
+       btrfs_set_header_flags(eb, flags | flag);
+       return (flags & flag) == flag;
+}
+
+static inline int btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag)
+{
+       u64 flags = btrfs_header_flags(eb);
+       btrfs_set_header_flags(eb, flags & ~flag);
+       return (flags & flag) == flag;
+}
+
 static inline u8 *btrfs_header_fsid(struct extent_buffer *eb)
 {
        unsigned long ptr = offsetof(struct btrfs_header, fsid);
index 1c5e097a4df20250173df2a34ef5e980b95b3da8..709e33d08bb5486fb2a9d5801e9b4bcf5d77a903 100644 (file)
@@ -159,17 +159,19 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
                        from_this_trans = 1;
 
                /* FIXME, this is not good */
-               if (from_this_trans == 0 &&
-                   memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) {
+               if (memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) {
                        u32 val;
                        u32 found = 0;
                        memcpy(&found, result, BTRFS_CRC32_SIZE);
 
                        read_extent_buffer(buf, &val, 0, BTRFS_CRC32_SIZE);
+                       WARN_ON(1);
                        printk("btrfs: %s checksum verify failed on %llu "
-                              "wanted %X found %X from_this_trans %d\n",
+                              "wanted %X found %X from_this_trans %d "
+                              "level %d\n",
                               root->fs_info->sb->s_id,
-                              buf->start, val, found, from_this_trans);
+                              buf->start, val, found, from_this_trans,
+                              btrfs_header_level(buf));
                        return 1;
                }
        } else {
@@ -220,6 +222,9 @@ int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
                goto err;
        }
        found_level = btrfs_header_level(eb);
+       spin_lock(&root->fs_info->hash_lock);
+       btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
+       spin_unlock(&root->fs_info->hash_lock);
        csum_tree_block(root, eb, 0);
 err:
        free_extent_buffer(eb);