Btrfs: Add back pointers from extents to the btree or file referencing them
Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
74493f7a59
commit
7bb86316c3
196
fs/btrfs/ctree.c
196
fs/btrfs/ctree.c
@ -77,13 +77,37 @@ static int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
|||||||
struct extent_buffer **cow_ret,
|
struct extent_buffer **cow_ret,
|
||||||
u64 search_start, u64 empty_size)
|
u64 search_start, u64 empty_size)
|
||||||
{
|
{
|
||||||
|
u64 root_gen;
|
||||||
struct extent_buffer *cow;
|
struct extent_buffer *cow;
|
||||||
|
u32 nritems;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int different_trans = 0;
|
int different_trans = 0;
|
||||||
|
int level;
|
||||||
|
struct btrfs_key first_key;
|
||||||
|
|
||||||
|
if (root->ref_cows) {
|
||||||
|
root_gen = trans->transid;
|
||||||
|
} else {
|
||||||
|
root_gen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN_ON(root->ref_cows && trans->transid !=
|
||||||
|
root->fs_info->running_transaction->transid);
|
||||||
WARN_ON(root->ref_cows && trans->transid != root->last_trans);
|
WARN_ON(root->ref_cows && trans->transid != root->last_trans);
|
||||||
|
|
||||||
cow = btrfs_alloc_free_block(trans, root, buf->len,
|
level = btrfs_header_level(buf);
|
||||||
|
nritems = btrfs_header_nritems(buf);
|
||||||
|
if (nritems) {
|
||||||
|
if (level == 0)
|
||||||
|
btrfs_item_key_to_cpu(buf, &first_key, 0);
|
||||||
|
else
|
||||||
|
btrfs_node_key_to_cpu(buf, &first_key, 0);
|
||||||
|
} else {
|
||||||
|
first_key.objectid = 0;
|
||||||
|
}
|
||||||
|
cow = __btrfs_alloc_free_block(trans, root, buf->len,
|
||||||
|
root->root_key.objectid,
|
||||||
|
root_gen, first_key.objectid, level,
|
||||||
search_start, empty_size);
|
search_start, empty_size);
|
||||||
if (IS_ERR(cow))
|
if (IS_ERR(cow))
|
||||||
return PTR_ERR(cow);
|
return PTR_ERR(cow);
|
||||||
@ -104,14 +128,17 @@ static int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (buf == root->node) {
|
if (buf == root->node) {
|
||||||
|
root_gen = btrfs_header_generation(buf);
|
||||||
root->node = cow;
|
root->node = cow;
|
||||||
extent_buffer_get(cow);
|
extent_buffer_get(cow);
|
||||||
if (buf != root->commit_root) {
|
if (buf != root->commit_root) {
|
||||||
btrfs_free_extent(trans, root, buf->start,
|
btrfs_free_extent(trans, root, buf->start,
|
||||||
buf->len, 1);
|
buf->len, root->root_key.objectid,
|
||||||
|
root_gen, 0, 0, 1);
|
||||||
}
|
}
|
||||||
free_extent_buffer(buf);
|
free_extent_buffer(buf);
|
||||||
} else {
|
} else {
|
||||||
|
root_gen = btrfs_header_generation(parent);
|
||||||
btrfs_set_node_blockptr(parent, parent_slot,
|
btrfs_set_node_blockptr(parent, parent_slot,
|
||||||
cow->start);
|
cow->start);
|
||||||
WARN_ON(trans->transid == 0);
|
WARN_ON(trans->transid == 0);
|
||||||
@ -119,7 +146,9 @@ static int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
|||||||
trans->transid);
|
trans->transid);
|
||||||
btrfs_mark_buffer_dirty(parent);
|
btrfs_mark_buffer_dirty(parent);
|
||||||
WARN_ON(btrfs_header_generation(parent) != trans->transid);
|
WARN_ON(btrfs_header_generation(parent) != trans->transid);
|
||||||
btrfs_free_extent(trans, root, buf->start, buf->len, 1);
|
btrfs_free_extent(trans, root, buf->start, buf->len,
|
||||||
|
btrfs_header_owner(parent), root_gen,
|
||||||
|
0, 0, 1);
|
||||||
}
|
}
|
||||||
free_extent_buffer(buf);
|
free_extent_buffer(buf);
|
||||||
btrfs_mark_buffer_dirty(cow);
|
btrfs_mark_buffer_dirty(cow);
|
||||||
@ -606,6 +635,8 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mid = path->nodes[level];
|
mid = path->nodes[level];
|
||||||
|
WARN_ON(btrfs_header_generation(mid) != trans->transid);
|
||||||
|
|
||||||
orig_ptr = btrfs_node_blockptr(mid, orig_slot);
|
orig_ptr = btrfs_node_blockptr(mid, orig_slot);
|
||||||
|
|
||||||
if (level < BTRFS_MAX_LEVEL - 1)
|
if (level < BTRFS_MAX_LEVEL - 1)
|
||||||
@ -631,7 +662,9 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
wait_on_tree_block_writeback(root, mid);
|
wait_on_tree_block_writeback(root, mid);
|
||||||
/* once for the path */
|
/* once for the path */
|
||||||
free_extent_buffer(mid);
|
free_extent_buffer(mid);
|
||||||
ret = btrfs_free_extent(trans, root, mid->start, mid->len, 1);
|
ret = btrfs_free_extent(trans, root, mid->start, mid->len,
|
||||||
|
root->root_key.objectid,
|
||||||
|
btrfs_header_generation(mid), 0, 0, 1);
|
||||||
/* once for the root ptr */
|
/* once for the root ptr */
|
||||||
free_extent_buffer(mid);
|
free_extent_buffer(mid);
|
||||||
return ret;
|
return ret;
|
||||||
@ -681,6 +714,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
ret = wret;
|
ret = wret;
|
||||||
if (btrfs_header_nritems(right) == 0) {
|
if (btrfs_header_nritems(right) == 0) {
|
||||||
u64 bytenr = right->start;
|
u64 bytenr = right->start;
|
||||||
|
u64 generation = btrfs_header_generation(parent);
|
||||||
u32 blocksize = right->len;
|
u32 blocksize = right->len;
|
||||||
|
|
||||||
clean_tree_block(trans, root, right);
|
clean_tree_block(trans, root, right);
|
||||||
@ -692,7 +726,9 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
wret = btrfs_free_extent(trans, root, bytenr,
|
wret = btrfs_free_extent(trans, root, bytenr,
|
||||||
blocksize, 1);
|
blocksize,
|
||||||
|
btrfs_header_owner(parent),
|
||||||
|
generation, 0, 0, 1);
|
||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
} else {
|
} else {
|
||||||
@ -722,6 +758,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
}
|
}
|
||||||
if (btrfs_header_nritems(mid) == 0) {
|
if (btrfs_header_nritems(mid) == 0) {
|
||||||
/* we've managed to empty the middle node, drop it */
|
/* we've managed to empty the middle node, drop it */
|
||||||
|
u64 root_gen = btrfs_header_generation(parent);
|
||||||
u64 bytenr = mid->start;
|
u64 bytenr = mid->start;
|
||||||
u32 blocksize = mid->len;
|
u32 blocksize = mid->len;
|
||||||
clean_tree_block(trans, root, mid);
|
clean_tree_block(trans, root, mid);
|
||||||
@ -731,7 +768,9 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
wret = del_ptr(trans, root, path, level + 1, pslot);
|
wret = del_ptr(trans, root, path, level + 1, pslot);
|
||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
wret = btrfs_free_extent(trans, root, bytenr, blocksize, 1);
|
wret = btrfs_free_extent(trans, root, bytenr, blocksize,
|
||||||
|
btrfs_header_owner(parent),
|
||||||
|
root_gen, 0, 0, 1);
|
||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
} else {
|
} else {
|
||||||
@ -788,6 +827,7 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans,
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
mid = path->nodes[level];
|
mid = path->nodes[level];
|
||||||
|
WARN_ON(btrfs_header_generation(mid) != trans->transid);
|
||||||
orig_ptr = btrfs_node_blockptr(mid, orig_slot);
|
orig_ptr = btrfs_node_blockptr(mid, orig_slot);
|
||||||
|
|
||||||
if (level < BTRFS_MAX_LEVEL - 1)
|
if (level < BTRFS_MAX_LEVEL - 1)
|
||||||
@ -1113,6 +1153,8 @@ static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
src_nritems = btrfs_header_nritems(src);
|
src_nritems = btrfs_header_nritems(src);
|
||||||
dst_nritems = btrfs_header_nritems(dst);
|
dst_nritems = btrfs_header_nritems(dst);
|
||||||
push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems;
|
push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems;
|
||||||
|
WARN_ON(btrfs_header_generation(src) != trans->transid);
|
||||||
|
WARN_ON(btrfs_header_generation(dst) != trans->transid);
|
||||||
|
|
||||||
if (push_items <= 0) {
|
if (push_items <= 0) {
|
||||||
return 1;
|
return 1;
|
||||||
@ -1159,6 +1201,9 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
|
|||||||
int dst_nritems;
|
int dst_nritems;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
WARN_ON(btrfs_header_generation(src) != trans->transid);
|
||||||
|
WARN_ON(btrfs_header_generation(dst) != trans->transid);
|
||||||
|
|
||||||
src_nritems = btrfs_header_nritems(src);
|
src_nritems = btrfs_header_nritems(src);
|
||||||
dst_nritems = btrfs_header_nritems(dst);
|
dst_nritems = btrfs_header_nritems(dst);
|
||||||
push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems;
|
push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems;
|
||||||
@ -1202,6 +1247,8 @@ static int insert_new_root(struct btrfs_trans_handle *trans,
|
|||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct btrfs_path *path, int level)
|
struct btrfs_path *path, int level)
|
||||||
{
|
{
|
||||||
|
u64 root_gen;
|
||||||
|
u64 lower_gen;
|
||||||
struct extent_buffer *lower;
|
struct extent_buffer *lower;
|
||||||
struct extent_buffer *c;
|
struct extent_buffer *c;
|
||||||
struct btrfs_disk_key lower_key;
|
struct btrfs_disk_key lower_key;
|
||||||
@ -1209,7 +1256,20 @@ static int insert_new_root(struct btrfs_trans_handle *trans,
|
|||||||
BUG_ON(path->nodes[level]);
|
BUG_ON(path->nodes[level]);
|
||||||
BUG_ON(path->nodes[level-1] != root->node);
|
BUG_ON(path->nodes[level-1] != root->node);
|
||||||
|
|
||||||
c = btrfs_alloc_free_block(trans, root, root->nodesize,
|
if (root->ref_cows)
|
||||||
|
root_gen = trans->transid;
|
||||||
|
else
|
||||||
|
root_gen = 0;
|
||||||
|
|
||||||
|
lower = path->nodes[level-1];
|
||||||
|
if (level == 1)
|
||||||
|
btrfs_item_key(lower, &lower_key, 0);
|
||||||
|
else
|
||||||
|
btrfs_node_key(lower, &lower_key, 0);
|
||||||
|
|
||||||
|
c = __btrfs_alloc_free_block(trans, root, root->nodesize,
|
||||||
|
root->root_key.objectid,
|
||||||
|
root_gen, lower_key.objectid, level,
|
||||||
root->node->start, 0);
|
root->node->start, 0);
|
||||||
if (IS_ERR(c))
|
if (IS_ERR(c))
|
||||||
return PTR_ERR(c);
|
return PTR_ERR(c);
|
||||||
@ -1219,19 +1279,16 @@ static int insert_new_root(struct btrfs_trans_handle *trans,
|
|||||||
btrfs_set_header_bytenr(c, c->start);
|
btrfs_set_header_bytenr(c, c->start);
|
||||||
btrfs_set_header_generation(c, trans->transid);
|
btrfs_set_header_generation(c, trans->transid);
|
||||||
btrfs_set_header_owner(c, root->root_key.objectid);
|
btrfs_set_header_owner(c, root->root_key.objectid);
|
||||||
lower = path->nodes[level-1];
|
|
||||||
|
|
||||||
write_extent_buffer(c, root->fs_info->fsid,
|
write_extent_buffer(c, root->fs_info->fsid,
|
||||||
(unsigned long)btrfs_header_fsid(c),
|
(unsigned long)btrfs_header_fsid(c),
|
||||||
BTRFS_FSID_SIZE);
|
BTRFS_FSID_SIZE);
|
||||||
if (level == 1)
|
|
||||||
btrfs_item_key(lower, &lower_key, 0);
|
|
||||||
else
|
|
||||||
btrfs_node_key(lower, &lower_key, 0);
|
|
||||||
btrfs_set_node_key(c, &lower_key, 0);
|
btrfs_set_node_key(c, &lower_key, 0);
|
||||||
btrfs_set_node_blockptr(c, 0, lower->start);
|
btrfs_set_node_blockptr(c, 0, lower->start);
|
||||||
WARN_ON(btrfs_header_generation(lower) == 0);
|
lower_gen = btrfs_header_generation(lower);
|
||||||
btrfs_set_node_ptr_generation(c, 0, btrfs_header_generation(lower));
|
WARN_ON(lower_gen == 0);
|
||||||
|
|
||||||
|
btrfs_set_node_ptr_generation(c, 0, lower_gen);
|
||||||
|
|
||||||
btrfs_mark_buffer_dirty(c);
|
btrfs_mark_buffer_dirty(c);
|
||||||
|
|
||||||
@ -1241,6 +1298,18 @@ static int insert_new_root(struct btrfs_trans_handle *trans,
|
|||||||
extent_buffer_get(c);
|
extent_buffer_get(c);
|
||||||
path->nodes[level] = c;
|
path->nodes[level] = c;
|
||||||
path->slots[level] = 0;
|
path->slots[level] = 0;
|
||||||
|
|
||||||
|
if (root->ref_cows && lower_gen != trans->transid) {
|
||||||
|
struct btrfs_path *back_path = btrfs_alloc_path();
|
||||||
|
int ret;
|
||||||
|
ret = btrfs_insert_extent_backref(trans,
|
||||||
|
root->fs_info->extent_root,
|
||||||
|
path, lower->start,
|
||||||
|
root->root_key.objectid,
|
||||||
|
trans->transid, 0, 0);
|
||||||
|
BUG_ON(ret);
|
||||||
|
btrfs_free_path(back_path);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1294,6 +1363,7 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
|
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||||
*root, struct btrfs_path *path, int level)
|
*root, struct btrfs_path *path, int level)
|
||||||
{
|
{
|
||||||
|
u64 root_gen;
|
||||||
struct extent_buffer *c;
|
struct extent_buffer *c;
|
||||||
struct extent_buffer *split;
|
struct extent_buffer *split;
|
||||||
struct btrfs_disk_key disk_key;
|
struct btrfs_disk_key disk_key;
|
||||||
@ -1303,6 +1373,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
u32 c_nritems;
|
u32 c_nritems;
|
||||||
|
|
||||||
c = path->nodes[level];
|
c = path->nodes[level];
|
||||||
|
WARN_ON(btrfs_header_generation(c) != trans->transid);
|
||||||
if (c == root->node) {
|
if (c == root->node) {
|
||||||
/* trying to split the root, lets make a new one */
|
/* trying to split the root, lets make a new one */
|
||||||
ret = insert_new_root(trans, root, path, level + 1);
|
ret = insert_new_root(trans, root, path, level + 1);
|
||||||
@ -1319,8 +1390,17 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
}
|
}
|
||||||
|
|
||||||
c_nritems = btrfs_header_nritems(c);
|
c_nritems = btrfs_header_nritems(c);
|
||||||
split = btrfs_alloc_free_block(trans, root, root->nodesize,
|
if (root->ref_cows)
|
||||||
c->start, 0);
|
root_gen = trans->transid;
|
||||||
|
else
|
||||||
|
root_gen = 0;
|
||||||
|
|
||||||
|
btrfs_node_key(c, &disk_key, 0);
|
||||||
|
split = __btrfs_alloc_free_block(trans, root, root->nodesize,
|
||||||
|
root->root_key.objectid,
|
||||||
|
root_gen,
|
||||||
|
btrfs_disk_key_objectid(&disk_key),
|
||||||
|
level, c->start, 0);
|
||||||
if (IS_ERR(split))
|
if (IS_ERR(split))
|
||||||
return PTR_ERR(split);
|
return PTR_ERR(split);
|
||||||
|
|
||||||
@ -1789,6 +1869,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
*root, struct btrfs_key *ins_key,
|
*root, struct btrfs_key *ins_key,
|
||||||
struct btrfs_path *path, int data_size, int extend)
|
struct btrfs_path *path, int data_size, int extend)
|
||||||
{
|
{
|
||||||
|
u64 root_gen;
|
||||||
struct extent_buffer *l;
|
struct extent_buffer *l;
|
||||||
u32 nritems;
|
u32 nritems;
|
||||||
int mid;
|
int mid;
|
||||||
@ -1807,6 +1888,11 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
if (extend)
|
if (extend)
|
||||||
space_needed = data_size;
|
space_needed = data_size;
|
||||||
|
|
||||||
|
if (root->ref_cows)
|
||||||
|
root_gen = trans->transid;
|
||||||
|
else
|
||||||
|
root_gen = 0;
|
||||||
|
|
||||||
/* first try to make some room by pushing left and right */
|
/* first try to make some room by pushing left and right */
|
||||||
if (ins_key->type != BTRFS_DIR_ITEM_KEY) {
|
if (ins_key->type != BTRFS_DIR_ITEM_KEY) {
|
||||||
wret = push_leaf_right(trans, root, path, data_size, 0);
|
wret = push_leaf_right(trans, root, path, data_size, 0);
|
||||||
@ -1837,8 +1923,12 @@ again:
|
|||||||
nritems = btrfs_header_nritems(l);
|
nritems = btrfs_header_nritems(l);
|
||||||
mid = (nritems + 1)/ 2;
|
mid = (nritems + 1)/ 2;
|
||||||
|
|
||||||
right = btrfs_alloc_free_block(trans, root, root->leafsize,
|
btrfs_item_key(l, &disk_key, 0);
|
||||||
l->start, 0);
|
|
||||||
|
right = __btrfs_alloc_free_block(trans, root, root->leafsize,
|
||||||
|
root->root_key.objectid,
|
||||||
|
root_gen, disk_key.objectid, 0,
|
||||||
|
l->start, 0);
|
||||||
if (IS_ERR(right))
|
if (IS_ERR(right))
|
||||||
return PTR_ERR(right);
|
return PTR_ERR(right);
|
||||||
|
|
||||||
@ -2413,13 +2503,16 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|||||||
if (leaf == root->node) {
|
if (leaf == root->node) {
|
||||||
btrfs_set_header_level(leaf, 0);
|
btrfs_set_header_level(leaf, 0);
|
||||||
} else {
|
} else {
|
||||||
|
u64 root_gen = btrfs_header_generation(path->nodes[1]);
|
||||||
clean_tree_block(trans, root, leaf);
|
clean_tree_block(trans, root, leaf);
|
||||||
wait_on_tree_block_writeback(root, leaf);
|
wait_on_tree_block_writeback(root, leaf);
|
||||||
wret = del_ptr(trans, root, path, 1, path->slots[1]);
|
wret = del_ptr(trans, root, path, 1, path->slots[1]);
|
||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
wret = btrfs_free_extent(trans, root,
|
wret = btrfs_free_extent(trans, root,
|
||||||
leaf->start, leaf->len, 1);
|
leaf->start, leaf->len,
|
||||||
|
btrfs_header_owner(path->nodes[1]),
|
||||||
|
root_gen, 0, 0, 1);
|
||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
}
|
}
|
||||||
@ -2456,9 +2549,13 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (btrfs_header_nritems(leaf) == 0) {
|
if (btrfs_header_nritems(leaf) == 0) {
|
||||||
|
u64 root_gen;
|
||||||
u64 bytenr = leaf->start;
|
u64 bytenr = leaf->start;
|
||||||
u32 blocksize = leaf->len;
|
u32 blocksize = leaf->len;
|
||||||
|
|
||||||
|
root_gen = btrfs_header_generation(
|
||||||
|
path->nodes[1]);
|
||||||
|
|
||||||
clean_tree_block(trans, root, leaf);
|
clean_tree_block(trans, root, leaf);
|
||||||
wait_on_tree_block_writeback(root, leaf);
|
wait_on_tree_block_writeback(root, leaf);
|
||||||
|
|
||||||
@ -2468,7 +2565,9 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|||||||
|
|
||||||
free_extent_buffer(leaf);
|
free_extent_buffer(leaf);
|
||||||
wret = btrfs_free_extent(trans, root, bytenr,
|
wret = btrfs_free_extent(trans, root, bytenr,
|
||||||
blocksize, 1);
|
blocksize,
|
||||||
|
btrfs_header_owner(path->nodes[1]),
|
||||||
|
root_gen, 0, 0, 1);
|
||||||
if (wret)
|
if (wret)
|
||||||
ret = wret;
|
ret = wret;
|
||||||
} else {
|
} else {
|
||||||
@ -2482,6 +2581,61 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* walk up the tree as far as required to find the previous leaf.
|
||||||
|
* returns 0 if it found something or 1 if there are no lesser leaves.
|
||||||
|
* returns < 0 on io errors.
|
||||||
|
*/
|
||||||
|
int btrfs_prev_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;
|
||||||
|
|
||||||
|
while(level < BTRFS_MAX_LEVEL) {
|
||||||
|
if (!path->nodes[level])
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
slot = path->slots[level];
|
||||||
|
c = path->nodes[level];
|
||||||
|
if (slot == 0) {
|
||||||
|
level++;
|
||||||
|
if (level == BTRFS_MAX_LEVEL)
|
||||||
|
return 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
slot--;
|
||||||
|
|
||||||
|
bytenr = btrfs_node_blockptr(c, slot);
|
||||||
|
if (next)
|
||||||
|
free_extent_buffer(next);
|
||||||
|
|
||||||
|
if (path->reada < 0)
|
||||||
|
reada_for_search(root, path, level, slot);
|
||||||
|
|
||||||
|
next = read_tree_block(root, bytenr,
|
||||||
|
btrfs_level_size(root, level - 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path->slots[level] = slot;
|
||||||
|
while(1) {
|
||||||
|
level--;
|
||||||
|
c = path->nodes[level];
|
||||||
|
free_extent_buffer(c);
|
||||||
|
path->nodes[level] = next;
|
||||||
|
path->slots[level] = 0;
|
||||||
|
if (!level)
|
||||||
|
break;
|
||||||
|
if (path->reada)
|
||||||
|
reada_for_search(root, path, level, 0);
|
||||||
|
next = read_tree_block(root, btrfs_node_blockptr(next, 0),
|
||||||
|
btrfs_level_size(root, level - 1));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* walk up the tree as far as required to find the next leaf.
|
* walk up the tree as far as required to find the next leaf.
|
||||||
* returns 0 if it found something or 1 if there are no greater leaves.
|
* returns 0 if it found something or 1 if there are no greater leaves.
|
||||||
@ -2503,6 +2657,8 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
|||||||
c = path->nodes[level];
|
c = path->nodes[level];
|
||||||
if (slot >= btrfs_header_nritems(c)) {
|
if (slot >= btrfs_header_nritems(c)) {
|
||||||
level++;
|
level++;
|
||||||
|
if (level == BTRFS_MAX_LEVEL)
|
||||||
|
return 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,11 +544,12 @@ 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_objectid, struct btrfs_extent_ref, objectid, 64);
|
||||||
BTRFS_SETGET_FUNCS(ref_offset, struct btrfs_extent_ref, offset, 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(stack_ref_root, struct btrfs_extent_ref, root, 64);
|
||||||
BTRFS_SETGET_STACK_FUNCS(ref_generation, struct btrfs_extent_ref,
|
BTRFS_SETGET_STACK_FUNCS(stack_ref_generation, struct btrfs_extent_ref,
|
||||||
generation, 64);
|
generation, 64);
|
||||||
BTRFS_SETGET_STACK_FUNCS(ref_objectid, struct btrfs_extent_ref, objectid, 64);
|
BTRFS_SETGET_STACK_FUNCS(stack_ref_objectid, struct btrfs_extent_ref,
|
||||||
BTRFS_SETGET_STACK_FUNCS(ref_offset, struct btrfs_extent_ref, offset, 64);
|
objectid, 64);
|
||||||
|
BTRFS_SETGET_STACK_FUNCS(stack_ref_offset, struct btrfs_extent_ref, offset, 64);
|
||||||
|
|
||||||
BTRFS_SETGET_STACK_FUNCS(stack_extent_refs, struct btrfs_extent_item,
|
BTRFS_SETGET_STACK_FUNCS(stack_extent_refs, struct btrfs_extent_item,
|
||||||
refs, 32);
|
refs, 32);
|
||||||
@ -914,24 +915,45 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
|
|||||||
*hint, u64 search_start,
|
*hint, u64 search_start,
|
||||||
int data, int owner);
|
int data, int owner);
|
||||||
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
|
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root);
|
struct btrfs_root *root, u64 owner_objectid);
|
||||||
struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, u32 size,
|
struct btrfs_root *root, u32 size,
|
||||||
|
u64 root_objectid,
|
||||||
u64 hint, u64 empty_size);
|
u64 hint, u64 empty_size);
|
||||||
|
struct extent_buffer *__btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
u32 blocksize,
|
||||||
|
u64 root_objectid,
|
||||||
|
u64 ref_generation,
|
||||||
|
u64 first_objectid,
|
||||||
|
int level,
|
||||||
|
u64 hint,
|
||||||
|
u64 empty_size);
|
||||||
|
int btrfs_insert_extent_backref(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
struct btrfs_path *path, u64 bytenr,
|
||||||
|
u64 root_objectid, u64 ref_generation,
|
||||||
|
u64 owner, u64 owner_offset);
|
||||||
int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
|
int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, u64 owner,
|
struct btrfs_root *root,
|
||||||
u64 num_bytes, u64 empty_size, u64 search_start,
|
u64 num_bytes, u64 root_objectid, u64 ref_generation,
|
||||||
|
u64 owner, u64 owner_offset,
|
||||||
|
u64 empty_size, u64 hint_byte,
|
||||||
u64 search_end, struct btrfs_key *ins, int data);
|
u64 search_end, struct btrfs_key *ins, int data);
|
||||||
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||||
struct extent_buffer *buf);
|
struct extent_buffer *buf);
|
||||||
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||||
*root, u64 bytenr, u64 num_bytes, int pin);
|
*root, u64 bytenr, u64 num_bytes,
|
||||||
|
u64 root_objectid, u64 ref_generation,
|
||||||
|
u64 owner_objectid, u64 owner_offset, int pin);
|
||||||
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
|
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct extent_map_tree *unpin);
|
struct extent_map_tree *unpin);
|
||||||
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
u64 bytenr, u64 num_bytes);
|
u64 bytenr, u64 num_bytes,
|
||||||
|
u64 root_objectid, u64 ref_generation,
|
||||||
|
u64 owner, u64 owner_offset);
|
||||||
int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
|
int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root);
|
struct btrfs_root *root);
|
||||||
int btrfs_free_block_groups(struct btrfs_fs_info *info);
|
int btrfs_free_block_groups(struct btrfs_fs_info *info);
|
||||||
@ -966,6 +988,7 @@ int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
*root, struct btrfs_path *path, struct btrfs_key
|
*root, struct btrfs_path *path, struct btrfs_key
|
||||||
*cpu_key, u32 data_size);
|
*cpu_key, u32 data_size);
|
||||||
int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
|
int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
|
||||||
|
int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
|
||||||
int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
|
int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
|
||||||
int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
|
int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||||
*root);
|
*root);
|
||||||
|
@ -210,7 +210,7 @@ static int btree_writepages(struct address_space *mapping,
|
|||||||
{
|
{
|
||||||
struct extent_map_tree *tree;
|
struct extent_map_tree *tree;
|
||||||
tree = &BTRFS_I(mapping->host)->extent_tree;
|
tree = &BTRFS_I(mapping->host)->extent_tree;
|
||||||
if (wbc->sync_mode == WB_SYNC_NONE) {
|
if (0 && wbc->sync_mode == WB_SYNC_NONE) {
|
||||||
u64 num_dirty;
|
u64 num_dirty;
|
||||||
u64 start = 0;
|
u64 start = 0;
|
||||||
unsigned long thresh = 96 * 1024 * 1024;
|
unsigned long thresh = 96 * 1024 * 1024;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
#include <linux/crc32c.h>
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
@ -89,7 +90,8 @@ static int cache_block_group(struct btrfs_root *root,
|
|||||||
|
|
||||||
btrfs_item_key_to_cpu(leaf, &key, slot);
|
btrfs_item_key_to_cpu(leaf, &key, slot);
|
||||||
if (key.objectid < block_group->key.objectid) {
|
if (key.objectid < block_group->key.objectid) {
|
||||||
if (key.objectid + key.offset > first_free)
|
if (btrfs_key_type(&key) != BTRFS_EXTENT_REF_KEY &&
|
||||||
|
key.objectid + key.offset > first_free)
|
||||||
first_free = key.objectid + key.offset;
|
first_free = key.objectid + key.offset;
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
@ -353,7 +355,7 @@ found:
|
|||||||
return found_group;
|
return found_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 hash_extent_ref(u64 root_objectid, u64 root_generation,
|
static u64 hash_extent_ref(u64 root_objectid, u64 ref_generation,
|
||||||
u64 owner, u64 owner_offset)
|
u64 owner, u64 owner_offset)
|
||||||
{
|
{
|
||||||
u32 high_crc = ~(u32)0;
|
u32 high_crc = ~(u32)0;
|
||||||
@ -362,53 +364,149 @@ static u64 hash_extent_ref(u64 root_objectid, u64 root_generation,
|
|||||||
|
|
||||||
lenum = cpu_to_le64(root_objectid);
|
lenum = cpu_to_le64(root_objectid);
|
||||||
high_crc = crc32c(high_crc, &lenum, sizeof(lenum));
|
high_crc = crc32c(high_crc, &lenum, sizeof(lenum));
|
||||||
lenum = cpu_to_le64(root_generation);
|
lenum = cpu_to_le64(ref_generation);
|
||||||
high_crc = crc32c(high_crc, &lenum, sizeof(lenum));
|
low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
|
||||||
|
|
||||||
|
#if 0
|
||||||
lenum = cpu_to_le64(owner);
|
lenum = cpu_to_le64(owner);
|
||||||
low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
|
low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
|
||||||
|
|
||||||
lenum = cpu_to_le64(owner_offset);
|
lenum = cpu_to_le64(owner_offset);
|
||||||
low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
|
low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
|
||||||
|
#endif
|
||||||
return ((u64)high_crc << 32) | (u64)low_crc;
|
return ((u64)high_crc << 32) | (u64)low_crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int insert_extent_ref(struct btrfs_trans_handle *trans,
|
static int match_extent_ref(struct extent_buffer *leaf,
|
||||||
struct btrfs_root *root,
|
struct btrfs_extent_ref *disk_ref,
|
||||||
struct btrfs_path *path,
|
struct btrfs_extent_ref *cpu_ref)
|
||||||
u64 bytenr,
|
{
|
||||||
u64 root_objectid, u64 root_generation,
|
int ret;
|
||||||
u64 owner, u64 owner_offset)
|
int len;
|
||||||
|
|
||||||
|
if (cpu_ref->objectid)
|
||||||
|
len = sizeof(*cpu_ref);
|
||||||
|
else
|
||||||
|
len = 2 * sizeof(u64);
|
||||||
|
ret = memcmp_extent_buffer(leaf, cpu_ref, (unsigned long)disk_ref,
|
||||||
|
len);
|
||||||
|
return ret == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lookup_extent_backref(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
struct btrfs_path *path, u64 bytenr,
|
||||||
|
u64 root_objectid, u64 ref_generation,
|
||||||
|
u64 owner, u64 owner_offset, int del)
|
||||||
|
{
|
||||||
|
u64 hash;
|
||||||
|
struct btrfs_key key;
|
||||||
|
struct btrfs_key found_key;
|
||||||
|
struct btrfs_extent_ref ref;
|
||||||
|
struct extent_buffer *leaf;
|
||||||
|
struct btrfs_extent_ref *disk_ref;
|
||||||
|
int ret;
|
||||||
|
int ret2;
|
||||||
|
|
||||||
|
btrfs_set_stack_ref_root(&ref, root_objectid);
|
||||||
|
btrfs_set_stack_ref_generation(&ref, ref_generation);
|
||||||
|
btrfs_set_stack_ref_objectid(&ref, owner);
|
||||||
|
btrfs_set_stack_ref_offset(&ref, owner_offset);
|
||||||
|
|
||||||
|
hash = hash_extent_ref(root_objectid, ref_generation, owner,
|
||||||
|
owner_offset);
|
||||||
|
key.offset = hash;
|
||||||
|
key.objectid = bytenr;
|
||||||
|
key.type = BTRFS_EXTENT_REF_KEY;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
ret = btrfs_search_slot(trans, root, &key, path,
|
||||||
|
del ? -1 : 0, del);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
leaf = path->nodes[0];
|
||||||
|
if (ret != 0) {
|
||||||
|
u32 nritems = btrfs_header_nritems(leaf);
|
||||||
|
if (path->slots[0] >= nritems) {
|
||||||
|
ret2 = btrfs_next_leaf(root, path);
|
||||||
|
if (ret2)
|
||||||
|
goto out;
|
||||||
|
leaf = path->nodes[0];
|
||||||
|
}
|
||||||
|
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||||
|
if (found_key.objectid != bytenr ||
|
||||||
|
found_key.type != BTRFS_EXTENT_REF_KEY)
|
||||||
|
goto out;
|
||||||
|
key.offset = found_key.offset;
|
||||||
|
if (del) {
|
||||||
|
btrfs_release_path(root, path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disk_ref = btrfs_item_ptr(path->nodes[0],
|
||||||
|
path->slots[0],
|
||||||
|
struct btrfs_extent_ref);
|
||||||
|
if (match_extent_ref(path->nodes[0], disk_ref, &ref)) {
|
||||||
|
ret = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||||
|
key.offset = found_key.offset + 1;
|
||||||
|
btrfs_release_path(root, path);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int btrfs_insert_extent_backref(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
struct btrfs_path *path, u64 bytenr,
|
||||||
|
u64 root_objectid, u64 ref_generation,
|
||||||
|
u64 owner, u64 owner_offset)
|
||||||
{
|
{
|
||||||
u64 hash;
|
u64 hash;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_extent_ref ref;
|
struct btrfs_extent_ref ref;
|
||||||
struct extent_buffer *l;
|
struct btrfs_extent_ref *disk_ref;
|
||||||
struct btrfs_extent_item *item;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
btrfs_set_stack_ref_root(&ref, root_objectid);
|
btrfs_set_stack_ref_root(&ref, root_objectid);
|
||||||
btrfs_set_stack_ref_generation(&ref, root_generation);
|
btrfs_set_stack_ref_generation(&ref, ref_generation);
|
||||||
btrfs_set_stack_ref_objectid(&ref, owner);
|
btrfs_set_stack_ref_objectid(&ref, owner);
|
||||||
btrfs_set_stack_ref_offset(&ref, owner_offset);
|
btrfs_set_stack_ref_offset(&ref, owner_offset);
|
||||||
|
|
||||||
ret = btrfs_name_hash(&ref, sizeof(ref), &hash);
|
hash = hash_extent_ref(root_objectid, ref_generation, owner,
|
||||||
|
owner_offset);
|
||||||
key.offset = hash;
|
key.offset = hash;
|
||||||
key.objectid = bytenr;
|
key.objectid = bytenr;
|
||||||
key.type = BTRFS_EXTENT_REF_KEY;
|
key.type = BTRFS_EXTENT_REF_KEY;
|
||||||
|
|
||||||
ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(ref));
|
ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(ref));
|
||||||
while (ret == -EEXIST) {
|
while (ret == -EEXIST) {
|
||||||
|
disk_ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
|
||||||
|
struct btrfs_extent_ref);
|
||||||
|
if (match_extent_ref(path->nodes[0], disk_ref, &ref))
|
||||||
|
goto out;
|
||||||
|
key.offset++;
|
||||||
|
btrfs_release_path(root, path);
|
||||||
|
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
||||||
|
sizeof(ref));
|
||||||
}
|
}
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
disk_ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
|
||||||
|
struct btrfs_extent_ref);
|
||||||
|
write_extent_buffer(path->nodes[0], &ref, (unsigned long)disk_ref,
|
||||||
|
sizeof(ref));
|
||||||
|
btrfs_mark_buffer_dirty(path->nodes[0]);
|
||||||
|
out:
|
||||||
|
btrfs_release_path(root, path);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
u64 bytenr, u64 num_bytes,
|
u64 bytenr, u64 num_bytes,
|
||||||
u64 root_objectid, u64 root_generation,
|
u64 root_objectid, u64 ref_generation,
|
||||||
u64 owner, u64 owner_offset)
|
u64 owner, u64 owner_offset)
|
||||||
{
|
{
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
@ -441,6 +539,11 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
|||||||
btrfs_mark_buffer_dirty(path->nodes[0]);
|
btrfs_mark_buffer_dirty(path->nodes[0]);
|
||||||
|
|
||||||
btrfs_release_path(root->fs_info->extent_root, path);
|
btrfs_release_path(root->fs_info->extent_root, path);
|
||||||
|
|
||||||
|
ret = btrfs_insert_extent_backref(trans, root->fs_info->extent_root,
|
||||||
|
path, bytenr, root_objectid,
|
||||||
|
ref_generation, owner, owner_offset);
|
||||||
|
BUG_ON(ret);
|
||||||
finish_current_insert(trans, root->fs_info->extent_root);
|
finish_current_insert(trans, root->fs_info->extent_root);
|
||||||
del_pending_extents(trans, root->fs_info->extent_root);
|
del_pending_extents(trans, root->fs_info->extent_root);
|
||||||
|
|
||||||
@ -489,10 +592,29 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
|
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root)
|
struct btrfs_root *root, u64 owner_objectid)
|
||||||
{
|
{
|
||||||
|
u64 generation;
|
||||||
|
u64 key_objectid;
|
||||||
|
u64 level;
|
||||||
|
u32 nritems;
|
||||||
|
struct btrfs_disk_key disk_key;
|
||||||
|
|
||||||
|
level = btrfs_header_level(root->node);
|
||||||
|
generation = trans->transid;
|
||||||
|
nritems = btrfs_header_nritems(root->node);
|
||||||
|
if (nritems > 0) {
|
||||||
|
if (level == 0)
|
||||||
|
btrfs_item_key(root->node, &disk_key, 0);
|
||||||
|
else
|
||||||
|
btrfs_node_key(root->node, &disk_key, 0);
|
||||||
|
key_objectid = btrfs_disk_key_objectid(&disk_key);
|
||||||
|
} else {
|
||||||
|
key_objectid = 0;
|
||||||
|
}
|
||||||
return btrfs_inc_extent_ref(trans, root, root->node->start,
|
return btrfs_inc_extent_ref(trans, root, root->node->start,
|
||||||
root->node->len);
|
root->node->len, owner_objectid,
|
||||||
|
generation, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||||
@ -506,7 +628,6 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|||||||
int level;
|
int level;
|
||||||
int ret;
|
int ret;
|
||||||
int faili;
|
int faili;
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!root->ref_cows)
|
if (!root->ref_cows)
|
||||||
return 0;
|
return 0;
|
||||||
@ -528,7 +649,9 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|||||||
if (disk_bytenr == 0)
|
if (disk_bytenr == 0)
|
||||||
continue;
|
continue;
|
||||||
ret = btrfs_inc_extent_ref(trans, root, disk_bytenr,
|
ret = btrfs_inc_extent_ref(trans, root, disk_bytenr,
|
||||||
btrfs_file_extent_disk_num_bytes(buf, fi));
|
btrfs_file_extent_disk_num_bytes(buf, fi),
|
||||||
|
root->root_key.objectid, trans->transid,
|
||||||
|
key.objectid, key.offset);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
faili = i;
|
faili = i;
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -536,7 +659,9 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|||||||
} else {
|
} else {
|
||||||
bytenr = btrfs_node_blockptr(buf, i);
|
bytenr = btrfs_node_blockptr(buf, i);
|
||||||
ret = btrfs_inc_extent_ref(trans, root, bytenr,
|
ret = btrfs_inc_extent_ref(trans, root, bytenr,
|
||||||
btrfs_level_size(root, level - 1));
|
btrfs_level_size(root, level - 1),
|
||||||
|
root->root_key.objectid,
|
||||||
|
trans->transid, 0, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
faili = i;
|
faili = i;
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -546,6 +671,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
|
#if 0
|
||||||
for (i =0; i < faili; i++) {
|
for (i =0; i < faili; i++) {
|
||||||
if (level == 0) {
|
if (level == 0) {
|
||||||
u64 disk_bytenr;
|
u64 disk_bytenr;
|
||||||
@ -571,6 +697,7 @@ fail:
|
|||||||
BUG_ON(err);
|
BUG_ON(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,18 +936,18 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
|
|||||||
static int finish_current_insert(struct btrfs_trans_handle *trans, struct
|
static int finish_current_insert(struct btrfs_trans_handle *trans, struct
|
||||||
btrfs_root *extent_root)
|
btrfs_root *extent_root)
|
||||||
{
|
{
|
||||||
|
u64 start;
|
||||||
|
u64 end;
|
||||||
|
struct btrfs_fs_info *info = extent_root->fs_info;
|
||||||
|
struct btrfs_path *path;
|
||||||
struct btrfs_key ins;
|
struct btrfs_key ins;
|
||||||
struct btrfs_extent_item extent_item;
|
struct btrfs_extent_item extent_item;
|
||||||
int ret;
|
int ret;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u64 start;
|
|
||||||
u64 end;
|
|
||||||
struct btrfs_fs_info *info = extent_root->fs_info;
|
|
||||||
|
|
||||||
btrfs_set_stack_extent_refs(&extent_item, 1);
|
btrfs_set_stack_extent_refs(&extent_item, 1);
|
||||||
btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
|
btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
|
||||||
btrfs_set_stack_extent_owner(&extent_item,
|
path = btrfs_alloc_path();
|
||||||
extent_root->root_key.objectid);
|
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
ret = find_first_extent_bit(&info->extent_ins, 0, &start,
|
ret = find_first_extent_bit(&info->extent_ins, 0, &start,
|
||||||
@ -834,7 +961,12 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
|
|||||||
&extent_item, sizeof(extent_item));
|
&extent_item, sizeof(extent_item));
|
||||||
clear_extent_bits(&info->extent_ins, start, end, EXTENT_LOCKED,
|
clear_extent_bits(&info->extent_ins, start, end, EXTENT_LOCKED,
|
||||||
GFP_NOFS);
|
GFP_NOFS);
|
||||||
|
err = btrfs_insert_extent_backref(trans, extent_root, path,
|
||||||
|
start, extent_root->root_key.objectid,
|
||||||
|
0, 0, 0);
|
||||||
|
BUG_ON(err);
|
||||||
}
|
}
|
||||||
|
btrfs_free_path(path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,7 +1003,9 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes,
|
|||||||
* remove an extent from the root, returns 0 on success
|
* remove an extent from the root, returns 0 on success
|
||||||
*/
|
*/
|
||||||
static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||||
*root, u64 bytenr, u64 num_bytes, int pin,
|
*root, u64 bytenr, u64 num_bytes,
|
||||||
|
u64 root_objectid, u64 ref_generation,
|
||||||
|
u64 owner_objectid, u64 owner_offset, int pin,
|
||||||
int mark_free)
|
int mark_free)
|
||||||
{
|
{
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
@ -891,6 +1025,24 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
if (!path)
|
if (!path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (ref_generation && owner_objectid == 0 && root_objectid == 3) {
|
||||||
|
//printk("drop backref root %Lu gen %Lu byte %Lu\n", root_objectid, ref_generation, bytenr );
|
||||||
|
}
|
||||||
|
ret = lookup_extent_backref(trans, extent_root, path,
|
||||||
|
bytenr, root_objectid,
|
||||||
|
ref_generation,
|
||||||
|
owner_objectid, owner_offset, 1);
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = btrfs_del_item(trans, extent_root, path);
|
||||||
|
} else {
|
||||||
|
btrfs_print_leaf(extent_root, path->nodes[0]);
|
||||||
|
WARN_ON(1);
|
||||||
|
printk("Unable to find ref byte nr %Lu root %Lu "
|
||||||
|
" gen %Lu owner %Lu offset %Lu\n", bytenr,
|
||||||
|
root_objectid, ref_generation, owner_objectid,
|
||||||
|
owner_offset);
|
||||||
|
}
|
||||||
|
btrfs_release_path(extent_root, path);
|
||||||
ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1);
|
ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
@ -965,7 +1117,9 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
|
|||||||
clear_extent_bits(pending_del, start, end, EXTENT_LOCKED,
|
clear_extent_bits(pending_del, start, end, EXTENT_LOCKED,
|
||||||
GFP_NOFS);
|
GFP_NOFS);
|
||||||
ret = __free_extent(trans, extent_root,
|
ret = __free_extent(trans, extent_root,
|
||||||
start, end + 1 - start, 0, 0);
|
start, end + 1 - start,
|
||||||
|
extent_root->root_key.objectid,
|
||||||
|
0, 0, 0, 0, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
err = ret;
|
err = ret;
|
||||||
}
|
}
|
||||||
@ -976,18 +1130,25 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
|
|||||||
* remove an extent from the root, returns 0 on success
|
* remove an extent from the root, returns 0 on success
|
||||||
*/
|
*/
|
||||||
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||||
*root, u64 bytenr, u64 num_bytes, int pin)
|
*root, u64 bytenr, u64 num_bytes,
|
||||||
|
u64 root_objectid, u64 ref_generation,
|
||||||
|
u64 owner_objectid, u64 owner_offset, int pin)
|
||||||
{
|
{
|
||||||
struct btrfs_root *extent_root = root->fs_info->extent_root;
|
struct btrfs_root *extent_root = root->fs_info->extent_root;
|
||||||
int pending_ret;
|
int pending_ret;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
WARN_ON(num_bytes < root->sectorsize);
|
WARN_ON(num_bytes < root->sectorsize);
|
||||||
|
if (!root->ref_cows)
|
||||||
|
ref_generation = 0;
|
||||||
|
|
||||||
if (root == extent_root) {
|
if (root == extent_root) {
|
||||||
pin_down_bytes(root, bytenr, num_bytes, 1);
|
pin_down_bytes(root, bytenr, num_bytes, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ret = __free_extent(trans, root, bytenr, num_bytes, pin, pin == 0);
|
ret = __free_extent(trans, root, bytenr, num_bytes, root_objectid,
|
||||||
|
ref_generation, owner_objectid, owner_offset,
|
||||||
|
pin, pin == 0);
|
||||||
pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
|
pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
|
||||||
return ret ? ret : pending_ret;
|
return ret ? ret : pending_ret;
|
||||||
}
|
}
|
||||||
@ -1080,23 +1241,26 @@ check_failed:
|
|||||||
btrfs_item_key_to_cpu(l, &key, path->slots[0]);
|
btrfs_item_key_to_cpu(l, &key, path->slots[0]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* a rare case, go back one key if we hit a block group item
|
* walk backwards to find the first extent item key
|
||||||
* instead of an extent item
|
|
||||||
*/
|
*/
|
||||||
if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY &&
|
while(btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY) {
|
||||||
key.objectid + key.offset >= search_start) {
|
if (path->slots[0] == 0) {
|
||||||
ins->objectid = key.objectid;
|
ret = btrfs_prev_leaf(root, path);
|
||||||
ins->offset = key.offset - 1;
|
if (ret != 0) {
|
||||||
btrfs_release_path(root, path);
|
ret = btrfs_search_slot(trans, root, ins,
|
||||||
ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
|
path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
if (path->slots[0] > 0)
|
||||||
if (path->slots[0] > 0) {
|
path->slots[0]--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
path->slots[0]--;
|
path->slots[0]--;
|
||||||
}
|
}
|
||||||
|
l = path->nodes[0];
|
||||||
|
btrfs_item_key_to_cpu(l, &key, path->slots[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
l = path->nodes[0];
|
l = path->nodes[0];
|
||||||
slot = path->slots[0];
|
slot = path->slots[0];
|
||||||
@ -1146,7 +1310,8 @@ check_failed:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY) {
|
if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY) {
|
||||||
if (!start_found) {
|
if (!start_found && btrfs_key_type(&key) ==
|
||||||
|
BTRFS_BLOCK_GROUP_ITEM_KEY) {
|
||||||
last_byte = key.objectid;
|
last_byte = key.objectid;
|
||||||
start_found = 1;
|
start_found = 1;
|
||||||
}
|
}
|
||||||
@ -1244,8 +1409,10 @@ error:
|
|||||||
* returns 0 if everything worked, non-zero otherwise.
|
* returns 0 if everything worked, non-zero otherwise.
|
||||||
*/
|
*/
|
||||||
int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
|
int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, u64 owner,
|
struct btrfs_root *root,
|
||||||
u64 num_bytes, u64 empty_size, u64 hint_byte,
|
u64 num_bytes, u64 root_objectid, u64 ref_generation,
|
||||||
|
u64 owner, u64 owner_offset,
|
||||||
|
u64 empty_size, u64 hint_byte,
|
||||||
u64 search_end, struct btrfs_key *ins, int data)
|
u64 search_end, struct btrfs_key *ins, int data)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -1255,9 +1422,9 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
|
|||||||
struct btrfs_fs_info *info = root->fs_info;
|
struct btrfs_fs_info *info = root->fs_info;
|
||||||
struct btrfs_root *extent_root = info->extent_root;
|
struct btrfs_root *extent_root = info->extent_root;
|
||||||
struct btrfs_extent_item extent_item;
|
struct btrfs_extent_item extent_item;
|
||||||
|
struct btrfs_path *path;
|
||||||
|
|
||||||
btrfs_set_stack_extent_refs(&extent_item, 1);
|
btrfs_set_stack_extent_refs(&extent_item, 1);
|
||||||
btrfs_set_stack_extent_owner(&extent_item, owner);
|
|
||||||
|
|
||||||
WARN_ON(num_bytes < root->sectorsize);
|
WARN_ON(num_bytes < root->sectorsize);
|
||||||
ret = find_free_extent(trans, root, num_bytes, empty_size,
|
ret = find_free_extent(trans, root, num_bytes, empty_size,
|
||||||
@ -1296,8 +1463,16 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
|
|||||||
|
|
||||||
trans->alloc_exclude_start = 0;
|
trans->alloc_exclude_start = 0;
|
||||||
trans->alloc_exclude_nr = 0;
|
trans->alloc_exclude_nr = 0;
|
||||||
|
BUG_ON(ret);
|
||||||
|
|
||||||
|
path = btrfs_alloc_path();
|
||||||
|
BUG_ON(!path);
|
||||||
|
ret = btrfs_insert_extent_backref(trans, extent_root, path,
|
||||||
|
ins->objectid, root_objectid,
|
||||||
|
ref_generation, owner, owner_offset);
|
||||||
|
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
btrfs_free_path(path);
|
||||||
finish_current_insert(trans, extent_root);
|
finish_current_insert(trans, extent_root);
|
||||||
pending_ret = del_pending_extents(trans, extent_root);
|
pending_ret = del_pending_extents(trans, extent_root);
|
||||||
|
|
||||||
@ -1321,15 +1496,43 @@ update_block:
|
|||||||
*/
|
*/
|
||||||
struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
u32 blocksize, u64 hint,
|
u32 blocksize,
|
||||||
|
u64 root_objectid, u64 hint,
|
||||||
|
u64 empty_size)
|
||||||
|
{
|
||||||
|
u64 ref_generation;
|
||||||
|
|
||||||
|
if (root->ref_cows)
|
||||||
|
ref_generation = trans->transid;
|
||||||
|
else
|
||||||
|
ref_generation = 0;
|
||||||
|
|
||||||
|
|
||||||
|
return __btrfs_alloc_free_block(trans, root, blocksize, root_objectid,
|
||||||
|
ref_generation, 0, 0, hint, empty_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* helper function to allocate a block for a given tree
|
||||||
|
* returns the tree buffer or NULL.
|
||||||
|
*/
|
||||||
|
struct extent_buffer *__btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
|
u32 blocksize,
|
||||||
|
u64 root_objectid,
|
||||||
|
u64 ref_generation,
|
||||||
|
u64 first_objectid,
|
||||||
|
int level,
|
||||||
|
u64 hint,
|
||||||
u64 empty_size)
|
u64 empty_size)
|
||||||
{
|
{
|
||||||
struct btrfs_key ins;
|
struct btrfs_key ins;
|
||||||
int ret;
|
int ret;
|
||||||
struct extent_buffer *buf;
|
struct extent_buffer *buf;
|
||||||
|
|
||||||
ret = btrfs_alloc_extent(trans, root, root->root_key.objectid,
|
ret = btrfs_alloc_extent(trans, root, blocksize,
|
||||||
blocksize, empty_size, hint,
|
root_objectid, ref_generation,
|
||||||
|
first_objectid, level, empty_size, hint,
|
||||||
(u64)-1, &ins, 0);
|
(u64)-1, &ins, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
BUG_ON(ret > 0);
|
BUG_ON(ret > 0);
|
||||||
@ -1337,7 +1540,9 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
|||||||
}
|
}
|
||||||
buf = btrfs_find_create_tree_block(root, ins.objectid, blocksize);
|
buf = btrfs_find_create_tree_block(root, ins.objectid, blocksize);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
btrfs_free_extent(trans, root, ins.objectid, blocksize, 0);
|
btrfs_free_extent(trans, root, ins.objectid, blocksize,
|
||||||
|
root->root_key.objectid, ref_generation,
|
||||||
|
0, 0, 0);
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
btrfs_set_buffer_uptodate(buf);
|
btrfs_set_buffer_uptodate(buf);
|
||||||
@ -1355,6 +1560,8 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
|||||||
static int drop_leaf_ref(struct btrfs_trans_handle *trans,
|
static int drop_leaf_ref(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, struct extent_buffer *leaf)
|
struct btrfs_root *root, struct extent_buffer *leaf)
|
||||||
{
|
{
|
||||||
|
u64 leaf_owner;
|
||||||
|
u64 leaf_generation;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_file_extent_item *fi;
|
struct btrfs_file_extent_item *fi;
|
||||||
int i;
|
int i;
|
||||||
@ -1363,6 +1570,9 @@ static int drop_leaf_ref(struct btrfs_trans_handle *trans,
|
|||||||
|
|
||||||
BUG_ON(!btrfs_is_leaf(leaf));
|
BUG_ON(!btrfs_is_leaf(leaf));
|
||||||
nritems = btrfs_header_nritems(leaf);
|
nritems = btrfs_header_nritems(leaf);
|
||||||
|
leaf_owner = btrfs_header_owner(leaf);
|
||||||
|
leaf_generation = btrfs_header_generation(leaf);
|
||||||
|
|
||||||
for (i = 0; i < nritems; i++) {
|
for (i = 0; i < nritems; i++) {
|
||||||
u64 disk_bytenr;
|
u64 disk_bytenr;
|
||||||
|
|
||||||
@ -1381,7 +1591,9 @@ static int drop_leaf_ref(struct btrfs_trans_handle *trans,
|
|||||||
if (disk_bytenr == 0)
|
if (disk_bytenr == 0)
|
||||||
continue;
|
continue;
|
||||||
ret = btrfs_free_extent(trans, root, disk_bytenr,
|
ret = btrfs_free_extent(trans, root, disk_bytenr,
|
||||||
btrfs_file_extent_disk_num_bytes(leaf, fi), 0);
|
btrfs_file_extent_disk_num_bytes(leaf, fi),
|
||||||
|
leaf_owner, leaf_generation,
|
||||||
|
key.objectid, key.offset, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -1423,9 +1635,12 @@ static void reada_walk_down(struct btrfs_root *root,
|
|||||||
static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||||
*root, struct btrfs_path *path, int *level)
|
*root, struct btrfs_path *path, int *level)
|
||||||
{
|
{
|
||||||
|
u64 root_owner;
|
||||||
|
u64 root_gen;
|
||||||
|
u64 bytenr;
|
||||||
struct extent_buffer *next;
|
struct extent_buffer *next;
|
||||||
struct extent_buffer *cur;
|
struct extent_buffer *cur;
|
||||||
u64 bytenr;
|
struct extent_buffer *parent;
|
||||||
u32 blocksize;
|
u32 blocksize;
|
||||||
int ret;
|
int ret;
|
||||||
u32 refs;
|
u32 refs;
|
||||||
@ -1466,9 +1681,13 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
ret = lookup_extent_ref(trans, root, bytenr, blocksize, &refs);
|
ret = lookup_extent_ref(trans, root, bytenr, blocksize, &refs);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
if (refs != 1) {
|
if (refs != 1) {
|
||||||
|
parent = path->nodes[*level];
|
||||||
|
root_owner = btrfs_header_owner(parent);
|
||||||
|
root_gen = btrfs_header_generation(parent);
|
||||||
path->slots[*level]++;
|
path->slots[*level]++;
|
||||||
ret = btrfs_free_extent(trans, root, bytenr,
|
ret = btrfs_free_extent(trans, root, bytenr,
|
||||||
blocksize, 1);
|
blocksize, root_owner,
|
||||||
|
root_gen, 0, 0, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1484,10 +1703,16 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
blocksize, &refs);
|
blocksize, &refs);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
if (refs != 1) {
|
if (refs != 1) {
|
||||||
|
parent = path->nodes[*level];
|
||||||
|
root_owner = btrfs_header_owner(parent);
|
||||||
|
root_gen = btrfs_header_generation(parent);
|
||||||
|
|
||||||
path->slots[*level]++;
|
path->slots[*level]++;
|
||||||
free_extent_buffer(next);
|
free_extent_buffer(next);
|
||||||
ret = btrfs_free_extent(trans, root,
|
ret = btrfs_free_extent(trans, root, bytenr,
|
||||||
bytenr, blocksize, 1);
|
blocksize,
|
||||||
|
root_owner,
|
||||||
|
root_gen, 0, 0, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1502,8 +1727,19 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
out:
|
out:
|
||||||
WARN_ON(*level < 0);
|
WARN_ON(*level < 0);
|
||||||
WARN_ON(*level >= BTRFS_MAX_LEVEL);
|
WARN_ON(*level >= BTRFS_MAX_LEVEL);
|
||||||
|
|
||||||
|
if (path->nodes[*level] == root->node) {
|
||||||
|
root_owner = root->root_key.objectid;
|
||||||
|
parent = path->nodes[*level];
|
||||||
|
} else {
|
||||||
|
parent = path->nodes[*level + 1];
|
||||||
|
root_owner = btrfs_header_owner(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
root_gen = btrfs_header_generation(parent);
|
||||||
ret = btrfs_free_extent(trans, root, path->nodes[*level]->start,
|
ret = btrfs_free_extent(trans, root, path->nodes[*level]->start,
|
||||||
path->nodes[*level]->len, 1);
|
path->nodes[*level]->len,
|
||||||
|
root_owner, root_gen, 0, 0, 1);
|
||||||
free_extent_buffer(path->nodes[*level]);
|
free_extent_buffer(path->nodes[*level]);
|
||||||
path->nodes[*level] = NULL;
|
path->nodes[*level] = NULL;
|
||||||
*level += 1;
|
*level += 1;
|
||||||
@ -1519,10 +1755,12 @@ out:
|
|||||||
static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||||
*root, struct btrfs_path *path, int *level)
|
*root, struct btrfs_path *path, int *level)
|
||||||
{
|
{
|
||||||
|
u64 root_owner;
|
||||||
|
u64 root_gen;
|
||||||
|
struct btrfs_root_item *root_item = &root->root_item;
|
||||||
int i;
|
int i;
|
||||||
int slot;
|
int slot;
|
||||||
int ret;
|
int ret;
|
||||||
struct btrfs_root_item *root_item = &root->root_item;
|
|
||||||
|
|
||||||
for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
|
for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
|
||||||
slot = path->slots[i];
|
slot = path->slots[i];
|
||||||
@ -1539,9 +1777,20 @@ static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
|||||||
root_item->drop_level = i;
|
root_item->drop_level = i;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
if (path->nodes[*level] == root->node) {
|
||||||
|
root_owner = root->root_key.objectid;
|
||||||
|
root_gen =
|
||||||
|
btrfs_header_generation(path->nodes[*level]);
|
||||||
|
} else {
|
||||||
|
struct extent_buffer *node;
|
||||||
|
node = path->nodes[*level + 1];
|
||||||
|
root_owner = btrfs_header_owner(node);
|
||||||
|
root_gen = btrfs_header_generation(node);
|
||||||
|
}
|
||||||
ret = btrfs_free_extent(trans, root,
|
ret = btrfs_free_extent(trans, root,
|
||||||
path->nodes[*level]->start,
|
path->nodes[*level]->start,
|
||||||
path->nodes[*level]->len, 1);
|
path->nodes[*level]->len,
|
||||||
|
root_owner, root_gen, 0, 0, 1);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
free_extent_buffer(path->nodes[*level]);
|
free_extent_buffer(path->nodes[*level]);
|
||||||
path->nodes[*level] = NULL;
|
path->nodes[*level] = NULL;
|
||||||
|
@ -496,7 +496,10 @@ next_slot:
|
|||||||
sizeof(old));
|
sizeof(old));
|
||||||
if (disk_bytenr != 0) {
|
if (disk_bytenr != 0) {
|
||||||
ret = btrfs_inc_extent_ref(trans, root,
|
ret = btrfs_inc_extent_ref(trans, root,
|
||||||
disk_bytenr, disk_num_bytes);
|
disk_bytenr, disk_num_bytes,
|
||||||
|
root->root_key.objectid,
|
||||||
|
trans->transid,
|
||||||
|
key.objectid, end);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,6 +544,14 @@ next_slot:
|
|||||||
u64 disk_bytenr = 0;
|
u64 disk_bytenr = 0;
|
||||||
u64 disk_num_bytes = 0;
|
u64 disk_num_bytes = 0;
|
||||||
u64 extent_num_bytes = 0;
|
u64 extent_num_bytes = 0;
|
||||||
|
u64 root_gen;
|
||||||
|
|
||||||
|
if (leaf != root->node) {
|
||||||
|
root_gen =
|
||||||
|
btrfs_header_generation(path->nodes[1]);
|
||||||
|
} else {
|
||||||
|
root_gen = btrfs_header_generation(leaf);
|
||||||
|
}
|
||||||
if (found_extent) {
|
if (found_extent) {
|
||||||
disk_bytenr =
|
disk_bytenr =
|
||||||
btrfs_file_extent_disk_bytenr(leaf,
|
btrfs_file_extent_disk_bytenr(leaf,
|
||||||
@ -562,8 +573,11 @@ next_slot:
|
|||||||
if (found_extent && disk_bytenr != 0) {
|
if (found_extent && disk_bytenr != 0) {
|
||||||
inode->i_blocks -= extent_num_bytes >> 9;
|
inode->i_blocks -= extent_num_bytes >> 9;
|
||||||
ret = btrfs_free_extent(trans, root,
|
ret = btrfs_free_extent(trans, root,
|
||||||
disk_bytenr,
|
disk_bytenr,
|
||||||
disk_num_bytes, 0);
|
disk_num_bytes,
|
||||||
|
root->root_key.objectid,
|
||||||
|
root_gen, inode->i_ino,
|
||||||
|
key.offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
@ -93,7 +93,9 @@ static int run_delalloc_range(struct inode *inode, u64 start, u64 end)
|
|||||||
if (alloc_hint == EXTENT_MAP_INLINE)
|
if (alloc_hint == EXTENT_MAP_INLINE)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = btrfs_alloc_extent(trans, root, inode->i_ino, num_bytes, 0,
|
ret = btrfs_alloc_extent(trans, root, num_bytes,
|
||||||
|
root->root_key.objectid, trans->transid,
|
||||||
|
inode->i_ino, start, 0,
|
||||||
alloc_hint, (u64)-1, &ins, 1);
|
alloc_hint, (u64)-1, &ins, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
@ -560,6 +562,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
|
|||||||
u64 extent_start = 0;
|
u64 extent_start = 0;
|
||||||
u64 extent_num_bytes = 0;
|
u64 extent_num_bytes = 0;
|
||||||
u64 item_end = 0;
|
u64 item_end = 0;
|
||||||
|
u64 root_gen = 0;
|
||||||
int found_extent;
|
int found_extent;
|
||||||
int del_item;
|
int del_item;
|
||||||
int extent_type = -1;
|
int extent_type = -1;
|
||||||
@ -670,6 +673,15 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
|
|||||||
found_extent = 1;
|
found_extent = 1;
|
||||||
inode->i_blocks -= num_dec;
|
inode->i_blocks -= num_dec;
|
||||||
}
|
}
|
||||||
|
if (leaf == root->node) {
|
||||||
|
root_gen =
|
||||||
|
btrfs_header_generation(leaf);
|
||||||
|
} else {
|
||||||
|
struct extent_buffer *parent;
|
||||||
|
parent = path->nodes[1];
|
||||||
|
root_gen =
|
||||||
|
btrfs_header_generation(parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE &&
|
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE &&
|
||||||
!del_item) {
|
!del_item) {
|
||||||
@ -690,7 +702,10 @@ delete:
|
|||||||
btrfs_release_path(root, path);
|
btrfs_release_path(root, path);
|
||||||
if (found_extent) {
|
if (found_extent) {
|
||||||
ret = btrfs_free_extent(trans, root, extent_start,
|
ret = btrfs_free_extent(trans, root, extent_start,
|
||||||
extent_num_bytes, 0);
|
extent_num_bytes,
|
||||||
|
root->root_key.objectid,
|
||||||
|
root_gen, inode->i_ino,
|
||||||
|
found_key.offset, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1900,7 +1915,14 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
|
|||||||
trans = btrfs_start_transaction(root, 1);
|
trans = btrfs_start_transaction(root, 1);
|
||||||
BUG_ON(!trans);
|
BUG_ON(!trans);
|
||||||
|
|
||||||
leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0, 0);
|
ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
|
||||||
|
0, &objectid);
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
leaf = __btrfs_alloc_free_block(trans, root, root->leafsize,
|
||||||
|
objectid, trans->transid, 0, 0,
|
||||||
|
0, 0);
|
||||||
if (IS_ERR(leaf))
|
if (IS_ERR(leaf))
|
||||||
return PTR_ERR(leaf);
|
return PTR_ERR(leaf);
|
||||||
|
|
||||||
@ -1908,7 +1930,8 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
|
|||||||
btrfs_set_header_level(leaf, 0);
|
btrfs_set_header_level(leaf, 0);
|
||||||
btrfs_set_header_bytenr(leaf, leaf->start);
|
btrfs_set_header_bytenr(leaf, leaf->start);
|
||||||
btrfs_set_header_generation(leaf, trans->transid);
|
btrfs_set_header_generation(leaf, trans->transid);
|
||||||
btrfs_set_header_owner(leaf, root->root_key.objectid);
|
btrfs_set_header_owner(leaf, objectid);
|
||||||
|
|
||||||
write_extent_buffer(leaf, root->fs_info->fsid,
|
write_extent_buffer(leaf, root->fs_info->fsid,
|
||||||
(unsigned long)btrfs_header_fsid(leaf),
|
(unsigned long)btrfs_header_fsid(leaf),
|
||||||
BTRFS_FSID_SIZE);
|
BTRFS_FSID_SIZE);
|
||||||
@ -1933,11 +1956,6 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
|
|||||||
free_extent_buffer(leaf);
|
free_extent_buffer(leaf);
|
||||||
leaf = NULL;
|
leaf = NULL;
|
||||||
|
|
||||||
ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
|
|
||||||
0, &objectid);
|
|
||||||
if (ret)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
btrfs_set_root_dirid(&root_item, new_dirid);
|
btrfs_set_root_dirid(&root_item, new_dirid);
|
||||||
|
|
||||||
key.objectid = objectid;
|
key.objectid = objectid;
|
||||||
@ -2056,7 +2074,7 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
ret = btrfs_inc_root_ref(trans, root);
|
ret = btrfs_inc_root_ref(trans, root, objectid);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
fail:
|
fail:
|
||||||
|
@ -33,6 +33,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
|
|||||||
struct btrfs_file_extent_item *fi;
|
struct btrfs_file_extent_item *fi;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_key found_key;
|
struct btrfs_key found_key;
|
||||||
|
struct btrfs_extent_ref *ref;
|
||||||
u32 type;
|
u32 type;
|
||||||
|
|
||||||
printk("leaf %llu total ptrs %d free space %d\n",
|
printk("leaf %llu total ptrs %d free space %d\n",
|
||||||
@ -73,6 +74,15 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
|
|||||||
printk("\t\textent data refs %u\n",
|
printk("\t\textent data refs %u\n",
|
||||||
btrfs_extent_refs(l, ei));
|
btrfs_extent_refs(l, ei));
|
||||||
break;
|
break;
|
||||||
|
case BTRFS_EXTENT_REF_KEY:
|
||||||
|
ref = btrfs_item_ptr(l, i, struct btrfs_extent_ref);
|
||||||
|
printk("\t\textent back ref root %llu gen %llu "
|
||||||
|
"owner %llu offset %llu\n",
|
||||||
|
(unsigned long long)btrfs_ref_root(l, ref),
|
||||||
|
(unsigned long long)btrfs_ref_generation(l, ref),
|
||||||
|
(unsigned long long)btrfs_ref_objectid(l, ref),
|
||||||
|
(unsigned long long)btrfs_ref_offset(l, ref));
|
||||||
|
break;
|
||||||
|
|
||||||
case BTRFS_EXTENT_DATA_KEY:
|
case BTRFS_EXTENT_DATA_KEY:
|
||||||
fi = btrfs_item_ptr(l, i,
|
fi = btrfs_item_ptr(l, i,
|
||||||
|
@ -78,6 +78,8 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (*level == 1) {
|
if (*level == 1) {
|
||||||
|
WARN_ON(btrfs_header_generation(path->nodes[*level]) !=
|
||||||
|
trans->transid);
|
||||||
ret = btrfs_realloc_node(trans, root,
|
ret = btrfs_realloc_node(trans, root,
|
||||||
path->nodes[*level],
|
path->nodes[*level],
|
||||||
path->slots[*level],
|
path->slots[*level],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user