]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Btrfs: Implement generation numbers in block pointers
authorChris Mason <chris.mason@oracle.com>
Tue, 11 Dec 2007 14:25:06 +0000 (09:25 -0500)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:03:58 +0000 (11:03 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/extent-tree.c

index 3b16051b121bfcfaa20e62999ab6f1f2d5246a8e..5697705f7530d2eb2360e718eba9b8a92908fc81 100644 (file)
@@ -114,6 +114,9 @@ static int __btrfs_cow_block(struct btrfs_trans_handle *trans,
        } else {
                btrfs_set_node_blockptr(parent, parent_slot,
                                        cow->start);
+               WARN_ON(trans->transid == 0);
+               btrfs_set_node_ptr_generation(parent, parent_slot,
+                                             trans->transid);
                btrfs_mark_buffer_dirty(parent);
                WARN_ON(btrfs_header_generation(parent) != trans->transid);
                btrfs_free_extent(trans, root, buf->start, buf->len, 1);
@@ -967,6 +970,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
 {
        struct extent_buffer *b;
        u64 bytenr;
+       u64 ptr_gen;
        int slot;
        int ret;
        int level;
@@ -1031,10 +1035,18 @@ again:
                        if (level == lowest_level)
                                break;
                        bytenr = btrfs_node_blockptr(b, slot);
+                       ptr_gen = btrfs_node_ptr_generation(b, slot);
                        if (should_reada)
                                reada_for_search(root, p, level, slot);
                        b = read_tree_block(root, bytenr,
                                            btrfs_level_size(root, level - 1));
+                       if (ptr_gen != btrfs_header_generation(b)) {
+                               printk("block %llu bad gen wanted %llu "
+                                      "found %llu\n",
+                               (unsigned long long)b->start,
+                               (unsigned long long)ptr_gen,
+                               (unsigned long long)btrfs_header_generation(b));
+                       }
                } else {
                        p->slots[level] = slot;
                        if (ins_len > 0 && btrfs_leaf_free_space(root, b) <
@@ -1218,6 +1230,8 @@ static int insert_new_root(struct btrfs_trans_handle *trans,
                btrfs_node_key(lower, &lower_key, 0);
        btrfs_set_node_key(c, &lower_key, 0);
        btrfs_set_node_blockptr(c, 0, lower->start);
+       WARN_ON(btrfs_header_generation(lower) == 0);
+       btrfs_set_node_ptr_generation(c, 0, btrfs_header_generation(lower));
 
        btrfs_mark_buffer_dirty(c);
 
@@ -1261,6 +1275,8 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
        }
        btrfs_set_node_key(lower, key, slot);
        btrfs_set_node_blockptr(lower, slot, bytenr);
+       WARN_ON(trans->transid == 0);
+       btrfs_set_node_ptr_generation(lower, slot, trans->transid);
        btrfs_set_header_nritems(lower, nritems + 1);
        btrfs_mark_buffer_dirty(lower);
        return 0;
index 9bc1b0a8615fb9590de894bdbb62ade7ff8c416e..fd58dd846e61ec66260e274231d1f831f8dd5975 100644 (file)
@@ -110,7 +110,7 @@ struct btrfs_header {
 #define BTRFS_MAX_LEVEL 8
 #define BTRFS_NODEPTRS_PER_BLOCK(r) (((r)->nodesize - \
                                sizeof(struct btrfs_header)) / \
-                              (sizeof(struct btrfs_disk_key) + sizeof(u64)))
+                               sizeof(struct btrfs_key_ptr))
 #define __BTRFS_LEAF_DATA_SIZE(bs) ((bs) - sizeof(struct btrfs_header))
 #define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->leafsize))
 #define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
@@ -168,6 +168,7 @@ struct btrfs_leaf {
 struct btrfs_key_ptr {
        struct btrfs_disk_key key;
        __le64 blockptr;
+       __le64 generation;
 } __attribute__ ((__packed__));
 
 struct btrfs_node {
@@ -196,7 +197,13 @@ struct btrfs_path {
  */
 struct btrfs_extent_item {
        __le32 refs;
-       __le64 owner;
+} __attribute__ ((__packed__));
+
+struct btrfs_extent_ref {
+       __le64 root;
+       __le64 generation;
+       __le64 objectid;
+       __le64 offset;
 } __attribute__ ((__packed__));
 
 struct btrfs_inode_timespec {
@@ -402,12 +409,13 @@ struct btrfs_root {
  * are used, and how many references there are to each block
  */
 #define BTRFS_EXTENT_ITEM_KEY  33
+#define BTRFS_EXTENT_REF_KEY   34
 
 /*
  * block groups give us hints into the extent allocation trees.  Which
  * blocks are free etc etc
  */
-#define BTRFS_BLOCK_GROUP_ITEM_KEY 34
+#define BTRFS_BLOCK_GROUP_ITEM_KEY 50
 
 /*
  * string items are for debugging.  They just store a short string of
@@ -529,15 +537,25 @@ BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_inode_timespec, nsec, 32);
 
 /* struct btrfs_extent_item */
 BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32);
-BTRFS_SETGET_FUNCS(extent_owner, struct btrfs_extent_item, owner, 64);
+
+/* struct btrfs_extent_ref */
+BTRFS_SETGET_FUNCS(ref_root, struct btrfs_extent_ref, root, 64);
+BTRFS_SETGET_FUNCS(ref_generation, struct btrfs_extent_ref, generation, 64);
+BTRFS_SETGET_FUNCS(ref_objectid, struct btrfs_extent_ref, objectid, 64);
+BTRFS_SETGET_FUNCS(ref_offset, struct btrfs_extent_ref, offset, 64);
+
+BTRFS_SETGET_STACK_FUNCS(ref_root, struct btrfs_extent_ref, root, 64);
+BTRFS_SETGET_STACK_FUNCS(ref_generation, struct btrfs_extent_ref,
+                        generation, 64);
+BTRFS_SETGET_STACK_FUNCS(ref_objectid, struct btrfs_extent_ref, objectid, 64);
+BTRFS_SETGET_STACK_FUNCS(ref_offset, struct btrfs_extent_ref, offset, 64);
 
 BTRFS_SETGET_STACK_FUNCS(stack_extent_refs, struct btrfs_extent_item,
                         refs, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_extent_owner, struct btrfs_extent_item,
-                        owner, 64);
 
 /* struct btrfs_node */
 BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64);
+BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64);
 
 static inline u64 btrfs_node_blockptr(struct extent_buffer *eb, int nr)
 {
@@ -556,6 +574,23 @@ static inline void btrfs_set_node_blockptr(struct extent_buffer *eb,
        btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val);
 }
 
+static inline u64 btrfs_node_ptr_generation(struct extent_buffer *eb, int nr)
+{
+       unsigned long ptr;
+       ptr = offsetof(struct btrfs_node, ptrs) +
+               sizeof(struct btrfs_key_ptr) * nr;
+       return btrfs_key_generation(eb, (struct btrfs_key_ptr *)ptr);
+}
+
+static inline void btrfs_set_node_ptr_generation(struct extent_buffer *eb,
+                                                int nr, u64 val)
+{
+       unsigned long ptr;
+       ptr = offsetof(struct btrfs_node, ptrs) +
+               sizeof(struct btrfs_key_ptr) * nr;
+       btrfs_set_key_generation(eb, (struct btrfs_key_ptr *)ptr, val);
+}
+
 static inline unsigned long btrfs_node_key_ptr_offset(int nr)
 {
        return offsetof(struct btrfs_node, ptrs) +
index 8ab4954f6ad0b73f7278f21194ce2da8325cd865..0f1ebdd4e925a28dd1ab69d0772962c78ecd26d7 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/sched.h>
+#include "hash.h"
 #include "ctree.h"
 #include "disk-io.h"
 #include "print-tree.h"
@@ -352,9 +353,63 @@ found:
        return found_group;
 }
 
+static u64 hash_extent_ref(u64 root_objectid, u64 root_generation,
+                          u64 owner, u64 owner_offset)
+{
+       u32 high_crc = ~(u32)0;
+       u32 low_crc = ~(u32)0;
+       __le64 lenum;
+
+       lenum = cpu_to_le64(root_objectid);
+       high_crc = crc32c(high_crc, &lenum, sizeof(lenum));
+       lenum = cpu_to_le64(root_generation);
+       high_crc = crc32c(high_crc, &lenum, sizeof(lenum));
+
+       lenum = cpu_to_le64(owner);
+       low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
+
+       lenum = cpu_to_le64(owner_offset);
+       low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
+
+       return ((u64)high_crc << 32) | (u64)low_crc;
+}
+
+int insert_extent_ref(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               struct btrfs_path *path,
+                               u64 bytenr,
+                               u64 root_objectid, u64 root_generation,
+                               u64 owner, u64 owner_offset)
+{
+       u64 hash;
+       struct btrfs_key key;
+       struct btrfs_extent_ref ref;
+       struct extent_buffer *l;
+       struct btrfs_extent_item *item;
+       int ret;
+
+       btrfs_set_stack_ref_root(&ref, root_objectid);
+       btrfs_set_stack_ref_generation(&ref, root_generation);
+       btrfs_set_stack_ref_objectid(&ref, owner);
+       btrfs_set_stack_ref_offset(&ref, owner_offset);
+
+       ret = btrfs_name_hash(&ref, sizeof(ref), &hash);
+       key.offset = hash;
+       key.objectid = bytenr;
+       key.type = BTRFS_EXTENT_REF_KEY;
+
+       ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(ref));
+       while (ret == -EEXIST) {
+
+       }
+
+}
+
 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
-                               u64 bytenr, u64 num_bytes)
+                               u64 bytenr, u64 num_bytes,
+                               u64 root_objectid, u64 root_generation,
+                               u64 owner, u64 owner_offset)
 {
        struct btrfs_path *path;
        int ret;
@@ -386,9 +441,10 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(path->nodes[0]);
 
        btrfs_release_path(root->fs_info->extent_root, path);
-       btrfs_free_path(path);
        finish_current_insert(trans, root->fs_info->extent_root);
        del_pending_extents(trans, root->fs_info->extent_root);
+
+       btrfs_free_path(path);
        return 0;
 }