Btrfs: Full back reference support

This patch makes the back reference system to explicit record the
location of parent node for all types of extents. The location of
parent node is placed into the offset field of backref key. Every
time a tree block is balanced, the back references for the affected
lower level extents are updated.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
Zheng Yan 2008-09-23 13:14:14 -04:00 committed by Chris Mason
parent 1c2308f8e7
commit 31840ae1a6
10 changed files with 1066 additions and 722 deletions

View file

@ -125,7 +125,6 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
u32 nritems; u32 nritems;
int ret = 0; int ret = 0;
int level; int level;
struct btrfs_key first_key;
struct btrfs_root *new_root; struct btrfs_root *new_root;
new_root = kmalloc(sizeof(*new_root), GFP_NOFS); new_root = kmalloc(sizeof(*new_root), GFP_NOFS);
@ -141,18 +140,10 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
level = btrfs_header_level(buf); level = btrfs_header_level(buf);
nritems = btrfs_header_nritems(buf); nritems = btrfs_header_nritems(buf);
if (nritems) {
if (level == 0) cow = btrfs_alloc_free_block(trans, new_root, buf->len, 0,
btrfs_item_key_to_cpu(buf, &first_key, 0); new_root_objectid, trans->transid,
else level, buf->start, 0);
btrfs_node_key_to_cpu(buf, &first_key, 0);
} else {
first_key.objectid = 0;
}
cow = btrfs_alloc_free_block(trans, new_root, buf->len,
new_root_objectid,
trans->transid, first_key.objectid,
level, buf->start, 0);
if (IS_ERR(cow)) { if (IS_ERR(cow)) {
kfree(new_root); kfree(new_root);
return PTR_ERR(cow); return PTR_ERR(cow);
@ -165,7 +156,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN); btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
WARN_ON(btrfs_header_generation(buf) > trans->transid); WARN_ON(btrfs_header_generation(buf) > trans->transid);
ret = btrfs_inc_ref(trans, new_root, buf, 0); ret = btrfs_inc_ref(trans, new_root, buf, cow, NULL);
kfree(new_root); kfree(new_root);
if (ret) if (ret)
@ -184,39 +175,31 @@ int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans,
u64 search_start, u64 empty_size, u64 search_start, u64 empty_size,
u64 prealloc_dest) u64 prealloc_dest)
{ {
u64 root_gen; u64 parent_start;
struct extent_buffer *cow; struct extent_buffer *cow;
u32 nritems; u32 nritems;
int ret = 0; int ret = 0;
int different_trans = 0; int different_trans = 0;
int level; int level;
int unlock_orig = 0; int unlock_orig = 0;
struct btrfs_key first_key;
if (*cow_ret == buf) if (*cow_ret == buf)
unlock_orig = 1; unlock_orig = 1;
WARN_ON(!btrfs_tree_locked(buf)); WARN_ON(!btrfs_tree_locked(buf));
if (root->ref_cows) { if (parent)
root_gen = trans->transid; parent_start = parent->start;
} else { else
root_gen = 0; parent_start = 0;
}
WARN_ON(root->ref_cows && trans->transid != WARN_ON(root->ref_cows && trans->transid !=
root->fs_info->running_transaction->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);
level = btrfs_header_level(buf); level = btrfs_header_level(buf);
nritems = btrfs_header_nritems(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;
}
if (prealloc_dest) { if (prealloc_dest) {
struct btrfs_key ins; struct btrfs_key ins;
@ -224,19 +207,19 @@ int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans,
ins.offset = buf->len; ins.offset = buf->len;
ins.type = BTRFS_EXTENT_ITEM_KEY; ins.type = BTRFS_EXTENT_ITEM_KEY;
ret = btrfs_alloc_reserved_extent(trans, root, ret = btrfs_alloc_reserved_extent(trans, root, parent_start,
root->root_key.objectid, root->root_key.objectid,
root_gen, level, trans->transid, level, 0,
first_key.objectid,
&ins); &ins);
BUG_ON(ret); BUG_ON(ret);
cow = btrfs_init_new_buffer(trans, root, prealloc_dest, cow = btrfs_init_new_buffer(trans, root, prealloc_dest,
buf->len); buf->len);
} else { } else {
cow = btrfs_alloc_free_block(trans, root, buf->len, cow = btrfs_alloc_free_block(trans, root, buf->len,
parent_start,
root->root_key.objectid, root->root_key.objectid,
root_gen, first_key.objectid, trans->transid, level,
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);
@ -249,17 +232,23 @@ int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans,
WARN_ON(btrfs_header_generation(buf) > trans->transid); WARN_ON(btrfs_header_generation(buf) > trans->transid);
if (btrfs_header_generation(buf) != trans->transid) { if (btrfs_header_generation(buf) != trans->transid) {
u32 nr_extents;
different_trans = 1; different_trans = 1;
ret = btrfs_inc_ref(trans, root, buf, 1); ret = btrfs_inc_ref(trans, root, buf, cow, &nr_extents);
if (ret) if (ret)
return ret; return ret;
ret = btrfs_cache_ref(trans, root, buf, nr_extents);
WARN_ON(ret);
} else { } else {
ret = btrfs_update_ref(trans, root, buf, cow, 0, nritems);
if (ret)
return ret;
clean_tree_block(trans, root, buf); clean_tree_block(trans, root, buf);
} }
if (buf == root->node) { if (buf == root->node) {
WARN_ON(parent && parent != buf); WARN_ON(parent && parent != buf);
root_gen = btrfs_header_generation(buf);
spin_lock(&root->node_lock); spin_lock(&root->node_lock);
root->node = cow; root->node = cow;
@ -268,13 +257,14 @@ int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans,
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, root->root_key.objectid, buf->len, buf->start,
root_gen, 0, 0, 1); root->root_key.objectid,
btrfs_header_generation(buf),
0, 0, 1);
} }
free_extent_buffer(buf); free_extent_buffer(buf);
add_root_to_dirty_list(root); add_root_to_dirty_list(root);
} 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);
@ -283,8 +273,8 @@ int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans,
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, btrfs_free_extent(trans, root, buf->start, buf->len,
btrfs_header_owner(parent), root_gen, parent_start, btrfs_header_owner(parent),
0, 0, 1); btrfs_header_generation(parent), 0, 0, 1);
} }
if (unlock_orig) if (unlock_orig)
btrfs_tree_unlock(buf); btrfs_tree_unlock(buf);
@ -831,6 +821,12 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
root->node = child; root->node = child;
spin_unlock(&root->node_lock); spin_unlock(&root->node_lock);
ret = btrfs_update_extent_ref(trans, root, child->start,
mid->start, child->start,
root->root_key.objectid,
trans->transid, level - 1, 0);
BUG_ON(ret);
add_root_to_dirty_list(root); add_root_to_dirty_list(root);
btrfs_tree_unlock(child); btrfs_tree_unlock(child);
path->locks[level] = 0; path->locks[level] = 0;
@ -840,7 +836,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
/* 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, ret = btrfs_free_extent(trans, root, mid->start, mid->len,
root->root_key.objectid, mid->start, root->root_key.objectid,
btrfs_header_generation(mid), 0, 0, 1); 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);
@ -905,7 +901,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
if (wret) if (wret)
ret = wret; ret = wret;
wret = btrfs_free_extent(trans, root, bytenr, wret = btrfs_free_extent(trans, root, bytenr,
blocksize, blocksize, parent->start,
btrfs_header_owner(parent), btrfs_header_owner(parent),
generation, 0, 0, 1); generation, 0, 0, 1);
if (wret) if (wret)
@ -954,6 +950,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
if (wret) if (wret)
ret = wret; ret = wret;
wret = btrfs_free_extent(trans, root, bytenr, blocksize, wret = btrfs_free_extent(trans, root, bytenr, blocksize,
parent->start,
btrfs_header_owner(parent), btrfs_header_owner(parent),
root_gen, 0, 0, 1); root_gen, 0, 0, 1);
if (wret) if (wret)
@ -1499,6 +1496,41 @@ static int fixup_low_keys(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
/*
* update item key.
*
* This function isn't completely safe. It's the caller's responsibility
* that the new key won't break the order
*/
int btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path,
struct btrfs_key *new_key)
{
struct btrfs_disk_key disk_key;
struct extent_buffer *eb;
int slot;
eb = path->nodes[0];
slot = path->slots[0];
if (slot > 0) {
btrfs_item_key(eb, &disk_key, slot - 1);
if (comp_keys(&disk_key, new_key) >= 0)
return -1;
}
if (slot < btrfs_header_nritems(eb) - 1) {
btrfs_item_key(eb, &disk_key, slot + 1);
if (comp_keys(&disk_key, new_key) <= 0)
return -1;
}
btrfs_cpu_key_to_disk(&disk_key, new_key);
btrfs_set_item_key(eb, &disk_key, slot);
btrfs_mark_buffer_dirty(eb);
if (slot == 0)
fixup_low_keys(trans, root, path, &disk_key, 1);
return 0;
}
/* /*
* try to push data from one node into the next node left in the * try to push data from one node into the next node left in the
* tree. * tree.
@ -1558,6 +1590,10 @@ static int push_node_left(struct btrfs_trans_handle *trans,
btrfs_set_header_nritems(dst, dst_nritems + push_items); btrfs_set_header_nritems(dst, dst_nritems + push_items);
btrfs_mark_buffer_dirty(src); btrfs_mark_buffer_dirty(src);
btrfs_mark_buffer_dirty(dst); btrfs_mark_buffer_dirty(dst);
ret = btrfs_update_ref(trans, root, src, dst, dst_nritems, push_items);
BUG_ON(ret);
return ret; return ret;
} }
@ -1619,6 +1655,10 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(src); btrfs_mark_buffer_dirty(src);
btrfs_mark_buffer_dirty(dst); btrfs_mark_buffer_dirty(dst);
ret = btrfs_update_ref(trans, root, src, dst, 0, push_items);
BUG_ON(ret);
return ret; return ret;
} }
@ -1633,30 +1673,24 @@ static int noinline 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; u64 lower_gen;
struct extent_buffer *lower; struct extent_buffer *lower;
struct extent_buffer *c; struct extent_buffer *c;
struct extent_buffer *old; struct extent_buffer *old;
struct btrfs_disk_key lower_key; struct btrfs_disk_key lower_key;
int ret;
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);
if (root->ref_cows)
root_gen = trans->transid;
else
root_gen = 0;
lower = path->nodes[level-1]; lower = path->nodes[level-1];
if (level == 1) if (level == 1)
btrfs_item_key(lower, &lower_key, 0); btrfs_item_key(lower, &lower_key, 0);
else else
btrfs_node_key(lower, &lower_key, 0); btrfs_node_key(lower, &lower_key, 0);
c = btrfs_alloc_free_block(trans, root, root->nodesize, c = btrfs_alloc_free_block(trans, root, root->nodesize, 0,
root->root_key.objectid, root->root_key.objectid, trans->transid,
root_gen, le64_to_cpu(lower_key.objectid),
level, root->node->start, 0); level, root->node->start, 0);
if (IS_ERR(c)) if (IS_ERR(c))
return PTR_ERR(c); return PTR_ERR(c);
@ -1679,7 +1713,7 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
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);
lower_gen = btrfs_header_generation(lower); lower_gen = btrfs_header_generation(lower);
WARN_ON(lower_gen == 0); WARN_ON(lower_gen != trans->transid);
btrfs_set_node_ptr_generation(c, 0, lower_gen); btrfs_set_node_ptr_generation(c, 0, lower_gen);
@ -1690,6 +1724,12 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
root->node = c; root->node = c;
spin_unlock(&root->node_lock); spin_unlock(&root->node_lock);
ret = btrfs_update_extent_ref(trans, root, lower->start,
lower->start, c->start,
root->root_key.objectid,
trans->transid, level - 1, 0);
BUG_ON(ret);
/* the super has an extra ref to root->node */ /* the super has an extra ref to root->node */
free_extent_buffer(old); free_extent_buffer(old);
@ -1698,20 +1738,6 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
path->nodes[level] = c; path->nodes[level] = c;
path->locks[level] = 1; path->locks[level] = 1;
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;
mutex_lock(&root->fs_info->alloc_mutex);
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);
mutex_unlock(&root->fs_info->alloc_mutex);
btrfs_free_path(back_path);
}
return 0; return 0;
} }
@ -1766,7 +1792,6 @@ static noinline int split_node(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;
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;
@ -1793,17 +1818,11 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
} }
c_nritems = btrfs_header_nritems(c); c_nritems = btrfs_header_nritems(c);
if (root->ref_cows)
root_gen = trans->transid;
else
root_gen = 0;
btrfs_node_key(c, &disk_key, 0);
split = btrfs_alloc_free_block(trans, root, root->nodesize, split = btrfs_alloc_free_block(trans, root, root->nodesize,
root->root_key.objectid, path->nodes[level + 1]->start,
root_gen, root->root_key.objectid,
btrfs_disk_key_objectid(&disk_key), trans->transid, level, c->start, 0);
level, c->start, 0);
if (IS_ERR(split)) if (IS_ERR(split))
return PTR_ERR(split); return PTR_ERR(split);
@ -1840,6 +1859,9 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
if (wret) if (wret)
ret = wret; ret = wret;
ret = btrfs_update_ref(trans, root, c, split, 0, c_nritems - mid);
BUG_ON(ret);
if (path->slots[level] >= mid) { if (path->slots[level] >= mid) {
path->slots[level] -= mid; path->slots[level] -= mid;
btrfs_tree_unlock(c); btrfs_tree_unlock(c);
@ -1955,10 +1977,23 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
else else
nr = 1; nr = 1;
if (path->slots[0] >= left_nritems)
push_space += data_size + sizeof(*item);
i = left_nritems - 1; i = left_nritems - 1;
while (i >= nr) { while (i >= nr) {
item = btrfs_item_nr(left, i); item = btrfs_item_nr(left, i);
if (!empty && push_items > 0) {
if (path->slots[0] > i)
break;
if (path->slots[0] == i) {
int space = btrfs_leaf_free_space(root, left);
if (space + push_space * 2 > free_space)
break;
}
}
if (path->slots[0] == i) if (path->slots[0] == i)
push_space += data_size + sizeof(*item); push_space += data_size + sizeof(*item);
@ -1973,6 +2008,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
this_item_size = btrfs_item_size(left, item); this_item_size = btrfs_item_size(left, item);
if (this_item_size + sizeof(*item) + push_space > free_space) if (this_item_size + sizeof(*item) + push_space > free_space)
break; break;
push_items++; push_items++;
push_space += this_item_size + sizeof(*item); push_space += this_item_size + sizeof(*item);
if (i == 0) if (i == 0)
@ -2046,6 +2082,9 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_mark_buffer_dirty(left); btrfs_mark_buffer_dirty(left);
btrfs_mark_buffer_dirty(right); btrfs_mark_buffer_dirty(right);
ret = btrfs_update_ref(trans, root, left, right, 0, push_items);
BUG_ON(ret);
btrfs_item_key(right, &disk_key, 0); btrfs_item_key(right, &disk_key, 0);
btrfs_set_node_key(upper, &disk_key, slot + 1); btrfs_set_node_key(upper, &disk_key, slot + 1);
btrfs_mark_buffer_dirty(upper); btrfs_mark_buffer_dirty(upper);
@ -2147,6 +2186,16 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
KM_USER1); KM_USER1);
} }
if (!empty && push_items > 0) {
if (path->slots[0] < i)
break;
if (path->slots[0] == i) {
int space = btrfs_leaf_free_space(root, right);
if (space + push_space * 2 > free_space)
break;
}
}
if (path->slots[0] == i) if (path->slots[0] == i)
push_space += data_size + sizeof(*item); push_space += data_size + sizeof(*item);
@ -2255,6 +2304,10 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
if (right_nritems) if (right_nritems)
btrfs_mark_buffer_dirty(right); btrfs_mark_buffer_dirty(right);
ret = btrfs_update_ref(trans, root, right, left,
old_left_nritems, push_items);
BUG_ON(ret);
btrfs_item_key(right, &disk_key, 0); btrfs_item_key(right, &disk_key, 0);
wret = fixup_low_keys(trans, root, path, &disk_key, 1); wret = fixup_low_keys(trans, root, path, &disk_key, 1);
if (wret) if (wret)
@ -2294,7 +2347,6 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
struct btrfs_path *path, int data_size, struct btrfs_path *path, int data_size,
int extend) int extend)
{ {
u64 root_gen;
struct extent_buffer *l; struct extent_buffer *l;
u32 nritems; u32 nritems;
int mid; int mid;
@ -2313,11 +2365,6 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
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);
@ -2348,13 +2395,10 @@ again:
nritems = btrfs_header_nritems(l); nritems = btrfs_header_nritems(l);
mid = (nritems + 1)/ 2; mid = (nritems + 1)/ 2;
btrfs_item_key(l, &disk_key, 0);
right = btrfs_alloc_free_block(trans, root, root->leafsize, right = btrfs_alloc_free_block(trans, root, root->leafsize,
root->root_key.objectid, path->nodes[1]->start,
root_gen, root->root_key.objectid,
le64_to_cpu(disk_key.objectid), trans->transid, 0, l->start, 0);
0, l->start, 0);
if (IS_ERR(right)) { if (IS_ERR(right)) {
BUG_ON(1); BUG_ON(1);
return PTR_ERR(right); return PTR_ERR(right);
@ -2485,6 +2529,9 @@ again:
btrfs_mark_buffer_dirty(l); btrfs_mark_buffer_dirty(l);
BUG_ON(path->slots[0] != slot); BUG_ON(path->slots[0] != slot);
ret = btrfs_update_ref(trans, root, l, right, 0, nritems);
BUG_ON(ret);
if (mid <= slot) { if (mid <= slot) {
btrfs_tree_unlock(path->nodes[0]); btrfs_tree_unlock(path->nodes[0]);
free_extent_buffer(path->nodes[0]); free_extent_buffer(path->nodes[0]);
@ -2956,6 +3003,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
ret = wret; ret = wret;
wret = btrfs_free_extent(trans, root, wret = btrfs_free_extent(trans, root,
leaf->start, leaf->len, leaf->start, leaf->len,
path->nodes[1]->start,
btrfs_header_owner(path->nodes[1]), btrfs_header_owner(path->nodes[1]),
root_gen, 0, 0, 1); root_gen, 0, 0, 1);
if (wret) if (wret)
@ -3007,7 +3055,7 @@ int btrfs_del_items(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, blocksize, path->nodes[1]->start,
btrfs_header_owner(path->nodes[1]), btrfs_header_owner(path->nodes[1]),
root_gen, 0, 0, 1); root_gen, 0, 0, 1);
if (wret) if (wret)

View file

@ -40,7 +40,7 @@ extern struct kmem_cache *btrfs_bit_radix_cachep;
extern struct kmem_cache *btrfs_path_cachep; extern struct kmem_cache *btrfs_path_cachep;
struct btrfs_ordered_sum; struct btrfs_ordered_sum;
#define BTRFS_MAGIC "_B8RfS_M" #define BTRFS_MAGIC "_B9RfS_M"
#define BTRFS_ACL_NOT_CACHED ((void *)-1) #define BTRFS_ACL_NOT_CACHED ((void *)-1)
@ -81,6 +81,9 @@ struct btrfs_ordered_sum;
#define BTRFS_TREE_LOG_OBJECTID -6ULL #define BTRFS_TREE_LOG_OBJECTID -6ULL
#define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL #define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL
/* dummy objectid represents multiple objectids */
#define BTRFS_MULTIPLE_OBJECTIDS -255ULL
/* /*
* All files have objectids in this range. * All files have objectids in this range.
*/ */
@ -369,6 +372,7 @@ struct btrfs_extent_ref {
__le64 generation; __le64 generation;
__le64 objectid; __le64 objectid;
__le64 offset; __le64 offset;
__le32 num_refs;
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
/* dev extents record free space on individual devices. The owner /* dev extents record free space on individual devices. The owner
@ -1047,9 +1051,6 @@ btrfs_inode_otime(struct btrfs_inode_item *inode_item)
BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64); BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64);
BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32); BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32);
/* struct btrfs_extent_item */
BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32);
/* struct btrfs_dev_extent */ /* struct btrfs_dev_extent */
BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent, BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent,
chunk_tree, 64); chunk_tree, 64);
@ -1070,14 +1071,20 @@ BTRFS_SETGET_FUNCS(ref_root, struct btrfs_extent_ref, root, 64);
BTRFS_SETGET_FUNCS(ref_generation, struct btrfs_extent_ref, generation, 64); 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_FUNCS(ref_num_refs, struct btrfs_extent_ref, num_refs, 32);
BTRFS_SETGET_STACK_FUNCS(stack_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(stack_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(stack_ref_objectid, struct btrfs_extent_ref, BTRFS_SETGET_STACK_FUNCS(stack_ref_objectid, struct btrfs_extent_ref,
objectid, 64); objectid, 64);
BTRFS_SETGET_STACK_FUNCS(stack_ref_offset, struct btrfs_extent_ref, offset, 64); BTRFS_SETGET_STACK_FUNCS(stack_ref_offset, struct btrfs_extent_ref,
offset, 64);
BTRFS_SETGET_STACK_FUNCS(stack_ref_num_refs, struct btrfs_extent_ref,
num_refs, 32);
/* struct btrfs_extent_item */
BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32);
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);
@ -1474,8 +1481,7 @@ static inline struct dentry *fdentry(struct file *file) {
} }
/* extent-tree.c */ /* extent-tree.c */
int btrfs_lookup_extent(struct btrfs_root *root, struct btrfs_path *path, int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len);
u64 start, u64 len);
int btrfs_update_pinned_extents(struct btrfs_root *root, int btrfs_update_pinned_extents(struct btrfs_root *root,
u64 bytenr, u64 num, int pin); u64 bytenr, u64 num, int pin);
int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
@ -1495,10 +1501,9 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
int data, int owner); int data, int owner);
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, u32 blocksize, u64 parent,
u64 root_objectid, u64 root_objectid,
u64 ref_generation, u64 ref_generation,
u64 first_objectid,
int level, int level,
u64 hint, u64 hint,
u64 empty_size); u64 empty_size);
@ -1508,23 +1513,24 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size); int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size);
int btrfs_insert_extent_backref(struct btrfs_trans_handle *trans, int btrfs_insert_extent_backref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_path *path, u64 bytenr, struct btrfs_path *path,
u64 bytenr, u64 parent,
u64 root_objectid, u64 ref_generation, u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset); 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, struct btrfs_root *root,
u64 num_bytes, u64 min_bytes, u64 num_bytes, u64 parent, u64 min_bytes,
u64 root_objectid, u64 ref_generation, u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset, u64 owner, u64 owner_offset,
u64 empty_size, u64 hint_byte, u64 empty_size, u64 hint_byte,
u64 search_end, struct btrfs_key *ins, u64 data); u64 search_end, struct btrfs_key *ins, u64 data);
int btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans, int btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root, u64 parent,
u64 root_objectid, u64 ref_generation, u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset, u64 owner, u64 owner_offset,
struct btrfs_key *ins); struct btrfs_key *ins);
int btrfs_alloc_logged_extent(struct btrfs_trans_handle *trans, int btrfs_alloc_logged_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root, u64 parent,
u64 root_objectid, u64 ref_generation, u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset, u64 owner, u64 owner_offset,
struct btrfs_key *ins); struct btrfs_key *ins);
@ -1535,9 +1541,16 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
u64 search_end, struct btrfs_key *ins, u64 search_end, struct btrfs_key *ins,
u64 data); u64 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, int cache_ref); struct extent_buffer *orig_buf, struct extent_buffer *buf,
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root u32 *nr_extents);
*root, u64 bytenr, u64 num_bytes, int btrfs_cache_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct extent_buffer *buf, u32 nr_extents);
int btrfs_update_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *orig_buf,
struct extent_buffer *buf, int start_slot, int nr);
int btrfs_free_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 bytenr, u64 num_bytes, u64 parent,
u64 root_objectid, u64 ref_generation, u64 root_objectid, u64 ref_generation,
u64 owner_objectid, u64 owner_offset, int pin); u64 owner_objectid, u64 owner_offset, int pin);
int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len); int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len);
@ -1545,10 +1558,15 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct extent_io_tree *unpin); struct extent_io_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 parent,
u64 root_objectid, u64 ref_generation, u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset); u64 owner, u64 owner_offset);
int btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr,
u64 orig_parent, u64 parent,
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);
@ -1561,7 +1579,9 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
int btrfs_previous_item(struct btrfs_root *root, int btrfs_previous_item(struct btrfs_root *root,
struct btrfs_path *path, u64 min_objectid, struct btrfs_path *path, u64 min_objectid,
int type); int type);
int btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path,
struct btrfs_key *new_key);
struct extent_buffer *btrfs_root_node(struct btrfs_root *root); struct extent_buffer *btrfs_root_node(struct btrfs_root *root);
struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root); struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root);
int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,

View file

@ -882,8 +882,8 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
root->ref_cows = 0; root->ref_cows = 0;
root->node = btrfs_alloc_free_block(trans, root, root->leafsize, root->node = btrfs_alloc_free_block(trans, root, root->leafsize,
BTRFS_TREE_LOG_OBJECTID, 0, BTRFS_TREE_LOG_OBJECTID,
0, 0, 0, 0, 0); trans->transid, 0, 0, 0);
btrfs_set_header_nritems(root->node, 0); btrfs_set_header_nritems(root->node, 0);
btrfs_set_header_level(root->node, 0); btrfs_set_header_level(root->node, 0);

File diff suppressed because it is too large Load diff

View file

@ -2201,9 +2201,10 @@ retry:
} }
if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
mapping->writeback_index = index; mapping->writeback_index = index;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
if (wbc->range_cont) if (wbc->range_cont)
wbc->range_start = index << PAGE_CACHE_SHIFT; wbc->range_start = index << PAGE_CACHE_SHIFT;
#endif
return ret; return ret;
} }
EXPORT_SYMBOL(extent_write_cache_pages); EXPORT_SYMBOL(extent_write_cache_pages);

View file

@ -524,6 +524,9 @@ int noinline btrfs_drop_extents(struct btrfs_trans_handle *trans,
{ {
u64 extent_end = 0; u64 extent_end = 0;
u64 search_start = start; u64 search_start = start;
u64 leaf_start;
u64 root_gen;
u64 root_owner;
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_file_extent_item *extent; struct btrfs_file_extent_item *extent;
struct btrfs_path *path; struct btrfs_path *path;
@ -562,6 +565,9 @@ next_slot:
bookend = 0; bookend = 0;
found_extent = 0; found_extent = 0;
found_inline = 0; found_inline = 0;
leaf_start = 0;
root_gen = 0;
root_owner = 0;
extent = NULL; extent = NULL;
leaf = path->nodes[0]; leaf = path->nodes[0];
slot = path->slots[0]; slot = path->slots[0];
@ -628,27 +634,18 @@ next_slot:
search_start = extent_end; search_start = extent_end;
if (end <= extent_end && start >= key.offset && found_inline) { if (end <= extent_end && start >= key.offset && found_inline) {
*hint_byte = EXTENT_MAP_INLINE; *hint_byte = EXTENT_MAP_INLINE;
continue; goto out;
} }
if (found_extent) {
read_extent_buffer(leaf, &old, (unsigned long)extent,
sizeof(old));
root_gen = btrfs_header_generation(leaf);
root_owner = btrfs_header_owner(leaf);
leaf_start = leaf->start;
}
if (end < extent_end && end >= key.offset) { if (end < extent_end && end >= key.offset) {
if (found_extent) {
u64 disk_bytenr =
btrfs_file_extent_disk_bytenr(leaf, extent);
u64 disk_num_bytes =
btrfs_file_extent_disk_num_bytes(leaf,
extent);
read_extent_buffer(leaf, &old,
(unsigned long)extent,
sizeof(old));
if (disk_bytenr != 0) {
ret = btrfs_inc_extent_ref(trans, root,
disk_bytenr, disk_num_bytes,
root->root_key.objectid,
trans->transid,
key.objectid, end);
BUG_ON(ret);
}
}
bookend = 1; bookend = 1;
if (found_inline && start <= key.offset) if (found_inline && start <= key.offset)
keep = 1; keep = 1;
@ -687,49 +684,12 @@ next_slot:
} }
/* delete the entire extent */ /* delete the entire extent */
if (!keep) { if (!keep) {
u64 disk_bytenr = 0;
u64 disk_num_bytes = 0;
u64 extent_num_bytes = 0;
u64 root_gen;
u64 root_owner;
root_gen = btrfs_header_generation(leaf);
root_owner = btrfs_header_owner(leaf);
if (found_extent) {
disk_bytenr =
btrfs_file_extent_disk_bytenr(leaf,
extent);
disk_num_bytes =
btrfs_file_extent_disk_num_bytes(leaf,
extent);
extent_num_bytes =
btrfs_file_extent_num_bytes(leaf, extent);
*hint_byte =
btrfs_file_extent_disk_bytenr(leaf,
extent);
}
ret = btrfs_del_item(trans, root, path); ret = btrfs_del_item(trans, root, path);
/* TODO update progress marker and return */ /* TODO update progress marker and return */
BUG_ON(ret); BUG_ON(ret);
btrfs_release_path(root, path);
extent = NULL; extent = NULL;
if (found_extent && disk_bytenr != 0) { btrfs_release_path(root, path);
dec_i_blocks(inode, extent_num_bytes); /* the extent will be freed later */
ret = btrfs_free_extent(trans, root,
disk_bytenr,
disk_num_bytes,
root_owner,
root_gen, inode->i_ino,
key.offset, 0);
}
BUG_ON(ret);
if (!bookend && search_start >= end) {
ret = 0;
goto out;
}
if (!bookend)
continue;
} }
if (bookend && found_inline && start <= key.offset) { if (bookend && found_inline && start <= key.offset) {
u32 new_size; u32 new_size;
@ -737,10 +697,13 @@ next_slot:
extent_end - end); extent_end - end);
dec_i_blocks(inode, (extent_end - key.offset) - dec_i_blocks(inode, (extent_end - key.offset) -
(extent_end - end)); (extent_end - end));
btrfs_truncate_item(trans, root, path, new_size, 0); ret = btrfs_truncate_item(trans, root, path,
new_size, 0);
BUG_ON(ret);
} }
/* create bookend, splitting the extent in two */ /* create bookend, splitting the extent in two */
if (bookend && found_extent) { if (bookend && found_extent) {
u64 disk_bytenr;
struct btrfs_key ins; struct btrfs_key ins;
ins.objectid = inode->i_ino; ins.objectid = inode->i_ino;
ins.offset = end; ins.offset = end;
@ -748,13 +711,9 @@ next_slot:
btrfs_release_path(root, path); btrfs_release_path(root, path);
ret = btrfs_insert_empty_item(trans, root, path, &ins, ret = btrfs_insert_empty_item(trans, root, path, &ins,
sizeof(*extent)); sizeof(*extent));
BUG_ON(ret);
leaf = path->nodes[0]; leaf = path->nodes[0];
if (ret) {
btrfs_print_leaf(root, leaf);
printk("got %d on inserting %Lu %u %Lu start %Lu end %Lu found %Lu %Lu keep was %d\n", ret , ins.objectid, ins.type, ins.offset, start, end, key.offset, extent_end, keep);
}
BUG_ON(ret);
extent = btrfs_item_ptr(leaf, path->slots[0], extent = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item); struct btrfs_file_extent_item);
write_extent_buffer(leaf, &old, write_extent_buffer(leaf, &old,
@ -770,11 +729,43 @@ next_slot:
BTRFS_FILE_EXTENT_REG); BTRFS_FILE_EXTENT_REG);
btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_mark_buffer_dirty(path->nodes[0]);
if (le64_to_cpu(old.disk_bytenr) != 0) {
disk_bytenr = le64_to_cpu(old.disk_bytenr);
if (disk_bytenr != 0) {
ret = btrfs_inc_extent_ref(trans, root,
disk_bytenr,
le64_to_cpu(old.disk_num_bytes),
leaf->start,
root->root_key.objectid,
trans->transid,
ins.objectid, ins.offset);
BUG_ON(ret);
}
btrfs_release_path(root, path);
if (disk_bytenr != 0) {
inode->i_blocks += inode->i_blocks +=
btrfs_file_extent_num_bytes(leaf, btrfs_file_extent_num_bytes(leaf,
extent) >> 9; extent) >> 9;
} }
}
if (found_extent && !keep) {
u64 disk_bytenr = le64_to_cpu(old.disk_bytenr);
if (disk_bytenr != 0) {
dec_i_blocks(inode, le64_to_cpu(old.num_bytes));
ret = btrfs_free_extent(trans, root,
disk_bytenr,
le64_to_cpu(old.disk_num_bytes),
leaf_start, root_owner,
root_gen, key.objectid,
key.offset, 0);
BUG_ON(ret);
*hint_byte = disk_bytenr;
}
}
if (search_start >= end) {
ret = 0; ret = 0;
goto out; goto out;
} }

View file

@ -528,6 +528,9 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct btrfs_ordered_extent *ordered_extent; struct btrfs_ordered_extent *ordered_extent;
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
struct btrfs_file_extent_item *extent_item;
struct btrfs_path *path = NULL;
struct extent_buffer *leaf;
u64 alloc_hint = 0; u64 alloc_hint = 0;
struct list_head list; struct list_head list;
struct btrfs_key ins; struct btrfs_key ins;
@ -544,20 +547,15 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags))
goto nocow; goto nocow;
path = btrfs_alloc_path();
BUG_ON(!path);
lock_extent(io_tree, ordered_extent->file_offset, lock_extent(io_tree, ordered_extent->file_offset,
ordered_extent->file_offset + ordered_extent->len - 1, ordered_extent->file_offset + ordered_extent->len - 1,
GFP_NOFS); GFP_NOFS);
INIT_LIST_HEAD(&list); INIT_LIST_HEAD(&list);
ins.objectid = ordered_extent->start;
ins.offset = ordered_extent->len;
ins.type = BTRFS_EXTENT_ITEM_KEY;
ret = btrfs_alloc_reserved_extent(trans, root, root->root_key.objectid,
trans->transid, inode->i_ino,
ordered_extent->file_offset, &ins);
BUG_ON(ret);
mutex_lock(&BTRFS_I(inode)->extent_mutex); mutex_lock(&BTRFS_I(inode)->extent_mutex);
ret = btrfs_drop_extents(trans, root, inode, ret = btrfs_drop_extents(trans, root, inode,
@ -566,18 +564,42 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
ordered_extent->len, ordered_extent->len,
ordered_extent->file_offset, &alloc_hint); ordered_extent->file_offset, &alloc_hint);
BUG_ON(ret); BUG_ON(ret);
ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
ordered_extent->file_offset, ins.objectid = inode->i_ino;
ordered_extent->start, ins.offset = ordered_extent->file_offset;
ordered_extent->len, ins.type = BTRFS_EXTENT_DATA_KEY;
ordered_extent->len, 0); ret = btrfs_insert_empty_item(trans, root, path, &ins,
sizeof(*extent_item));
BUG_ON(ret); BUG_ON(ret);
leaf = path->nodes[0];
extent_item = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
btrfs_set_file_extent_generation(leaf, extent_item, trans->transid);
btrfs_set_file_extent_type(leaf, extent_item, BTRFS_FILE_EXTENT_REG);
btrfs_set_file_extent_disk_bytenr(leaf, extent_item,
ordered_extent->start);
btrfs_set_file_extent_disk_num_bytes(leaf, extent_item,
ordered_extent->len);
btrfs_set_file_extent_offset(leaf, extent_item, 0);
btrfs_set_file_extent_num_bytes(leaf, extent_item,
ordered_extent->len);
btrfs_mark_buffer_dirty(leaf);
btrfs_drop_extent_cache(inode, ordered_extent->file_offset, btrfs_drop_extent_cache(inode, ordered_extent->file_offset,
ordered_extent->file_offset + ordered_extent->file_offset +
ordered_extent->len - 1); ordered_extent->len - 1);
mutex_unlock(&BTRFS_I(inode)->extent_mutex); mutex_unlock(&BTRFS_I(inode)->extent_mutex);
ins.objectid = ordered_extent->start;
ins.offset = ordered_extent->len;
ins.type = BTRFS_EXTENT_ITEM_KEY;
ret = btrfs_alloc_reserved_extent(trans, root, leaf->start,
root->root_key.objectid,
trans->transid, inode->i_ino,
ordered_extent->file_offset, &ins);
BUG_ON(ret);
btrfs_release_path(root, path);
inode->i_blocks += ordered_extent->len >> 9; inode->i_blocks += ordered_extent->len >> 9;
unlock_extent(io_tree, ordered_extent->file_offset, unlock_extent(io_tree, ordered_extent->file_offset,
ordered_extent->file_offset + ordered_extent->len - 1, ordered_extent->file_offset + ordered_extent->len - 1,
@ -596,6 +618,8 @@ nocow:
btrfs_put_ordered_extent(ordered_extent); btrfs_put_ordered_extent(ordered_extent);
btrfs_end_transaction(trans, root); btrfs_end_transaction(trans, root);
if (path)
btrfs_free_path(path);
return 0; return 0;
} }
@ -1433,10 +1457,7 @@ search_again:
if (root->ref_cows) if (root->ref_cows)
dec_i_blocks(inode, num_dec); dec_i_blocks(inode, num_dec);
} }
if (root->ref_cows) { root_gen = btrfs_header_generation(leaf);
root_gen =
btrfs_header_generation(leaf);
}
root_owner = btrfs_header_owner(leaf); root_owner = btrfs_header_owner(leaf);
} }
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
@ -1477,7 +1498,7 @@ delete:
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, extent_num_bytes,
root_owner, leaf->start, root_owner,
root_gen, inode->i_ino, root_gen, inode->i_ino,
found_key.offset, 0); found_key.offset, 0);
BUG_ON(ret); BUG_ON(ret);

View file

@ -76,9 +76,8 @@ static noinline int create_subvol(struct btrfs_root *root, char *name,
if (ret) if (ret)
goto fail; goto fail;
leaf = btrfs_alloc_free_block(trans, root, root->leafsize, leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0,
objectid, trans->transid, 0, 0, objectid, trans->transid, 0, 0, 0);
0, 0);
if (IS_ERR(leaf)) { if (IS_ERR(leaf)) {
ret = PTR_ERR(leaf); ret = PTR_ERR(leaf);
goto fail; goto fail;
@ -525,13 +524,10 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd)
struct file *src_file; struct file *src_file;
struct inode *src; struct inode *src;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
struct btrfs_ordered_extent *ordered;
struct btrfs_path *path; struct btrfs_path *path;
struct extent_buffer *leaf; struct extent_buffer *leaf;
char *buf; char *buf;
struct btrfs_key key; struct btrfs_key key;
struct btrfs_key new_key;
u32 size;
u32 nritems; u32 nritems;
int slot; int slot;
int ret; int ret;
@ -576,6 +572,7 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd)
/* do any pending delalloc/csum calc on src, one way or /* do any pending delalloc/csum calc on src, one way or
another, and lock file content */ another, and lock file content */
while (1) { while (1) {
struct btrfs_ordered_extent *ordered;
lock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS); lock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS);
ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1); ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1);
if (BTRFS_I(src)->delalloc_bytes == 0 && !ordered) if (BTRFS_I(src)->delalloc_bytes == 0 && !ordered)
@ -619,6 +616,32 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd)
key.objectid != src->i_ino) key.objectid != src->i_ino)
break; break;
if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY ||
btrfs_key_type(&key) == BTRFS_CSUM_ITEM_KEY) {
u32 size;
struct btrfs_key new_key;
size = btrfs_item_size_nr(leaf, slot);
read_extent_buffer(leaf, buf,
btrfs_item_ptr_offset(leaf, slot),
size);
btrfs_release_path(root, path);
memcpy(&new_key, &key, sizeof(new_key));
new_key.objectid = inode->i_ino;
ret = btrfs_insert_empty_item(trans, root, path,
&new_key, size);
if (ret)
goto out;
leaf = path->nodes[0];
slot = path->slots[0];
write_extent_buffer(leaf, buf,
btrfs_item_ptr_offset(leaf, slot),
size);
btrfs_mark_buffer_dirty(leaf);
}
if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) { if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) {
struct btrfs_file_extent_item *extent; struct btrfs_file_extent_item *extent;
int found_type; int found_type;
@ -634,31 +657,15 @@ long btrfs_ioctl_clone(struct file *file, unsigned long src_fd)
/* ds == 0 means there's a hole */ /* ds == 0 means there's a hole */
if (ds != 0) { if (ds != 0) {
ret = btrfs_inc_extent_ref(trans, root, ret = btrfs_inc_extent_ref(trans, root,
ds, dl, ds, dl, leaf->start,
root->root_key.objectid, root->root_key.objectid,
trans->transid, trans->transid,
inode->i_ino, key.offset); inode->i_ino, key.offset);
if (ret) BUG_ON(ret);
goto out;
} }
} }
} }
btrfs_release_path(root, path);
if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY ||
btrfs_key_type(&key) == BTRFS_CSUM_ITEM_KEY) {
size = btrfs_item_size_nr(leaf, slot);
read_extent_buffer(leaf, buf,
btrfs_item_ptr_offset(leaf, slot),
size);
btrfs_release_path(root, path);
memcpy(&new_key, &key, sizeof(new_key));
new_key.objectid = inode->i_ino;
ret = btrfs_insert_item(trans, root, &new_key,
buf, size);
BUG_ON(ret);
} else {
btrfs_release_path(root, path);
}
key.offset++; key.offset++;
} }
ret = 0; ret = 0;

View file

@ -102,11 +102,12 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
case BTRFS_EXTENT_REF_KEY: case BTRFS_EXTENT_REF_KEY:
ref = btrfs_item_ptr(l, i, struct btrfs_extent_ref); ref = btrfs_item_ptr(l, i, struct btrfs_extent_ref);
printk("\t\textent back ref root %llu gen %llu " printk("\t\textent back ref root %llu gen %llu "
"owner %llu offset %llu\n", "owner %llu offset %llu num_refs %lu\n",
(unsigned long long)btrfs_ref_root(l, ref), (unsigned long long)btrfs_ref_root(l, ref),
(unsigned long long)btrfs_ref_generation(l, ref), (unsigned long long)btrfs_ref_generation(l, ref),
(unsigned long long)btrfs_ref_objectid(l, ref), (unsigned long long)btrfs_ref_objectid(l, ref),
(unsigned long long)btrfs_ref_offset(l, ref)); (unsigned long long)btrfs_ref_offset(l, ref),
(unsigned long)btrfs_ref_num_refs(l, ref));
break; break;
case BTRFS_EXTENT_DATA_KEY: case BTRFS_EXTENT_DATA_KEY:

View file

@ -89,9 +89,9 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
int ret; int ret;
u64 objectid = root->root_key.objectid; u64 objectid = root->root_key.objectid;
leaf = btrfs_alloc_free_block(trans, root, root->leafsize, leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0,
BTRFS_TREE_LOG_OBJECTID, BTRFS_TREE_LOG_OBJECTID,
0, 0, 0, 0, 0); trans->transid, 0, 0, 0);
if (IS_ERR(leaf)) { if (IS_ERR(leaf)) {
ret = PTR_ERR(leaf); ret = PTR_ERR(leaf);
return ret; return ret;
@ -433,6 +433,49 @@ insert:
trans->transid); trans->transid);
} }
} }
if (overwrite_root &&
key->type == BTRFS_EXTENT_DATA_KEY) {
int extent_type;
struct btrfs_file_extent_item *fi;
fi = (struct btrfs_file_extent_item *)dst_ptr;
extent_type = btrfs_file_extent_type(path->nodes[0], fi);
if (extent_type == BTRFS_FILE_EXTENT_REG) {
struct btrfs_key ins;
ins.objectid = btrfs_file_extent_disk_bytenr(
path->nodes[0], fi);
ins.offset = btrfs_file_extent_disk_num_bytes(
path->nodes[0], fi);
ins.type = BTRFS_EXTENT_ITEM_KEY;
/*
* is this extent already allocated in the extent
* allocation tree? If so, just add a reference
*/
ret = btrfs_lookup_extent(root, ins.objectid,
ins.offset);
if (ret == 0) {
ret = btrfs_inc_extent_ref(trans, root,
ins.objectid, ins.offset,
path->nodes[0]->start,
root->root_key.objectid,
trans->transid,
key->objectid, key->offset);
} else {
/*
* insert the extent pointer in the extent
* allocation tree
*/
ret = btrfs_alloc_logged_extent(trans, root,
path->nodes[0]->start,
root->root_key.objectid,
trans->transid, key->objectid,
key->offset, &ins);
BUG_ON(ret);
}
}
}
no_copy: no_copy:
btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_mark_buffer_dirty(path->nodes[0]);
btrfs_release_path(root, path); btrfs_release_path(root, path);
@ -551,45 +594,10 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
start, extent_end, start, &alloc_hint); start, extent_end, start, &alloc_hint);
BUG_ON(ret); BUG_ON(ret);
/* insert the extent */
ret = overwrite_item(trans, root, path, eb, slot, key);
BUG_ON(ret); BUG_ON(ret);
if (found_type == BTRFS_FILE_EXTENT_REG) {
struct btrfs_key ins;
ins.objectid = btrfs_file_extent_disk_bytenr(eb, item);
ins.offset = btrfs_file_extent_disk_num_bytes(eb, item);
ins.type = BTRFS_EXTENT_ITEM_KEY;
/* insert the extent pointer in the file */
ret = overwrite_item(trans, root, path, eb, slot, key);
BUG_ON(ret);
/*
* is this extent already allocated in the extent
* allocation tree? If so, just add a reference
*/
ret = btrfs_lookup_extent(root, path, ins.objectid, ins.offset);
btrfs_release_path(root, path);
if (ret == 0) {
ret = btrfs_inc_extent_ref(trans, root,
ins.objectid, ins.offset,
root->root_key.objectid,
trans->transid, key->objectid, start);
} else {
/*
* insert the extent pointer in the extent
* allocation tree
*/
ret = btrfs_alloc_logged_extent(trans, root,
root->root_key.objectid,
trans->transid, key->objectid,
start, &ins);
BUG_ON(ret);
}
} else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
/* inline extents are easy, we just overwrite them */
ret = overwrite_item(trans, root, path, eb, slot, key);
BUG_ON(ret);
}
/* btrfs_drop_extents changes i_blocks, update it here */ /* btrfs_drop_extents changes i_blocks, update it here */
inode->i_blocks += (extent_end - start) >> 9; inode->i_blocks += (extent_end - start) >> 9;
btrfs_update_inode(trans, root, inode); btrfs_update_inode(trans, root, inode);
@ -1806,16 +1814,14 @@ static int noinline walk_up_log_tree(struct btrfs_trans_handle *trans,
WARN_ON(*level == 0); WARN_ON(*level == 0);
return 0; return 0;
} else { } else {
if (path->nodes[*level] == root->node) { struct extent_buffer *parent;
root_owner = root->root_key.objectid; if (path->nodes[*level] == root->node)
root_gen = parent = path->nodes[*level];
btrfs_header_generation(path->nodes[*level]); else
} else { parent = path->nodes[*level + 1];
struct extent_buffer *node;
node = path->nodes[*level + 1]; root_owner = btrfs_header_owner(parent);
root_owner = btrfs_header_owner(node); root_gen = btrfs_header_generation(parent);
root_gen = btrfs_header_generation(node);
}
wc->process_func(root, path->nodes[*level], wc, wc->process_func(root, path->nodes[*level], wc,
btrfs_header_generation(path->nodes[*level])); btrfs_header_generation(path->nodes[*level]));
if (wc->free) { if (wc->free) {
@ -2525,8 +2531,10 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
if (ds != 0) { if (ds != 0) {
ret = btrfs_inc_extent_ref(trans, log, ret = btrfs_inc_extent_ref(trans, log,
ds, dl, ds, dl,
dst_path->nodes[0]->start,
BTRFS_TREE_LOG_OBJECTID, BTRFS_TREE_LOG_OBJECTID,
0, ins_keys[i].objectid, trans->transid,
ins_keys[i].objectid,
ins_keys[i].offset); ins_keys[i].offset);
BUG_ON(ret); BUG_ON(ret);
} }