@@ -348,10 +348,8 @@ static noinline int update_ref_for_cow(s
BUG_ON(ret);
}
if (new_flags != 0) {
- ret = btrfs_set_disk_extent_flags(trans, root,
- buf->start,
- buf->len,
- new_flags, 0);
+ ret = btrfs_update_tree_block_info(trans, root, buf,
+ NULL, new_flags, 0);
BUG_ON(ret);
}
} else {
@@ -1126,6 +1124,10 @@ static noinline int balance_level(struct
btrfs_node_key(right, &right_key, 0);
btrfs_set_node_key(parent, &right_key, pslot + 1);
btrfs_mark_buffer_dirty(parent);
+
+ wret = btrfs_update_tree_block_key(trans, root,
+ right, &right_key);
+ BUG_ON(wret);
}
}
if (btrfs_header_nritems(mid) == 1) {
@@ -1167,6 +1169,10 @@ static noinline int balance_level(struct
btrfs_node_key(mid, &mid_key, 0);
btrfs_set_node_key(parent, &mid_key, pslot);
btrfs_mark_buffer_dirty(parent);
+
+ wret = btrfs_update_tree_block_key(trans, root,
+ mid, &mid_key);
+ BUG_ON(wret);
}
/* update the path */
@@ -1266,6 +1272,11 @@ static noinline int push_nodes_for_inser
btrfs_node_key(mid, &disk_key, 0);
btrfs_set_node_key(parent, &disk_key, pslot);
btrfs_mark_buffer_dirty(parent);
+
+ wret = btrfs_update_tree_block_key(trans, root,
+ mid, &disk_key);
+ BUG_ON(wret);
+
if (btrfs_header_nritems(left) > orig_slot) {
path->nodes[level] = left;
path->slots[level + 1] -= 1;
@@ -1318,6 +1329,10 @@ static noinline int push_nodes_for_inser
btrfs_set_node_key(parent, &disk_key, pslot + 1);
btrfs_mark_buffer_dirty(parent);
+ wret = btrfs_update_tree_block_key(trans, root,
+ right, &disk_key);
+ BUG_ON(wret);
+
if (btrfs_header_nritems(mid) <= orig_slot) {
path->nodes[level] = right;
path->slots[level + 1] += 1;
@@ -1893,6 +1908,8 @@ static int fixup_low_keys(struct btrfs_t
btrfs_mark_buffer_dirty(path->nodes[i]);
if (tslot != 0)
break;
+ ret = btrfs_update_tree_block_key(trans, root, t, key);
+ BUG_ON(ret);
}
return ret;
}
@@ -1927,9 +1944,13 @@ int btrfs_set_item_key_safe(struct btrfs
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)
+ if (slot == 0) {
+ int ret;
+ btrfs_set_path_blocking(path);
+ ret = btrfs_update_tree_block_key(trans, root, eb, &disk_key);
+ BUG_ON(ret);
fixup_low_keys(trans, root, path, &disk_key, 1);
-
+ }
return 0;
}
@@ -2312,6 +2333,7 @@ static noinline int __push_leaf_right(st
struct extent_buffer *upper = path->nodes[1];
struct btrfs_disk_key disk_key;
int slot;
+ int ret;
u32 i;
int push_space = 0;
int push_items = 0;
@@ -2439,6 +2461,9 @@ static noinline int __push_leaf_right(st
btrfs_set_node_key(upper, &disk_key, slot + 1);
btrfs_mark_buffer_dirty(upper);
+ ret = btrfs_update_tree_block_key(trans, root, right, &disk_key);
+ BUG_ON(ret);
+
/* then fixup the leaf pointer in the path */
if (path->slots[0] >= left_nritems) {
path->slots[0] -= left_nritems;
@@ -2677,6 +2702,10 @@ static noinline int __push_leaf_left(str
if (right_nritems) {
btrfs_mark_buffer_dirty(right);
btrfs_item_key(right, &disk_key, 0);
+ wret = btrfs_update_tree_block_key(trans, root, right,
+ &disk_key);
+ BUG_ON(wret);
+
wret = fixup_low_keys(trans, root, path, &disk_key, 1);
if (wret)
ret = wret;
@@ -3324,8 +3353,13 @@ int btrfs_truncate_item(struct btrfs_tra
offset = btrfs_disk_key_offset(&disk_key);
btrfs_set_disk_key_offset(&disk_key, offset + size_diff);
btrfs_set_item_key(leaf, &disk_key, slot);
- if (slot == 0)
+ if (slot == 0) {
+ btrfs_set_path_blocking(path);
+ ret = btrfs_update_tree_block_key(trans, root,
+ leaf, &disk_key);
+ BUG_ON(ret);
fixup_low_keys(trans, root, path, &disk_key, 1);
+ }
}
item = btrfs_item_nr(leaf, slot);
@@ -3561,6 +3595,11 @@ int btrfs_insert_some_items(struct btrfs
ret = 0;
if (slot == 0) {
btrfs_cpu_key_to_disk(&disk_key, cpu_key);
+
+ btrfs_set_path_blocking(path);
+ ret = btrfs_update_tree_block_key(trans, root, leaf,
+ &disk_key);
+ BUG_ON(ret);
ret = fixup_low_keys(trans, root, path, &disk_key, 1);
}
@@ -3669,6 +3708,11 @@ setup_items_for_insert(struct btrfs_tran
if (slot == 0) {
struct btrfs_disk_key disk_key;
btrfs_cpu_key_to_disk(&disk_key, cpu_key);
+
+ btrfs_set_path_blocking(path);
+ ret = btrfs_update_tree_block_key(trans, root, leaf,
+ &disk_key);
+ BUG_ON(ret);
ret = fixup_low_keys(trans, root, path, &disk_key, 1);
}
btrfs_unlock_up_safe(path, 1);
@@ -3775,8 +3819,11 @@ static int del_ptr(struct btrfs_trans_ha
btrfs_set_header_level(root->node, 0);
} else if (slot == 0) {
struct btrfs_disk_key disk_key;
-
btrfs_node_key(parent, &disk_key, 0);
+
+ ret = btrfs_update_tree_block_key(trans, root, parent,
+ &disk_key);
+ BUG_ON(ret);
wret = fixup_low_keys(trans, root, path, &disk_key, level + 1);
if (wret)
ret = wret;
@@ -3893,8 +3940,12 @@ int btrfs_del_items(struct btrfs_trans_h
int used = leaf_space_used(leaf, 0, nritems);
if (slot == 0) {
struct btrfs_disk_key disk_key;
-
btrfs_item_key(leaf, &disk_key, 0);
+
+ btrfs_set_path_blocking(path);
+ wret = btrfs_update_tree_block_key(trans, root,
+ leaf, &disk_key);
+ BUG_ON(wret);
wret = fixup_low_keys(trans, root, path,
&disk_key, 1);
if (wret)
@@ -2013,10 +2013,15 @@ int btrfs_inc_ref(struct btrfs_trans_han
struct extent_buffer *buf, int full_backref);
int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct extent_buffer *buf, int full_backref);
-int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
+int btrfs_update_tree_block_key(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- u64 bytenr, u64 num_bytes, u64 flags,
- int is_data);
+ struct extent_buffer *eb,
+ struct btrfs_disk_key *key);
+int btrfs_update_tree_block_info(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct extent_buffer *eb,
+ struct btrfs_disk_key *key,
+ u64 flags_to_set, int update_gen);
int btrfs_free_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 bytenr, u64 num_bytes, u64 parent,
@@ -509,6 +509,9 @@ update_existing_head_ref(struct btrfs_de
sizeof(ref->extent_op->key));
existing_ref->extent_op->update_key = 1;
}
+ if (ref->extent_op->update_gen)
+ existing_ref->extent_op->update_gen = 1;
+
if (ref->extent_op->update_flags) {
existing_ref->extent_op->flags_to_set |=
ref->extent_op->flags_to_set;
@@ -58,6 +58,7 @@ struct btrfs_delayed_extent_op {
struct btrfs_disk_key key;
u64 flags_to_set;
unsigned int update_key:1;
+ unsigned int update_gen:1;
unsigned int update_flags:1;
unsigned int is_data:1;
};
@@ -46,7 +46,7 @@ static int __btrfs_free_extent(struct bt
struct btrfs_delayed_extent_op *extra_op);
static void __run_delayed_extent_op(struct btrfs_delayed_extent_op *extent_op,
struct extent_buffer *leaf,
- struct btrfs_extent_item *ei);
+ struct btrfs_extent_item *ei, u64 transid);
static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 parent, u64 root_objectid,
@@ -55,8 +55,8 @@ static int alloc_reserved_file_extent(st
static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 parent, u64 root_objectid,
- u64 flags, struct btrfs_disk_key *key,
- int level, struct btrfs_key *ins);
+ int level, struct btrfs_key *ins,
+ struct btrfs_delayed_extent_op *extent_op);
static int do_chunk_alloc(struct btrfs_trans_handle *trans,
struct btrfs_root *extent_root, u64 alloc_bytes,
u64 flags, int force);
@@ -1389,7 +1389,7 @@ int setup_inline_extent_backref(struct b
refs += refs_to_add;
btrfs_set_extent_refs(leaf, ei, refs);
if (extent_op)
- __run_delayed_extent_op(extent_op, leaf, ei);
+ __run_delayed_extent_op(extent_op, leaf, ei, trans->transid);
ptr = (unsigned long)ei + item_offset;
end = (unsigned long)ei + btrfs_item_size_nr(leaf, path->slots[0]);
@@ -1478,7 +1478,7 @@ int update_inline_extent_backref(struct
refs += refs_to_mod;
btrfs_set_extent_refs(leaf, ei, refs);
if (extent_op)
- __run_delayed_extent_op(extent_op, leaf, ei);
+ __run_delayed_extent_op(extent_op, leaf, ei, trans->transid);
type = btrfs_extent_inline_ref_type(leaf, iref);
@@ -1681,7 +1681,7 @@ static int __btrfs_inc_extent_ref(struct
refs = btrfs_extent_refs(leaf, item);
btrfs_set_extent_refs(leaf, item, refs + refs_to_add);
if (extent_op)
- __run_delayed_extent_op(extent_op, leaf, item);
+ __run_delayed_extent_op(extent_op, leaf, item, trans->transid);
btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(root->fs_info->extent_root, path);
@@ -1724,6 +1724,7 @@ static int run_delayed_data_ref(struct b
if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) {
if (extent_op) {
+ BUG_ON(extent_op->update_gen);
BUG_ON(extent_op->update_key);
flags |= extent_op->flags_to_set;
}
@@ -1751,7 +1752,7 @@ static int run_delayed_data_ref(struct b
static void __run_delayed_extent_op(struct btrfs_delayed_extent_op *extent_op,
struct extent_buffer *leaf,
- struct btrfs_extent_item *ei)
+ struct btrfs_extent_item *ei, u64 transid)
{
u64 flags = btrfs_extent_flags(leaf, ei);
if (extent_op->update_flags) {
@@ -1759,6 +1760,9 @@ static void __run_delayed_extent_op(stru
btrfs_set_extent_flags(leaf, ei, flags);
}
+ if (extent_op->update_gen)
+ btrfs_set_extent_generation(leaf, ei, transid);
+
if (extent_op->update_key) {
struct btrfs_tree_block_info *bi;
BUG_ON(!(flags & BTRFS_EXTENT_FLAG_TREE_BLOCK));
@@ -1817,7 +1821,7 @@ static int run_delayed_extent_op(struct
#endif
BUG_ON(item_size < sizeof(*ei));
ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
- __run_delayed_extent_op(extent_op, leaf, ei);
+ __run_delayed_extent_op(extent_op, leaf, ei, trans->transid);
btrfs_mark_buffer_dirty(leaf);
out:
@@ -1849,13 +1853,10 @@ static int run_delayed_tree_ref(struct b
BUG_ON(node->ref_mod != 1);
if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) {
- BUG_ON(!extent_op || !extent_op->update_flags ||
- !extent_op->update_key);
ret = alloc_reserved_tree_block(trans, root,
parent, ref_root,
- extent_op->flags_to_set,
- &extent_op->key,
- ref->level, &ins);
+ ref->level, &ins,
+ extent_op);
} else if (node->action == BTRFS_ADD_DELAYED_REF) {
ret = __btrfs_inc_extent_ref(trans, root, node->bytenr,
node->num_bytes, parent, ref_root,
@@ -2156,24 +2157,55 @@ out:
return 0;
}
-int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
+int btrfs_update_tree_block_key(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
- u64 bytenr, u64 num_bytes, u64 flags,
- int is_data)
+ struct extent_buffer *eb,
+ struct btrfs_disk_key *key)
{
struct btrfs_delayed_extent_op *extent_op;
int ret;
- extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
+ if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID)
+ return 0;
+
+ extent_op = kzalloc(sizeof(*extent_op), GFP_NOFS);
if (!extent_op)
return -ENOMEM;
- extent_op->flags_to_set = flags;
- extent_op->update_flags = 1;
- extent_op->update_key = 0;
- extent_op->is_data = is_data ? 1 : 0;
+ memcpy(&extent_op->key, key, sizeof(extent_op->key));
+ extent_op->update_key = 1;
- ret = btrfs_add_delayed_extent_op(trans, bytenr, num_bytes, extent_op);
+ ret = btrfs_add_delayed_extent_op(trans, eb->start, eb->len, extent_op);
+ if (ret)
+ kfree(extent_op);
+ return ret;
+}
+
+int btrfs_update_tree_block_info(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct extent_buffer *eb,
+ struct btrfs_disk_key *key,
+ u64 flags_to_set, int update_gen)
+{
+ struct btrfs_delayed_extent_op *extent_op;
+ int ret;
+
+ extent_op = kzalloc(sizeof(*extent_op), GFP_NOFS);
+ if (!extent_op)
+ return -ENOMEM;
+
+ if (key) {
+ memcpy(&extent_op->key, key, sizeof(extent_op->key));
+ extent_op->update_key = 1;
+ }
+ if (flags_to_set) {
+ extent_op->flags_to_set = flags_to_set;
+ extent_op->update_flags = 1;
+ }
+ if (update_gen)
+ extent_op->update_gen = 1;
+
+ ret = btrfs_add_delayed_extent_op(trans, eb->start, eb->len, extent_op);
if (ret)
kfree(extent_op);
return ret;
@@ -3883,7 +3915,8 @@ static int __btrfs_free_extent(struct bt
if (refs > 0) {
if (extent_op)
- __run_delayed_extent_op(extent_op, leaf, ei);
+ __run_delayed_extent_op(extent_op, leaf, ei,
+ trans->transid);
/*
* In the case of inline back ref, reference count will
* be updated by remove_extent_backref
@@ -4783,8 +4816,8 @@ static int alloc_reserved_file_extent(st
static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 parent, u64 root_objectid,
- u64 flags, struct btrfs_disk_key *key,
- int level, struct btrfs_key *ins)
+ int level, struct btrfs_key *ins,
+ struct btrfs_delayed_extent_op *extent_op)
{
int ret;
struct btrfs_fs_info *fs_info = root->fs_info;
@@ -4795,6 +4828,9 @@ static int alloc_reserved_tree_block(str
struct extent_buffer *leaf;
u32 size = sizeof(*extent_item) + sizeof(*block_info) + sizeof(*iref);
+ BUG_ON(!extent_op ||
+ !extent_op->update_flags || !extent_op->update_key);
+
path = btrfs_alloc_path();
BUG_ON(!path);
@@ -4807,17 +4843,23 @@ static int alloc_reserved_tree_block(str
extent_item = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_extent_item);
btrfs_set_extent_refs(leaf, extent_item, 1);
- btrfs_set_extent_generation(leaf, extent_item, trans->transid);
btrfs_set_extent_flags(leaf, extent_item,
- flags | BTRFS_EXTENT_FLAG_TREE_BLOCK);
- block_info = (struct btrfs_tree_block_info *)(extent_item + 1);
+ BTRFS_EXTENT_FLAG_TREE_BLOCK |
+ extent_op->flags_to_set);
+ if (extent_op->update_gen)
+ btrfs_set_extent_generation(leaf, extent_item,
+ trans->transid);
+ else
+ btrfs_set_extent_generation(leaf, extent_item, 0);
- btrfs_set_tree_block_key(leaf, block_info, key);
+ block_info = (struct btrfs_tree_block_info *)(extent_item + 1);
+ btrfs_set_tree_block_key(leaf, block_info, &extent_op->key);
btrfs_set_tree_block_level(leaf, block_info, level);
iref = (struct btrfs_extent_inline_ref *)(block_info + 1);
if (parent > 0) {
- BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF));
+ BUG_ON(!(extent_op->flags_to_set &
+ BTRFS_BLOCK_FLAG_FULL_BACKREF));
btrfs_set_extent_inline_ref_type(leaf, iref,
BTRFS_SHARED_BLOCK_REF_KEY);
btrfs_set_extent_inline_ref_offset(leaf, iref, parent);
@@ -4946,16 +4988,14 @@ static int alloc_tree_block(struct btrfs
if (root_objectid != BTRFS_TREE_LOG_OBJECTID) {
struct btrfs_delayed_extent_op *extent_op;
- extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS);
+ extent_op = kzalloc(sizeof(*extent_op), GFP_NOFS);
BUG_ON(!extent_op);
if (key)
memcpy(&extent_op->key, key, sizeof(extent_op->key));
- else
- memset(&extent_op->key, 0, sizeof(extent_op->key));
extent_op->flags_to_set = flags;
extent_op->update_key = 1;
+ extent_op->update_gen = 1;
extent_op->update_flags = 1;
- extent_op->is_data = 0;
ret = btrfs_add_delayed_tree_ref(trans, ins->objectid,
ins->offset, parent, root_objectid,
@@ -5193,8 +5233,8 @@ static noinline int walk_down_proc(struc
BUG_ON(ret);
ret = btrfs_dec_ref(trans, root, eb, 0);
BUG_ON(ret);
- ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
- eb->len, flag, 0);
+ ret = btrfs_update_tree_block_info(trans, root, eb,
+ NULL, flag, 0);
BUG_ON(ret);
wc->flags[level] |= flag;
}