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,
struct extent_buffer *cur;
struct extent_buffer *tmp;
u64 blocknr;
+ u64 gen;
u64 search_start = *last_ret;
u64 last_block = 0;
u64 other;
progress_passed = 1;
blocknr = btrfs_node_blockptr(parent, i);
+ gen = btrfs_node_ptr_generation(parent, i);
if (last_block == 0)
last_block = blocknr;
}
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,
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,
/* 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)
* 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) {
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) {
wret = 1;
else {
wret = push_node_left(trans, root,
- left, mid);
+ left, mid, 0);
}
}
if (wret < 0)
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++;
ins_len, int cow)
{
struct extent_buffer *b;
- u64 bytenr;
- u64 ptr_gen;
int slot;
int ret;
int level;
/* 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) <
*/
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;
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),
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;
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;
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);
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);
*/
int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
{
- u64 bytenr;
int slot;
int level = 1;
struct extent_buffer *c;
}
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;
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;
}
{
int slot;
int level = 1;
- u64 bytenr;
struct extent_buffer *c;
struct extent_buffer *next = NULL;
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;
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;
}