|
@@ -1872,20 +1872,24 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
|
|
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root,
|
|
|
u64 bytenr, u64 num_bytes, u64 parent,
|
|
|
- u64 root_objectid, u64 owner, u64 offset)
|
|
|
+ u64 root_objectid, u64 owner, u64 offset, int for_cow)
|
|
|
{
|
|
|
int ret;
|
|
|
+ struct btrfs_fs_info *fs_info = root->fs_info;
|
|
|
+
|
|
|
BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID &&
|
|
|
root_objectid == BTRFS_TREE_LOG_OBJECTID);
|
|
|
|
|
|
if (owner < BTRFS_FIRST_FREE_OBJECTID) {
|
|
|
- ret = btrfs_add_delayed_tree_ref(trans, bytenr, num_bytes,
|
|
|
+ ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr,
|
|
|
+ num_bytes,
|
|
|
parent, root_objectid, (int)owner,
|
|
|
- BTRFS_ADD_DELAYED_REF, NULL);
|
|
|
+ BTRFS_ADD_DELAYED_REF, NULL, for_cow);
|
|
|
} else {
|
|
|
- ret = btrfs_add_delayed_data_ref(trans, bytenr, num_bytes,
|
|
|
+ ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
|
|
|
+ num_bytes,
|
|
|
parent, root_objectid, owner, offset,
|
|
|
- BTRFS_ADD_DELAYED_REF, NULL);
|
|
|
+ BTRFS_ADD_DELAYED_REF, NULL, for_cow);
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
@@ -2405,7 +2409,8 @@ int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
|
|
|
extent_op->update_key = 0;
|
|
|
extent_op->is_data = is_data ? 1 : 0;
|
|
|
|
|
|
- ret = btrfs_add_delayed_extent_op(trans, bytenr, num_bytes, extent_op);
|
|
|
+ ret = btrfs_add_delayed_extent_op(root->fs_info, trans, bytenr,
|
|
|
+ num_bytes, extent_op);
|
|
|
if (ret)
|
|
|
kfree(extent_op);
|
|
|
return ret;
|
|
@@ -2590,7 +2595,7 @@ out:
|
|
|
static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root,
|
|
|
struct extent_buffer *buf,
|
|
|
- int full_backref, int inc)
|
|
|
+ int full_backref, int inc, int for_cow)
|
|
|
{
|
|
|
u64 bytenr;
|
|
|
u64 num_bytes;
|
|
@@ -2603,7 +2608,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
|
|
|
int level;
|
|
|
int ret = 0;
|
|
|
int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *,
|
|
|
- u64, u64, u64, u64, u64, u64);
|
|
|
+ u64, u64, u64, u64, u64, u64, int);
|
|
|
|
|
|
ref_root = btrfs_header_owner(buf);
|
|
|
nritems = btrfs_header_nritems(buf);
|
|
@@ -2640,14 +2645,15 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
|
|
|
key.offset -= btrfs_file_extent_offset(buf, fi);
|
|
|
ret = process_func(trans, root, bytenr, num_bytes,
|
|
|
parent, ref_root, key.objectid,
|
|
|
- key.offset);
|
|
|
+ key.offset, for_cow);
|
|
|
if (ret)
|
|
|
goto fail;
|
|
|
} else {
|
|
|
bytenr = btrfs_node_blockptr(buf, i);
|
|
|
num_bytes = btrfs_level_size(root, level - 1);
|
|
|
ret = process_func(trans, root, bytenr, num_bytes,
|
|
|
- parent, ref_root, level - 1, 0);
|
|
|
+ parent, ref_root, level - 1, 0,
|
|
|
+ for_cow);
|
|
|
if (ret)
|
|
|
goto fail;
|
|
|
}
|
|
@@ -2659,15 +2665,15 @@ fail:
|
|
|
}
|
|
|
|
|
|
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|
|
- struct extent_buffer *buf, int full_backref)
|
|
|
+ struct extent_buffer *buf, int full_backref, int for_cow)
|
|
|
{
|
|
|
- return __btrfs_mod_ref(trans, root, buf, full_backref, 1);
|
|
|
+ return __btrfs_mod_ref(trans, root, buf, full_backref, 1, for_cow);
|
|
|
}
|
|
|
|
|
|
int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|
|
- struct extent_buffer *buf, int full_backref)
|
|
|
+ struct extent_buffer *buf, int full_backref, int for_cow)
|
|
|
{
|
|
|
- return __btrfs_mod_ref(trans, root, buf, full_backref, 0);
|
|
|
+ return __btrfs_mod_ref(trans, root, buf, full_backref, 0, for_cow);
|
|
|
}
|
|
|
|
|
|
static int write_one_cache_group(struct btrfs_trans_handle *trans,
|
|
@@ -4937,16 +4943,17 @@ out:
|
|
|
void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root,
|
|
|
struct extent_buffer *buf,
|
|
|
- u64 parent, int last_ref)
|
|
|
+ u64 parent, int last_ref, int for_cow)
|
|
|
{
|
|
|
struct btrfs_block_group_cache *cache = NULL;
|
|
|
int ret;
|
|
|
|
|
|
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
|
|
|
- ret = btrfs_add_delayed_tree_ref(trans, buf->start, buf->len,
|
|
|
- parent, root->root_key.objectid,
|
|
|
- btrfs_header_level(buf),
|
|
|
- BTRFS_DROP_DELAYED_REF, NULL);
|
|
|
+ ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
|
|
|
+ buf->start, buf->len,
|
|
|
+ parent, root->root_key.objectid,
|
|
|
+ btrfs_header_level(buf),
|
|
|
+ BTRFS_DROP_DELAYED_REF, NULL, for_cow);
|
|
|
BUG_ON(ret);
|
|
|
}
|
|
|
|
|
@@ -4981,12 +4988,12 @@ out:
|
|
|
btrfs_put_block_group(cache);
|
|
|
}
|
|
|
|
|
|
-int btrfs_free_extent(struct btrfs_trans_handle *trans,
|
|
|
- struct btrfs_root *root,
|
|
|
- u64 bytenr, u64 num_bytes, u64 parent,
|
|
|
- u64 root_objectid, u64 owner, u64 offset)
|
|
|
+int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
|
|
+ u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid,
|
|
|
+ u64 owner, u64 offset, int for_cow)
|
|
|
{
|
|
|
int ret;
|
|
|
+ struct btrfs_fs_info *fs_info = root->fs_info;
|
|
|
|
|
|
/*
|
|
|
* tree log blocks never actually go into the extent allocation
|
|
@@ -4998,14 +5005,17 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
|
|
|
btrfs_pin_extent(root, bytenr, num_bytes, 1);
|
|
|
ret = 0;
|
|
|
} else if (owner < BTRFS_FIRST_FREE_OBJECTID) {
|
|
|
- ret = btrfs_add_delayed_tree_ref(trans, bytenr, num_bytes,
|
|
|
+ ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr,
|
|
|
+ num_bytes,
|
|
|
parent, root_objectid, (int)owner,
|
|
|
- BTRFS_DROP_DELAYED_REF, NULL);
|
|
|
+ BTRFS_DROP_DELAYED_REF, NULL, for_cow);
|
|
|
BUG_ON(ret);
|
|
|
} else {
|
|
|
- ret = btrfs_add_delayed_data_ref(trans, bytenr, num_bytes,
|
|
|
- parent, root_objectid, owner,
|
|
|
- offset, BTRFS_DROP_DELAYED_REF, NULL);
|
|
|
+ ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr,
|
|
|
+ num_bytes,
|
|
|
+ parent, root_objectid, owner,
|
|
|
+ offset, BTRFS_DROP_DELAYED_REF,
|
|
|
+ NULL, for_cow);
|
|
|
BUG_ON(ret);
|
|
|
}
|
|
|
return ret;
|
|
@@ -5826,9 +5836,10 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
BUG_ON(root_objectid == BTRFS_TREE_LOG_OBJECTID);
|
|
|
|
|
|
- ret = btrfs_add_delayed_data_ref(trans, ins->objectid, ins->offset,
|
|
|
- 0, root_objectid, owner, offset,
|
|
|
- BTRFS_ADD_DELAYED_EXTENT, NULL);
|
|
|
+ ret = btrfs_add_delayed_data_ref(root->fs_info, trans, ins->objectid,
|
|
|
+ ins->offset, 0,
|
|
|
+ root_objectid, owner, offset,
|
|
|
+ BTRFS_ADD_DELAYED_EXTENT, NULL, 0);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -5998,7 +6009,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root, u32 blocksize,
|
|
|
u64 parent, u64 root_objectid,
|
|
|
struct btrfs_disk_key *key, int level,
|
|
|
- u64 hint, u64 empty_size)
|
|
|
+ u64 hint, u64 empty_size, int for_cow)
|
|
|
{
|
|
|
struct btrfs_key ins;
|
|
|
struct btrfs_block_rsv *block_rsv;
|
|
@@ -6042,10 +6053,11 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
|
|
extent_op->update_flags = 1;
|
|
|
extent_op->is_data = 0;
|
|
|
|
|
|
- ret = btrfs_add_delayed_tree_ref(trans, ins.objectid,
|
|
|
+ ret = btrfs_add_delayed_tree_ref(root->fs_info, trans,
|
|
|
+ ins.objectid,
|
|
|
ins.offset, parent, root_objectid,
|
|
|
level, BTRFS_ADD_DELAYED_EXTENT,
|
|
|
- extent_op);
|
|
|
+ extent_op, for_cow);
|
|
|
BUG_ON(ret);
|
|
|
}
|
|
|
return buf;
|
|
@@ -6062,6 +6074,7 @@ struct walk_control {
|
|
|
int keep_locks;
|
|
|
int reada_slot;
|
|
|
int reada_count;
|
|
|
+ int for_reloc;
|
|
|
};
|
|
|
|
|
|
#define DROP_REFERENCE 1
|
|
@@ -6200,9 +6213,9 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
|
|
|
/* wc->stage == UPDATE_BACKREF */
|
|
|
if (!(wc->flags[level] & flag)) {
|
|
|
BUG_ON(!path->locks[level]);
|
|
|
- ret = btrfs_inc_ref(trans, root, eb, 1);
|
|
|
+ ret = btrfs_inc_ref(trans, root, eb, 1, wc->for_reloc);
|
|
|
BUG_ON(ret);
|
|
|
- ret = btrfs_dec_ref(trans, root, eb, 0);
|
|
|
+ ret = btrfs_dec_ref(trans, root, eb, 0, wc->for_reloc);
|
|
|
BUG_ON(ret);
|
|
|
ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
|
|
|
eb->len, flag, 0);
|
|
@@ -6346,7 +6359,7 @@ skip:
|
|
|
}
|
|
|
|
|
|
ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
|
|
|
- root->root_key.objectid, level - 1, 0);
|
|
|
+ root->root_key.objectid, level - 1, 0, 0);
|
|
|
BUG_ON(ret);
|
|
|
}
|
|
|
btrfs_tree_unlock(next);
|
|
@@ -6420,9 +6433,11 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
|
|
|
if (wc->refs[level] == 1) {
|
|
|
if (level == 0) {
|
|
|
if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
|
|
|
- ret = btrfs_dec_ref(trans, root, eb, 1);
|
|
|
+ ret = btrfs_dec_ref(trans, root, eb, 1,
|
|
|
+ wc->for_reloc);
|
|
|
else
|
|
|
- ret = btrfs_dec_ref(trans, root, eb, 0);
|
|
|
+ ret = btrfs_dec_ref(trans, root, eb, 0,
|
|
|
+ wc->for_reloc);
|
|
|
BUG_ON(ret);
|
|
|
}
|
|
|
/* make block locked assertion in clean_tree_block happy */
|
|
@@ -6449,7 +6464,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
|
|
|
btrfs_header_owner(path->nodes[level + 1]));
|
|
|
}
|
|
|
|
|
|
- btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1);
|
|
|
+ btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1, 0);
|
|
|
out:
|
|
|
wc->refs[level] = 0;
|
|
|
wc->flags[level] = 0;
|
|
@@ -6533,7 +6548,8 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans,
|
|
|
* blocks are properly updated.
|
|
|
*/
|
|
|
void btrfs_drop_snapshot(struct btrfs_root *root,
|
|
|
- struct btrfs_block_rsv *block_rsv, int update_ref)
|
|
|
+ struct btrfs_block_rsv *block_rsv, int update_ref,
|
|
|
+ int for_reloc)
|
|
|
{
|
|
|
struct btrfs_path *path;
|
|
|
struct btrfs_trans_handle *trans;
|
|
@@ -6621,6 +6637,7 @@ void btrfs_drop_snapshot(struct btrfs_root *root,
|
|
|
wc->stage = DROP_REFERENCE;
|
|
|
wc->update_ref = update_ref;
|
|
|
wc->keep_locks = 0;
|
|
|
+ wc->for_reloc = for_reloc;
|
|
|
wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root);
|
|
|
|
|
|
while (1) {
|
|
@@ -6705,6 +6722,7 @@ out:
|
|
|
* drop subtree rooted at tree block 'node'.
|
|
|
*
|
|
|
* NOTE: this function will unlock and release tree block 'node'
|
|
|
+ * only used by relocation code
|
|
|
*/
|
|
|
int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
|
|
|
struct btrfs_root *root,
|
|
@@ -6749,6 +6767,7 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
|
|
|
wc->stage = DROP_REFERENCE;
|
|
|
wc->update_ref = 0;
|
|
|
wc->keep_locks = 1;
|
|
|
+ wc->for_reloc = 1;
|
|
|
wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root);
|
|
|
|
|
|
while (1) {
|