Btrfs: Pass down the expected generation number when reading tree blocks
[deliverable/linux.git] / fs / btrfs / ctree.c
index 8ad8b5cc295ac3eb6144789161b95d56dae43aa6..289d71d8653a9caf19a51fbe0e51b07a2033efcb 100644 (file)
@@ -29,7 +29,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
                      struct btrfs_path *path, int data_size, int extend);
 static int push_node_left(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, struct extent_buffer *dst,
-                         struct extent_buffer *src);
+                         struct extent_buffer *src, int empty);
 static int balance_node_right(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root,
                              struct extent_buffer *dst_buf,
@@ -302,6 +302,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
        struct extent_buffer *cur;
        struct extent_buffer *tmp;
        u64 blocknr;
+       u64 gen;
        u64 search_start = *last_ret;
        u64 last_block = 0;
        u64 other;
@@ -354,6 +355,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 
                progress_passed = 1;
                blocknr = btrfs_node_blockptr(parent, i);
+               gen = btrfs_node_ptr_generation(parent, i);
                if (last_block == 0)
                        last_block = blocknr;
 
@@ -387,15 +389,14 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                        }
                        if (!cur) {
                                cur = read_tree_block(root, blocknr,
-                                                        blocksize);
+                                                        blocksize, gen);
                        } else if (!uptodate) {
-                               btrfs_read_buffer(cur);
+                               btrfs_read_buffer(cur, gen);
                        }
                }
                if (search_start == 0)
                        search_start = last_block;
 
-               btrfs_verify_block_csum(root, cur);
                err = __btrfs_cow_block(trans, root, cur, parent, i,
                                        &tmp, search_start,
                                        min(16 * blocksize,
@@ -696,12 +697,17 @@ static int bin_search(struct extent_buffer *eb, struct btrfs_key *key,
 static struct extent_buffer *read_node_slot(struct btrfs_root *root,
                                   struct extent_buffer *parent, int slot)
 {
+       int level = btrfs_header_level(parent);
        if (slot < 0)
                return NULL;
        if (slot >= btrfs_header_nritems(parent))
                return NULL;
+
+       BUG_ON(level == 0);
+
        return read_tree_block(root, btrfs_node_blockptr(parent, slot),
-                      btrfs_level_size(root, btrfs_header_level(parent) - 1));
+                      btrfs_level_size(root, level - 1),
+                      btrfs_node_ptr_generation(parent, slot));
 }
 
 static int balance_level(struct btrfs_trans_handle *trans,
@@ -789,7 +795,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
        /* first, try to make some room in the middle buffer */
        if (left) {
                orig_slot += btrfs_header_nritems(left);
-               wret = push_node_left(trans, root, left, mid);
+               wret = push_node_left(trans, root, left, mid, 1);
                if (wret < 0)
                        ret = wret;
                if (btrfs_header_nritems(mid) < 2)
@@ -800,7 +806,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
         * then try to empty the right most buffer into the middle
         */
        if (right) {
-               wret = push_node_left(trans, root, mid, right);
+               wret = push_node_left(trans, root, mid, right, 1);
                if (wret < 0 && wret != -ENOSPC)
                        ret = wret;
                if (btrfs_header_nritems(right) == 0) {
@@ -844,6 +850,11 @@ static int balance_level(struct btrfs_trans_handle *trans,
                        ret = wret;
                        goto enospc;
                }
+               if (wret == 1) {
+                       wret = push_node_left(trans, root, left, mid, 1);
+                       if (wret < 0)
+                               ret = wret;
+               }
                BUG_ON(wret == 1);
        }
        if (btrfs_header_nritems(mid) == 0) {
@@ -941,7 +952,7 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
                                wret = 1;
                        else {
                                wret = push_node_left(trans, root,
-                                                     left, mid);
+                                                     left, mid, 0);
                        }
                }
                if (wret < 0)
@@ -1071,7 +1082,8 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
                if ((search >= lowest_read && search <= highest_read) ||
                    (search < lowest_read && lowest_read - search <= 32768) ||
                    (search > highest_read && search - highest_read <= 32768)) {
-                       readahead_tree_block(root, search, blocksize);
+                       readahead_tree_block(root, search, blocksize,
+                                    btrfs_node_ptr_generation(node, nr));
                        nread += blocksize;
                }
                nscan++;
@@ -1104,8 +1116,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
                      ins_len, int cow)
 {
        struct extent_buffer *b;
-       u64 bytenr;
-       u64 ptr_gen;
        int slot;
        int ret;
        int level;
@@ -1169,20 +1179,12 @@ again:
                        /* this is only true while dropping a snapshot */
                        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,
                                                 key->objectid);
-                       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));
-                       }
+
+                       b = read_node_slot(root, b, slot);
                } else {
                        p->slots[level] = slot;
                        if (ins_len > 0 && btrfs_leaf_free_space(root, b) <
@@ -1239,7 +1241,7 @@ static int fixup_low_keys(struct btrfs_trans_handle *trans,
  */
 static int push_node_left(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, struct extent_buffer *dst,
-                         struct extent_buffer *src)
+                         struct extent_buffer *src, int empty)
 {
        int push_items = 0;
        int src_nritems;
@@ -1252,12 +1254,27 @@ static int push_node_left(struct btrfs_trans_handle *trans,
        WARN_ON(btrfs_header_generation(src) != trans->transid);
        WARN_ON(btrfs_header_generation(dst) != trans->transid);
 
+       if (!empty && src_nritems <= 8)
+               return 1;
+
        if (push_items <= 0) {
                return 1;
        }
 
-       if (src_nritems < push_items)
-               push_items = src_nritems;
+       if (empty) {
+               push_items = min(src_nritems, push_items);
+               if (push_items < src_nritems) {
+                       /* leave at least 8 pointers in the node if
+                        * we aren't going to empty it
+                        */
+                       if (src_nritems - push_items < 8) {
+                               if (push_items <= 8)
+                                       return 1;
+                               push_items -= 8;
+                       }
+               }
+       } else
+               push_items = min(src_nritems - 8, push_items);
 
        copy_extent_buffer(dst, src,
                           btrfs_node_key_ptr_offset(dst_nritems),
@@ -1303,13 +1320,19 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
        src_nritems = btrfs_header_nritems(src);
        dst_nritems = btrfs_header_nritems(dst);
        push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems;
-       if (push_items <= 0)
+       if (push_items <= 0) {
                return 1;
+       }
+
+       if (src_nritems < 4) {
+               return 1;
+       }
 
        max_push = src_nritems / 2 + 1;
        /* don't try to empty the node */
-       if (max_push >= src_nritems)
+       if (max_push >= src_nritems) {
                return 1;
+       }
 
        if (max_push < push_items)
                push_items = max_push;
@@ -1485,7 +1508,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
                ret = push_nodes_for_insert(trans, root, path, level);
                c = path->nodes[level];
                if (!ret && btrfs_header_nritems(c) <
-                   BTRFS_NODEPTRS_PER_BLOCK(root) - 1)
+                   BTRFS_NODEPTRS_PER_BLOCK(root) - 3)
                        return 0;
                if (ret < 0)
                        return ret;
@@ -1624,8 +1647,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
        if (slot >= btrfs_header_nritems(upper) - 1)
                return 1;
 
-       right = read_tree_block(root, btrfs_node_blockptr(upper, slot + 1),
-                               root->leafsize);
+       right = read_node_slot(root, upper, slot + 1);
        free_space = btrfs_leaf_free_space(root, right);
        if (free_space < data_size + sizeof(struct btrfs_item)) {
                free_extent_buffer(right);
@@ -1800,8 +1822,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
                return 1;
        }
 
-       left = read_tree_block(root, btrfs_node_blockptr(path->nodes[1],
-                              slot - 1), root->leafsize);
+       left = read_node_slot(root, path->nodes[1], slot - 1);
        free_space = btrfs_leaf_free_space(root, left);
        if (free_space < data_size + sizeof(struct btrfs_item)) {
                free_extent_buffer(left);
@@ -2716,7 +2737,6 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
  */
 int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
 {
-       u64 bytenr;
        int slot;
        int level = 1;
        struct extent_buffer *c;
@@ -2736,12 +2756,10 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
                }
                slot--;
 
-               bytenr = btrfs_node_blockptr(c, slot);
                if (next)
                        free_extent_buffer(next);
 
-               next = read_tree_block(root, bytenr,
-                                      btrfs_level_size(root, level - 1));
+               next = read_node_slot(root, c, slot);
                break;
        }
        path->slots[level] = slot;
@@ -2756,8 +2774,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
                path->slots[level] = slot;
                if (!level)
                        break;
-               next = read_tree_block(root, btrfs_node_blockptr(next, slot),
-                                      btrfs_level_size(root, level - 1));
+               next = read_node_slot(root, next, slot);
        }
        return 0;
 }
@@ -2771,7 +2788,6 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
 {
        int slot;
        int level = 1;
-       u64 bytenr;
        struct extent_buffer *c;
        struct extent_buffer *next = NULL;
 
@@ -2788,15 +2804,13 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
                        continue;
                }
 
-               bytenr = btrfs_node_blockptr(c, slot);
                if (next)
                        free_extent_buffer(next);
 
                if (path->reada)
                        reada_for_search(root, path, level, slot, 0);
 
-               next = read_tree_block(root, bytenr,
-                                      btrfs_level_size(root, level -1));
+               next = read_node_slot(root, c, slot);
                break;
        }
        path->slots[level] = slot;
@@ -2810,8 +2824,7 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
                        break;
                if (path->reada)
                        reada_for_search(root, path, level, 0, 0);
-               next = read_tree_block(root, btrfs_node_blockptr(next, 0),
-                                      btrfs_level_size(root, level - 1));
+               next = read_node_slot(root, next, 0);
        }
        return 0;
 }
This page took 0.050862 seconds and 5 git commands to generate.