#include "repair.h"
#include "internal.h"
#include "sizes.h"
+#include "messages.h"
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, int level);
* this returns the address of the start of the last item,
* which is the stop of the leaf data stack
*/
-static inline unsigned int leaf_data_end(struct btrfs_root *root,
- struct extent_buffer *leaf)
+static inline unsigned int leaf_data_end(const struct btrfs_fs_info *fs_info,
+ const struct extent_buffer *leaf)
{
u32 nr = btrfs_header_nritems(leaf);
if (nr == 0)
- return BTRFS_LEAF_DATA_SIZE(root->fs_info);
+ return BTRFS_LEAF_DATA_SIZE(fs_info);
return btrfs_item_offset_nr(leaf, nr - 1);
}
(unsigned long long)btrfs_header_bytenr(buf));
goto fail;
}
- if (btrfs_leaf_free_space(root, buf) < 0) {
+ if (btrfs_leaf_free_space(root->fs_info, buf) < 0) {
ret = BTRFS_TREE_BLOCK_INVALID_FREE_SPACE;
fprintf(stderr, "leaf free space incorrect %llu %d\n",
(unsigned long long)btrfs_header_bytenr(buf),
- btrfs_leaf_free_space(root, buf));
+ btrfs_leaf_free_space(root->fs_info, buf));
goto fail;
}
struct extent_buffer *read_node_slot(struct btrfs_fs_info *fs_info,
struct extent_buffer *parent, int slot)
{
+ struct extent_buffer *ret;
int level = btrfs_header_level(parent);
+
if (slot < 0)
return NULL;
if (slot >= btrfs_header_nritems(parent))
if (level == 0)
return NULL;
- return read_tree_block(fs_info, btrfs_node_blockptr(parent, slot),
+ ret = read_tree_block(fs_info, btrfs_node_blockptr(parent, slot),
btrfs_node_ptr_generation(parent, slot));
+ if (!extent_buffer_uptodate(ret))
+ return ERR_PTR(-EIO);
+
+ if (btrfs_header_level(ret) != level - 1) {
+ error(
+"child eb corrupted: parent bytenr=%llu item=%d parent level=%d child level=%d",
+ btrfs_header_bytenr(parent), slot,
+ btrfs_header_level(parent), btrfs_header_level(ret));
+ free_extent_buffer(ret);
+ return ERR_PTR(-EIO);
+ }
+ return ret;
}
static int balance_level(struct btrfs_trans_handle *trans,
} else {
p->slots[level] = slot;
if (ins_len > 0 &&
- ins_len > btrfs_leaf_free_space(root, b)) {
+ ins_len > btrfs_leaf_free_space(root->fs_info, b)) {
int sret = split_leaf(trans, root, key,
p, ins_len, ret == 0);
BUG_ON(sret > 0);
* the start of the leaf data. IOW, how much room
* the leaf has left for both items and data
*/
-int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf)
+int btrfs_leaf_free_space(struct btrfs_fs_info *fs_info,
+ struct extent_buffer *leaf)
{
- u32 nodesize = (root ? BTRFS_LEAF_DATA_SIZE(root->fs_info) : leaf->len);
int nritems = btrfs_header_nritems(leaf);
int ret;
- ret = nodesize - leaf_space_used(leaf, 0, nritems);
+
+ ret = BTRFS_LEAF_DATA_SIZE(fs_info) - leaf_space_used(leaf, 0, nritems);
if (ret < 0) {
- printk("leaf free space ret %d, leaf data size %u, used %d nritems %d\n",
- ret, nodesize, leaf_space_used(leaf, 0, nritems),
- nritems);
+ printk("leaf free space ret %d, leaf data size %lu, used %d nritems %d\n",
+ ret, BTRFS_LEAF_DATA_SIZE(fs_info),
+ leaf_space_used(leaf, 0, nritems), nritems);
}
return ret;
}
return PTR_ERR(right);
return -EIO;
}
- free_space = btrfs_leaf_free_space(root, right);
+ free_space = btrfs_leaf_free_space(fs_info, right);
if (free_space < data_size) {
free_extent_buffer(right);
return 1;
free_extent_buffer(right);
return 1;
}
- free_space = btrfs_leaf_free_space(root, right);
+ free_space = btrfs_leaf_free_space(fs_info, right);
if (free_space < data_size) {
free_extent_buffer(right);
return 1;
right_nritems = btrfs_header_nritems(right);
push_space = btrfs_item_end_nr(left, left_nritems - push_items);
- push_space -= leaf_data_end(root, left);
+ push_space -= leaf_data_end(fs_info, left);
/* make room in the right data area */
- data_end = leaf_data_end(root, right);
+ data_end = leaf_data_end(fs_info, right);
memmove_extent_buffer(right,
btrfs_leaf_data(right) + data_end - push_space,
btrfs_leaf_data(right) + data_end,
/* copy from the left data area */
copy_extent_buffer(right, left, btrfs_leaf_data(right) +
BTRFS_LEAF_DATA_SIZE(root->fs_info) - push_space,
- btrfs_leaf_data(left) + leaf_data_end(root, left),
+ btrfs_leaf_data(left) + leaf_data_end(fs_info, left),
push_space);
memmove_extent_buffer(right, btrfs_item_nr_offset(push_items),
}
left = read_node_slot(fs_info, path->nodes[1], slot - 1);
- free_space = btrfs_leaf_free_space(root, left);
+ free_space = btrfs_leaf_free_space(fs_info, left);
if (free_space < data_size) {
free_extent_buffer(left);
return 1;
return 1;
}
- free_space = btrfs_leaf_free_space(root, left);
+ free_space = btrfs_leaf_free_space(fs_info, left);
if (free_space < data_size) {
free_extent_buffer(left);
return 1;
btrfs_item_offset_nr(right, push_items -1);
copy_extent_buffer(left, right, btrfs_leaf_data(left) +
- leaf_data_end(root, left) - push_space,
+ leaf_data_end(fs_info, left) - push_space,
btrfs_leaf_data(right) +
btrfs_item_offset_nr(right, push_items - 1),
push_space);
if (push_items < right_nritems) {
push_space = btrfs_item_offset_nr(right, push_items - 1) -
- leaf_data_end(root, right);
+ leaf_data_end(fs_info, right);
memmove_extent_buffer(right, btrfs_leaf_data(right) +
BTRFS_LEAF_DATA_SIZE(root->fs_info) -
push_space,
btrfs_leaf_data(right) +
- leaf_data_end(root, right), push_space);
+ leaf_data_end(fs_info, right),
+ push_space);
memmove_extent_buffer(right, btrfs_item_nr_offset(0),
btrfs_item_nr_offset(push_items),
nritems = nritems - mid;
btrfs_set_header_nritems(right, nritems);
- data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l);
+ data_copy_size = btrfs_item_end_nr(l, mid) -
+ leaf_data_end(root->fs_info, l);
copy_extent_buffer(right, l, btrfs_item_nr_offset(0),
btrfs_item_nr_offset(mid),
btrfs_leaf_data(right) +
BTRFS_LEAF_DATA_SIZE(root->fs_info) -
data_copy_size, btrfs_leaf_data(l) +
- leaf_data_end(root, l), data_copy_size);
+ leaf_data_end(root->fs_info, l), data_copy_size);
rt_data_off = BTRFS_LEAF_DATA_SIZE(root->fs_info) -
btrfs_item_end_nr(l, mid);
l = path->nodes[0];
/* did the pushes work? */
- if (btrfs_leaf_free_space(root, l) >= data_size)
+ if (btrfs_leaf_free_space(root->fs_info, l) >= data_size)
return 0;
}
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]);
- if (btrfs_leaf_free_space(root, leaf) >= sizeof(struct btrfs_item))
+ if (btrfs_leaf_free_space(root->fs_info, leaf) >=
+ sizeof(struct btrfs_item))
goto split;
item_size = btrfs_item_size_nr(leaf, path->slots[0]);
ret = split_leaf(trans, root, &orig_key, path, 0, 0);
BUG_ON(ret);
- BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item));
+ BUG_ON(btrfs_leaf_free_space(root->fs_info, leaf) <
+ sizeof(struct btrfs_item));
leaf = path->nodes[0];
split:
btrfs_mark_buffer_dirty(leaf);
ret = 0;
- if (btrfs_leaf_free_space(root, leaf) < 0) {
- btrfs_print_leaf(root, leaf);
+ if (btrfs_leaf_free_space(root->fs_info, leaf) < 0) {
+ btrfs_print_leaf(leaf);
BUG();
}
kfree(buf);
return 0;
nritems = btrfs_header_nritems(leaf);
- data_end = leaf_data_end(root, leaf);
+ data_end = leaf_data_end(root->fs_info, leaf);
old_data_start = btrfs_item_offset_nr(leaf, slot);
btrfs_mark_buffer_dirty(leaf);
ret = 0;
- if (btrfs_leaf_free_space(root, leaf) < 0) {
- btrfs_print_leaf(root, leaf);
+ if (btrfs_leaf_free_space(root->fs_info, leaf) < 0) {
+ btrfs_print_leaf(leaf);
BUG();
}
return ret;
leaf = path->nodes[0];
nritems = btrfs_header_nritems(leaf);
- data_end = leaf_data_end(root, leaf);
+ data_end = leaf_data_end(root->fs_info, leaf);
- if (btrfs_leaf_free_space(root, leaf) < data_size) {
- btrfs_print_leaf(root, leaf);
+ if (btrfs_leaf_free_space(root->fs_info, leaf) < data_size) {
+ btrfs_print_leaf(leaf);
BUG();
}
slot = path->slots[0];
BUG_ON(slot < 0);
if (slot >= nritems) {
- btrfs_print_leaf(root, leaf);
+ btrfs_print_leaf(leaf);
printk("slot %d too large, nritems %d\n", slot, nritems);
BUG_ON(1);
}
btrfs_mark_buffer_dirty(leaf);
ret = 0;
- if (btrfs_leaf_free_space(root, leaf) < 0) {
- btrfs_print_leaf(root, leaf);
+ if (btrfs_leaf_free_space(root->fs_info, leaf) < 0) {
+ btrfs_print_leaf(leaf);
BUG();
}
return ret;
leaf = path->nodes[0];
nritems = btrfs_header_nritems(leaf);
- data_end = leaf_data_end(root, leaf);
+ data_end = leaf_data_end(root->fs_info, leaf);
- if (btrfs_leaf_free_space(root, leaf) < total_size) {
- btrfs_print_leaf(root, leaf);
+ if (btrfs_leaf_free_space(root->fs_info, leaf) < total_size) {
+ btrfs_print_leaf(leaf);
printk("not enough freespace need %u have %d\n",
- total_size, btrfs_leaf_free_space(root, leaf));
+ total_size, btrfs_leaf_free_space(root->fs_info, leaf));
BUG();
}
unsigned int old_data = btrfs_item_end_nr(leaf, slot);
if (old_data < data_end) {
- btrfs_print_leaf(root, leaf);
+ btrfs_print_leaf(leaf);
printk("slot %d old_data %d data_end %d\n",
slot, old_data, data_end);
BUG_ON(1);
btrfs_fixup_low_keys(root, path, &disk_key, 1);
}
- if (btrfs_leaf_free_space(root, leaf) < 0) {
- btrfs_print_leaf(root, leaf);
+ if (btrfs_leaf_free_space(root->fs_info, leaf) < 0) {
+ btrfs_print_leaf(leaf);
BUG();
}
nritems = btrfs_header_nritems(leaf);
if (slot + nr != nritems) {
- int data_end = leaf_data_end(root, leaf);
+ int data_end = leaf_data_end(root->fs_info, leaf);
memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
data_end + dsize,