X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=ctree.c;h=20848f0f702446309234854ec95a08469ed5ed7b;hb=47c694b0f4afa4fabf1a2013b9f9514a832898f7;hp=130c61fa036e12d50a02e008a4382c78a00b66bc;hpb=ccdd0a067f36b689a0928074d53e5020f3ff5f5d;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/ctree.c b/ctree.c index 130c61f..20848f0 100644 --- a/ctree.c +++ b/ctree.c @@ -20,6 +20,9 @@ #include "transaction.h" #include "print-tree.h" #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); @@ -141,7 +144,7 @@ static int btrfs_block_can_be_shared(struct btrfs_root *root, struct extent_buffer *buf) { /* - * Tree blocks not in refernece counted trees and tree roots + * Tree blocks not in reference counted trees and tree roots * are never shared. If a block was allocated after the last * snapshot and the block was not allocated by tree relocation, * we know the block is not shared. @@ -367,7 +370,7 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, return 0; } - search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1); + search_start = buf->start & ~((u64)SZ_1G - 1); ret = __btrfs_cow_block(trans, root, buf, parent, parent_slot, cow_ret, search_start, 0); return ret; @@ -406,12 +409,12 @@ static int btrfs_comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2) * 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); + return BTRFS_LEAF_DATA_SIZE(fs_info); return btrfs_item_offset_nr(leaf, nr - 1); } @@ -425,7 +428,7 @@ btrfs_check_node(struct btrfs_root *root, struct btrfs_disk_key *parent_key, u32 nritems = btrfs_header_nritems(buf); enum btrfs_tree_block_status ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS; - if (nritems == 0 || nritems > BTRFS_NODEPTRS_PER_BLOCK(root)) + if (nritems == 0 || nritems > BTRFS_NODEPTRS_PER_BLOCK(root->fs_info)) goto fail; ret = BTRFS_TREE_BLOCK_INVALID_PARENT_KEY; @@ -477,11 +480,11 @@ btrfs_check_leaf(struct btrfs_root *root, struct btrfs_disk_key *parent_key, (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; } @@ -513,14 +516,30 @@ btrfs_check_leaf(struct btrfs_root *root, struct btrfs_disk_key *parent_key, goto fail; } if (i == 0 && btrfs_item_end_nr(buf, i) != - BTRFS_LEAF_DATA_SIZE(root)) { + BTRFS_LEAF_DATA_SIZE(root->fs_info)) { ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS; fprintf(stderr, "bad item end %u wanted %u\n", btrfs_item_end_nr(buf, i), - (unsigned)BTRFS_LEAF_DATA_SIZE(root)); + (unsigned)BTRFS_LEAF_DATA_SIZE(root->fs_info)); goto fail; } } + + for (i = 0; i < nritems; i++) { + if (btrfs_item_end_nr(buf, i) > + BTRFS_LEAF_DATA_SIZE(root->fs_info)) { + btrfs_item_key(buf, &key, 0); + btrfs_print_key(&key); + fflush(stdout); + ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS; + fprintf(stderr, "slot end outside of leaf %llu > %llu\n", + (unsigned long long)btrfs_item_end_nr(buf, i), + (unsigned long long)BTRFS_LEAF_DATA_SIZE( + root->fs_info)); + goto fail; + } + } + return BTRFS_TREE_BLOCK_CLEAN; fail: if (btrfs_header_owner(buf) == BTRFS_EXTENT_TREE_OBJECTID) { @@ -621,10 +640,12 @@ static int bin_search(struct extent_buffer *eb, struct btrfs_key *key, slot); } -struct extent_buffer *read_node_slot(struct btrfs_root *root, +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)) @@ -633,9 +654,20 @@ struct extent_buffer *read_node_slot(struct btrfs_root *root, if (level == 0) return NULL; - return read_tree_block(root, btrfs_node_blockptr(parent, slot), - btrfs_level_size(root, level - 1), + 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, @@ -646,6 +678,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct extent_buffer *mid; struct extent_buffer *left = NULL; struct extent_buffer *parent = NULL; + struct btrfs_fs_info *fs_info = root->fs_info; int ret = 0; int wret; int pslot; @@ -676,7 +709,7 @@ static int balance_level(struct btrfs_trans_handle *trans, return 0; /* promote the child to a root */ - child = read_node_slot(root, mid, 0); + child = read_node_slot(fs_info, mid, 0); BUG_ON(!extent_buffer_uptodate(child)); ret = btrfs_cow_block(trans, root, child, mid, 0, &child); BUG_ON(ret); @@ -685,7 +718,6 @@ static int balance_level(struct btrfs_trans_handle *trans, add_root_to_dirty_list(root); path->nodes[level] = NULL; clean_tree_block(trans, root, mid); - wait_on_tree_block_writeback(root, mid); /* once for the path */ free_extent_buffer(mid); @@ -697,10 +729,10 @@ static int balance_level(struct btrfs_trans_handle *trans, return ret; } if (btrfs_header_nritems(mid) > - BTRFS_NODEPTRS_PER_BLOCK(root) / 4) + BTRFS_NODEPTRS_PER_BLOCK(fs_info) / 4) return 0; - left = read_node_slot(root, parent, pslot - 1); + left = read_node_slot(fs_info, parent, pslot - 1); if (extent_buffer_uptodate(left)) { wret = btrfs_cow_block(trans, root, left, parent, pslot - 1, &left); @@ -709,7 +741,7 @@ static int balance_level(struct btrfs_trans_handle *trans, goto enospc; } } - right = read_node_slot(root, parent, pslot + 1); + right = read_node_slot(fs_info, parent, pslot + 1); if (extent_buffer_uptodate(right)) { wret = btrfs_cow_block(trans, root, right, parent, pslot + 1, &right); @@ -739,11 +771,9 @@ static int balance_level(struct btrfs_trans_handle *trans, u32 blocksize = right->len; clean_tree_block(trans, root, right); - wait_on_tree_block_writeback(root, right); free_extent_buffer(right); right = NULL; - wret = btrfs_del_ptr(trans, root, path, - level + 1, pslot + 1); + wret = btrfs_del_ptr(root, path, level + 1, pslot + 1); if (wret) ret = wret; wret = btrfs_free_extent(trans, root, bytenr, @@ -787,10 +817,9 @@ static int balance_level(struct btrfs_trans_handle *trans, u64 bytenr = mid->start; u32 blocksize = mid->len; clean_tree_block(trans, root, mid); - wait_on_tree_block_writeback(root, mid); free_extent_buffer(mid); mid = NULL; - wret = btrfs_del_ptr(trans, root, path, level + 1, pslot); + wret = btrfs_del_ptr(root, path, level + 1, pslot); if (wret) ret = wret; wret = btrfs_free_extent(trans, root, bytenr, blocksize, @@ -842,6 +871,7 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans, struct extent_buffer *mid; struct extent_buffer *left = NULL; struct extent_buffer *parent = NULL; + struct btrfs_fs_info *fs_info = root->fs_info; int ret = 0; int wret; int pslot; @@ -861,13 +891,13 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans, if (!parent) return 1; - left = read_node_slot(root, parent, pslot - 1); + left = read_node_slot(fs_info, parent, pslot - 1); /* first, try to make some room in the middle buffer */ if (extent_buffer_uptodate(left)) { u32 left_nr; left_nr = btrfs_header_nritems(left); - if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { + if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(fs_info) - 1) { wret = 1; } else { ret = btrfs_cow_block(trans, root, left, parent, @@ -902,7 +932,7 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans, } free_extent_buffer(left); } - right= read_node_slot(root, parent, pslot + 1); + right= read_node_slot(fs_info, parent, pslot + 1); /* * then try to empty the right most buffer into the middle @@ -910,7 +940,7 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans, if (extent_buffer_uptodate(right)) { u32 right_nr; right_nr = btrfs_header_nritems(right); - if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { + if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root->fs_info) - 1) { wret = 1; } else { ret = btrfs_cow_block(trans, root, right, @@ -954,6 +984,7 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans, void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, int level, int slot, u64 objectid) { + struct btrfs_fs_info *fs_info = root->fs_info; struct extent_buffer *node; struct btrfs_disk_key disk_key; u32 nritems; @@ -964,7 +995,6 @@ void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, int direction = path->reada; struct extent_buffer *eb; u32 nr; - u32 blocksize; u32 nscan = 0; if (level != 1) @@ -975,8 +1005,7 @@ void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, node = path->nodes[level]; search = btrfs_node_blockptr(node, slot); - blocksize = btrfs_level_size(root, level - 1); - eb = btrfs_find_tree_block(root, search, blocksize); + eb = btrfs_find_tree_block(fs_info, search, fs_info->nodesize); if (eb) { free_extent_buffer(eb); return; @@ -1006,14 +1035,14 @@ 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(fs_info, search, btrfs_node_ptr_generation(node, nr)); - nread += blocksize; + nread += fs_info->nodesize; } nscan++; - if (path->reada < 2 && (nread > (256 * 1024) || nscan > 32)) + if (path->reada < 2 && (nread > SZ_256K || nscan > 32)) break; - if(nread > (1024 * 1024) || nscan > 128) + if(nread > SZ_1M || nscan > 128) break; if (search < lowest_read) @@ -1044,26 +1073,28 @@ int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path, path = found_path; ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0); - if ((ret < 0) || (found_key == NULL)) { - if (path != found_path) - btrfs_free_path(path); - return ret; - } + if ((ret < 0) || (found_key == NULL)) + goto out; eb = path->nodes[0]; if (ret && path->slots[0] >= btrfs_header_nritems(eb)) { ret = btrfs_next_leaf(fs_root, path); if (ret) - return ret; + goto out; eb = path->nodes[0]; } btrfs_item_key_to_cpu(eb, found_key, path->slots[0]); if (found_key->type != key.type || - found_key->objectid != key.objectid) - return 1; + found_key->objectid != key.objectid) { + ret = 1; + goto out; + } - return 0; +out: + if (path != found_path) + btrfs_free_path(path); + return ret; } /* @@ -1088,6 +1119,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root int ret; int level; int should_reada = p->reada; + struct btrfs_fs_info *fs_info = root->fs_info; u8 lowest_level = 0; lowest_level = p->lowest_level; @@ -1127,7 +1159,7 @@ again: p->slots[level] = slot; if ((p->search_for_split || ins_len > 0) && btrfs_header_nritems(b) >= - BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { + BTRFS_NODEPTRS_PER_BLOCK(fs_info) - 3) { int sret = split_node(trans, root, p, level); BUG_ON(sret > 0); if (sret) @@ -1155,13 +1187,13 @@ again: reada_for_search(root, p, level, slot, key->objectid); - b = read_node_slot(root, b, slot); + b = read_node_slot(fs_info, b, slot); if (!extent_buffer_uptodate(b)) return -EIO; } 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); @@ -1273,7 +1305,7 @@ static int push_node_left(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; + push_items = BTRFS_NODEPTRS_PER_BLOCK(root->fs_info) - dst_nritems; WARN_ON(btrfs_header_generation(src) != trans->transid); WARN_ON(btrfs_header_generation(dst) != trans->transid); @@ -1343,7 +1375,7 @@ 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; + push_items = BTRFS_NODEPTRS_PER_BLOCK(root->fs_info) - dst_nritems; if (push_items <= 0) { return 1; } @@ -1406,7 +1438,7 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans, else btrfs_node_key(lower, &lower_key, 0); - c = btrfs_alloc_free_block(trans, root, root->nodesize, + c = btrfs_alloc_free_block(trans, root, root->fs_info->nodesize, root->root_key.objectid, &lower_key, level, root->node->start, 0); @@ -1471,9 +1503,10 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root nritems = btrfs_header_nritems(lower); if (slot > nritems) BUG(); - if (nritems == BTRFS_NODEPTRS_PER_BLOCK(root)) + if (nritems == BTRFS_NODEPTRS_PER_BLOCK(root->fs_info)) BUG(); - if (slot != nritems) { + if (slot < nritems) { + /* shift the items */ memmove_extent_buffer(lower, btrfs_node_key_ptr_offset(slot + 1), btrfs_node_key_ptr_offset(slot), @@ -1519,7 +1552,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) - 3) + BTRFS_NODEPTRS_PER_BLOCK(root->fs_info) - 3) return 0; if (ret < 0) return ret; @@ -1529,7 +1562,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root mid = (c_nritems + 1) / 2; btrfs_node_key(c, &disk_key, mid); - split = btrfs_alloc_free_block(trans, root, root->nodesize, + split = btrfs_alloc_free_block(trans, root, root->fs_info->nodesize, root->root_key.objectid, &disk_key, level, c->start, 0); if (IS_ERR(split)) @@ -1601,14 +1634,16 @@ static int leaf_space_used(struct extent_buffer *l, int start, int nr) * 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) { int nritems = btrfs_header_nritems(leaf); int ret; - ret = BTRFS_LEAF_DATA_SIZE(root) - 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 %lu, used %d nritems %d\n", - ret, (unsigned long) BTRFS_LEAF_DATA_SIZE(root), + ret, BTRFS_LEAF_DATA_SIZE(fs_info), leaf_space_used(leaf, 0, nritems), nritems); } return ret; @@ -1629,6 +1664,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root struct extent_buffer *right; struct extent_buffer *upper; struct btrfs_disk_key disk_key; + struct btrfs_fs_info *fs_info = root->fs_info; int slot; u32 i; int free_space; @@ -1650,13 +1686,13 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root if (slot >= btrfs_header_nritems(upper) - 1) return 1; - right = read_node_slot(root, upper, slot + 1); + right = read_node_slot(fs_info, upper, slot + 1); if (!extent_buffer_uptodate(right)) { if (IS_ERR(right)) 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; @@ -1669,7 +1705,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root 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; @@ -1715,19 +1751,19 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root 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, - BTRFS_LEAF_DATA_SIZE(root) - data_end); + BTRFS_LEAF_DATA_SIZE(root->fs_info) - data_end); /* copy from the left data area */ copy_extent_buffer(right, left, btrfs_leaf_data(right) + - BTRFS_LEAF_DATA_SIZE(root) - push_space, - btrfs_leaf_data(left) + leaf_data_end(root, left), + BTRFS_LEAF_DATA_SIZE(root->fs_info) - push_space, + btrfs_leaf_data(left) + leaf_data_end(fs_info, left), push_space); memmove_extent_buffer(right, btrfs_item_nr_offset(push_items), @@ -1742,7 +1778,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root /* update the item pointers */ right_nritems += push_items; btrfs_set_header_nritems(right, right_nritems); - push_space = BTRFS_LEAF_DATA_SIZE(root); + push_space = BTRFS_LEAF_DATA_SIZE(root->fs_info); for (i = 0; i < right_nritems; i++) { item = btrfs_item_nr(i); push_space -= btrfs_item_size(right, item); @@ -1782,6 +1818,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root struct btrfs_disk_key disk_key; struct extent_buffer *right = path->nodes[0]; struct extent_buffer *left; + struct btrfs_fs_info *fs_info = root->fs_info; int slot; int i; int free_space; @@ -1806,8 +1843,8 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root return 1; } - left = read_node_slot(root, path->nodes[1], slot - 1); - free_space = btrfs_leaf_free_space(root, left); + left = read_node_slot(fs_info, path->nodes[1], slot - 1); + free_space = btrfs_leaf_free_space(fs_info, left); if (free_space < data_size) { free_extent_buffer(left); return 1; @@ -1822,7 +1859,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root 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; @@ -1860,11 +1897,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_item_nr_offset(0), push_items * sizeof(struct btrfs_item)); - push_space = BTRFS_LEAF_DATA_SIZE(root) - + push_space = BTRFS_LEAF_DATA_SIZE(root->fs_info) - 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); @@ -1878,7 +1915,8 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root item = btrfs_item_nr(i); ioff = btrfs_item_offset(left, item); btrfs_set_item_offset(left, item, - ioff - (BTRFS_LEAF_DATA_SIZE(root) - old_left_item_size)); + ioff - (BTRFS_LEAF_DATA_SIZE(root->fs_info) - + old_left_item_size)); } btrfs_set_header_nritems(left, old_left_nritems + push_items); @@ -1890,11 +1928,13 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root 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) - push_space, + 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), @@ -1903,7 +1943,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root } right_nritems -= push_items; btrfs_set_header_nritems(right, right_nritems); - push_space = BTRFS_LEAF_DATA_SIZE(root); + push_space = BTRFS_LEAF_DATA_SIZE(root->fs_info); for (i = 0; i < right_nritems; i++) { item = btrfs_item_nr(i); push_space = push_space - btrfs_item_size(right, item); @@ -1953,18 +1993,20 @@ static noinline int copy_for_split(struct btrfs_trans_handle *trans, 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), nritems * sizeof(struct btrfs_item)); copy_extent_buffer(right, l, - btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) - + 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) - + rt_data_off = BTRFS_LEAF_DATA_SIZE(root->fs_info) - btrfs_item_end_nr(l, mid); for (i = 0; i < nritems; i++) { @@ -2025,7 +2067,7 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans, l = path->nodes[0]; slot = path->slots[0]; if (extend && data_size + btrfs_item_size_nr(l, slot) + - sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root)) + sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) return -EOVERFLOW; /* first try to make some room by pushing left and right */ @@ -2041,7 +2083,7 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans, 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; } @@ -2060,21 +2102,22 @@ again: if (mid <= slot) { if (nritems == 1 || leaf_space_used(l, mid, nritems - mid) + data_size > - BTRFS_LEAF_DATA_SIZE(root)) { + BTRFS_LEAF_DATA_SIZE(root->fs_info)) { if (slot >= nritems) { split = 0; } else { mid = slot; if (mid != nritems && leaf_space_used(l, mid, nritems - mid) + - data_size > BTRFS_LEAF_DATA_SIZE(root)) { + data_size > + BTRFS_LEAF_DATA_SIZE(root->fs_info)) { split = 2; } } } } else { if (leaf_space_used(l, 0, mid) + data_size > - BTRFS_LEAF_DATA_SIZE(root)) { + BTRFS_LEAF_DATA_SIZE(root->fs_info)) { if (!extend && data_size && slot == 0) { split = 0; } else if ((extend || !data_size) && slot == 0) { @@ -2083,7 +2126,8 @@ again: mid = slot; if (mid != nritems && leaf_space_used(l, mid, nritems - mid) + - data_size > BTRFS_LEAF_DATA_SIZE(root)) { + data_size > + BTRFS_LEAF_DATA_SIZE(root->fs_info)) { split = 2 ; } } @@ -2095,7 +2139,7 @@ again: else btrfs_item_key(l, &disk_key, mid); - right = btrfs_alloc_free_block(trans, root, root->leafsize, + right = btrfs_alloc_free_block(trans, root, root->fs_info->nodesize, root->root_key.objectid, &disk_key, 0, l->start, 0); if (IS_ERR(right)) { @@ -2196,7 +2240,8 @@ int btrfs_split_item(struct btrfs_trans_handle *trans, 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]); @@ -2216,7 +2261,8 @@ int btrfs_split_item(struct btrfs_trans_handle *trans, 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: @@ -2226,6 +2272,7 @@ split: buf = kmalloc(item_size, GFP_NOFS); + BUG_ON(!buf); read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, path->slots[0]), item_size); slot = path->slots[0] + 1; @@ -2233,7 +2280,7 @@ split: nritems = btrfs_header_nritems(leaf); - if (slot != nritems) { + if (slot < nritems) { /* shift the items */ memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1), btrfs_item_nr_offset(slot), @@ -2267,7 +2314,7 @@ split: btrfs_mark_buffer_dirty(leaf); ret = 0; - if (btrfs_leaf_free_space(root, leaf) < 0) { + if (btrfs_leaf_free_space(root->fs_info, leaf) < 0) { btrfs_print_leaf(root, leaf); BUG(); } @@ -2275,9 +2322,7 @@ split: return ret; } -int btrfs_truncate_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, +int btrfs_truncate_item(struct btrfs_root *root, struct btrfs_path *path, u32 new_size, int from_end) { int ret = 0; @@ -2299,7 +2344,7 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans, 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); @@ -2365,15 +2410,14 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans, btrfs_mark_buffer_dirty(leaf); ret = 0; - if (btrfs_leaf_free_space(root, leaf) < 0) { + if (btrfs_leaf_free_space(root->fs_info, leaf) < 0) { btrfs_print_leaf(root, leaf); BUG(); } return ret; } -int btrfs_extend_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_path *path, +int btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path, u32 data_size) { int ret = 0; @@ -2389,9 +2433,9 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans, 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) { + if (btrfs_leaf_free_space(root->fs_info, leaf) < data_size) { btrfs_print_leaf(root, leaf); BUG(); } @@ -2428,7 +2472,7 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans, btrfs_mark_buffer_dirty(leaf); ret = 0; - if (btrfs_leaf_free_space(root, leaf) < 0) { + if (btrfs_leaf_free_space(root->fs_info, leaf) < 0) { btrfs_print_leaf(root, leaf); BUG(); } @@ -2475,19 +2519,19 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, 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) { + if (btrfs_leaf_free_space(root->fs_info, leaf) < total_size) { btrfs_print_leaf(root, 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(); } slot = path->slots[0]; BUG_ON(slot < 0); - if (slot != nritems) { + if (slot < nritems) { unsigned int old_data = btrfs_item_end_nr(leaf, slot); if (old_data < data_end) { @@ -2538,7 +2582,7 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, btrfs_fixup_low_keys(root, path, &disk_key, 1); } - if (btrfs_leaf_free_space(root, leaf) < 0) { + if (btrfs_leaf_free_space(root->fs_info, leaf) < 0) { btrfs_print_leaf(root, leaf); BUG(); } @@ -2561,7 +2605,9 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root unsigned long ptr; path = btrfs_alloc_path(); - BUG_ON(!path); + if (!path) + return -ENOMEM; + ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); if (!ret) { leaf = path->nodes[0]; @@ -2580,15 +2626,16 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root * continuing all the way the root if required. The root is converted into * a leaf if all the nodes are emptied. */ -int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct btrfs_path *path, int level, int slot) +int btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path, + int level, int slot) { struct extent_buffer *parent = path->nodes[level]; u32 nritems; int ret = 0; nritems = btrfs_header_nritems(parent); - if (slot != nritems -1) { + if (slot < nritems - 1) { + /* shift the items */ memmove_extent_buffer(parent, btrfs_node_key_ptr_offset(slot), btrfs_node_key_ptr_offset(slot + 1), @@ -2629,7 +2676,7 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans, int ret; WARN_ON(btrfs_header_generation(leaf) != trans->transid); - ret = btrfs_del_ptr(trans, root, path, 1, path->slots[1]); + ret = btrfs_del_ptr(root, path, 1, path->slots[1]); if (ret) return ret; @@ -2663,7 +2710,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, 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, @@ -2692,8 +2739,6 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, btrfs_set_header_level(leaf, 0); } else { clean_tree_block(trans, root, leaf); - wait_on_tree_block_writeback(root, leaf); - wret = btrfs_del_leaf(trans, root, path, leaf); BUG_ON(ret); if (wret) @@ -2709,7 +2754,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, } /* delete the leaf if it is mostly empty */ - if (used < BTRFS_LEAF_DATA_SIZE(root) / 4) { + if (used < BTRFS_LEAF_DATA_SIZE(root->fs_info) / 4) { /* push_leaf_left fixes the path. * make sure the path still points to our leaf * for possible call to del_ptr below @@ -2730,8 +2775,6 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, if (btrfs_header_nritems(leaf) == 0) { clean_tree_block(trans, root, leaf); - wait_on_tree_block_writeback(root, leaf); - path->slots[1] = slot; ret = btrfs_del_leaf(trans, root, path, leaf); BUG_ON(ret); @@ -2759,6 +2802,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) int level = 1; struct extent_buffer *c; struct extent_buffer *next = NULL; + struct btrfs_fs_info *fs_info = root->fs_info; while(level < BTRFS_MAX_LEVEL) { if (!path->nodes[level]) @@ -2774,7 +2818,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) } slot--; - next = read_node_slot(root, c, slot); + next = read_node_slot(fs_info, c, slot); if (!extent_buffer_uptodate(next)) { if (IS_ERR(next)) return PTR_ERR(next); @@ -2794,7 +2838,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) path->slots[level] = slot; if (!level) break; - next = read_node_slot(root, next, slot); + next = read_node_slot(fs_info, next, slot); if (!extent_buffer_uptodate(next)) { if (IS_ERR(next)) return PTR_ERR(next); @@ -2815,6 +2859,7 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) int level = 1; struct extent_buffer *c; struct extent_buffer *next = NULL; + struct btrfs_fs_info *fs_info = root->fs_info; while(level < BTRFS_MAX_LEVEL) { if (!path->nodes[level]) @@ -2832,7 +2877,7 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) if (path->reada) reada_for_search(root, path, level, slot, 0); - next = read_node_slot(root, c, slot); + next = read_node_slot(fs_info, c, slot); if (!extent_buffer_uptodate(next)) return -EIO; break; @@ -2848,7 +2893,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_node_slot(root, next, 0); + next = read_node_slot(fs_info, next, 0); if (!extent_buffer_uptodate(next)) return -EIO; } @@ -2861,6 +2906,7 @@ int btrfs_previous_item(struct btrfs_root *root, { struct btrfs_key found_key; struct extent_buffer *leaf; + u32 nritems; int ret; while(1) { @@ -2872,9 +2918,20 @@ int btrfs_previous_item(struct btrfs_root *root, path->slots[0]--; } leaf = path->nodes[0]; + nritems = btrfs_header_nritems(leaf); + if (nritems == 0) + return 1; + if (path->slots[0] == nritems) + path->slots[0]--; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + if (found_key.objectid < min_objectid) + break; if (found_key.type == type) return 0; + if (found_key.objectid == min_objectid && + found_key.type < type) + break; } return 1; } @@ -2920,3 +2977,27 @@ int btrfs_previous_extent_item(struct btrfs_root *root, } return 1; } + +/* + * Search in extent tree to found next meta/data extent + * Caller needs to check for no-hole or skinny metadata features. + */ +int btrfs_next_extent_item(struct btrfs_root *root, + struct btrfs_path *path, u64 max_objectid) +{ + struct btrfs_key found_key; + int ret; + + while (1) { + ret = btrfs_next_item(root, path); + if (ret) + return ret; + btrfs_item_key_to_cpu(path->nodes[0], &found_key, + path->slots[0]); + if (found_key.objectid > max_objectid) + return 1; + if (found_key.type == BTRFS_EXTENT_ITEM_KEY || + found_key.type == BTRFS_METADATA_ITEM_KEY) + return 0; + } +}