struct extent_buffer *src_buf);
static void del_ptr(struct btrfs_root *root, struct btrfs_path *path,
int level, int slot);
-static int tree_mod_log_free_eb(struct btrfs_fs_info *fs_info,
- struct extent_buffer *eb);
struct btrfs_path *btrfs_alloc_path(void)
{
MOD_LOG_ROOT_REPLACE,
};
-struct tree_mod_move {
- int dst_slot;
- int nr_items;
-};
-
struct tree_mod_root {
u64 logical;
u8 level;
u64 blockptr;
/* this is used for op == MOD_LOG_MOVE_KEYS */
- struct tree_mod_move move;
+ struct {
+ int dst_slot;
+ int nr_items;
+ } move;
/* this is used for op == MOD_LOG_ROOT_REPLACE */
struct tree_mod_root old_root;
};
-static inline void tree_mod_log_read_lock(struct btrfs_fs_info *fs_info)
-{
- read_lock(&fs_info->tree_mod_log_lock);
-}
-
-static inline void tree_mod_log_read_unlock(struct btrfs_fs_info *fs_info)
-{
- read_unlock(&fs_info->tree_mod_log_lock);
-}
-
-static inline void tree_mod_log_write_lock(struct btrfs_fs_info *fs_info)
-{
- write_lock(&fs_info->tree_mod_log_lock);
-}
-
-static inline void tree_mod_log_write_unlock(struct btrfs_fs_info *fs_info)
-{
- write_unlock(&fs_info->tree_mod_log_lock);
-}
-
/*
* Pull a new tree mod seq number for our operation.
*/
u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info,
struct seq_list *elem)
{
- tree_mod_log_write_lock(fs_info);
+ write_lock(&fs_info->tree_mod_log_lock);
spin_lock(&fs_info->tree_mod_seq_lock);
if (!elem->seq) {
elem->seq = btrfs_inc_tree_mod_seq(fs_info);
list_add_tail(&elem->list, &fs_info->tree_mod_seq_list);
}
spin_unlock(&fs_info->tree_mod_seq_lock);
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
return elem->seq;
}
* anything that's lower than the lowest existing (read: blocked)
* sequence number can be removed from the tree.
*/
- tree_mod_log_write_lock(fs_info);
+ write_lock(&fs_info->tree_mod_log_lock);
tm_root = &fs_info->tree_mod_log;
for (node = rb_first(tm_root); node; node = next) {
next = rb_next(node);
rb_erase(node, tm_root);
kfree(tm);
}
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
}
/*
* for root replace operations, or the logical address of the affected
* block for all other operations.
*
- * Note: must be called with write lock (tree_mod_log_write_lock).
+ * Note: must be called with write lock for fs_info::tree_mod_log_lock.
*/
static noinline int
__tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
* Determines if logging can be omitted. Returns 1 if it can. Otherwise, it
* returns zero with the tree_mod_log_lock acquired. The caller must hold
* this until all tree mod log insertions are recorded in the rb tree and then
- * call tree_mod_log_write_unlock() to release.
+ * write unlock fs_info::tree_mod_log_lock.
*/
static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info,
struct extent_buffer *eb) {
if (eb && btrfs_header_level(eb) == 0)
return 1;
- tree_mod_log_write_lock(fs_info);
+ write_lock(&fs_info->tree_mod_log_lock);
if (list_empty(&(fs_info)->tree_mod_seq_list)) {
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
return 1;
}
return tm;
}
-static noinline int
-tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
- struct extent_buffer *eb, int slot,
- enum mod_log_op op, gfp_t flags)
+static noinline int tree_mod_log_insert_key(struct extent_buffer *eb, int slot,
+ enum mod_log_op op, gfp_t flags)
{
struct tree_mod_elem *tm;
int ret;
- if (!tree_mod_need_log(fs_info, eb))
+ if (!tree_mod_need_log(eb->fs_info, eb))
return 0;
tm = alloc_tree_mod_elem(eb, slot, op, flags);
if (!tm)
return -ENOMEM;
- if (tree_mod_dont_log(fs_info, eb)) {
+ if (tree_mod_dont_log(eb->fs_info, eb)) {
kfree(tm);
return 0;
}
- ret = __tree_mod_log_insert(fs_info, tm);
- tree_mod_log_write_unlock(fs_info);
+ ret = __tree_mod_log_insert(eb->fs_info, tm);
+ write_unlock(&eb->fs_info->tree_mod_log_lock);
if (ret)
kfree(tm);
return ret;
}
-static noinline int
-tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
- struct extent_buffer *eb, int dst_slot, int src_slot,
- int nr_items)
+static noinline int tree_mod_log_insert_move(struct extent_buffer *eb,
+ int dst_slot, int src_slot, int nr_items)
{
struct tree_mod_elem *tm = NULL;
struct tree_mod_elem **tm_list = NULL;
int i;
int locked = 0;
- if (!tree_mod_need_log(fs_info, eb))
+ if (!tree_mod_need_log(eb->fs_info, eb))
return 0;
tm_list = kcalloc(nr_items, sizeof(struct tree_mod_elem *), GFP_NOFS);
}
}
- if (tree_mod_dont_log(fs_info, eb))
+ if (tree_mod_dont_log(eb->fs_info, eb))
goto free_tms;
locked = 1;
* buffer, i.e. dst_slot < src_slot.
*/
for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
- ret = __tree_mod_log_insert(fs_info, tm_list[i]);
+ ret = __tree_mod_log_insert(eb->fs_info, tm_list[i]);
if (ret)
goto free_tms;
}
- ret = __tree_mod_log_insert(fs_info, tm);
+ ret = __tree_mod_log_insert(eb->fs_info, tm);
if (ret)
goto free_tms;
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&eb->fs_info->tree_mod_log_lock);
kfree(tm_list);
return 0;
free_tms:
for (i = 0; i < nr_items; i++) {
if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node))
- rb_erase(&tm_list[i]->node, &fs_info->tree_mod_log);
+ rb_erase(&tm_list[i]->node, &eb->fs_info->tree_mod_log);
kfree(tm_list[i]);
}
if (locked)
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&eb->fs_info->tree_mod_log_lock);
kfree(tm_list);
kfree(tm);
return 0;
}
-static noinline int
-tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
- struct extent_buffer *old_root,
- struct extent_buffer *new_root,
- int log_removal)
+static noinline int tree_mod_log_insert_root(struct extent_buffer *old_root,
+ struct extent_buffer *new_root, int log_removal)
{
+ struct btrfs_fs_info *fs_info = old_root->fs_info;
struct tree_mod_elem *tm = NULL;
struct tree_mod_elem **tm_list = NULL;
int nritems = 0;
if (!ret)
ret = __tree_mod_log_insert(fs_info, tm);
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
if (ret)
goto free_tms;
kfree(tm_list);
struct tree_mod_elem *cur = NULL;
struct tree_mod_elem *found = NULL;
- tree_mod_log_read_lock(fs_info);
+ read_lock(&fs_info->tree_mod_log_lock);
tm_root = &fs_info->tree_mod_log;
node = tm_root->rb_node;
while (node) {
break;
}
}
- tree_mod_log_read_unlock(fs_info);
+ read_unlock(&fs_info->tree_mod_log_lock);
return found;
}
goto free_tms;
}
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
kfree(tm_list);
return 0;
kfree(tm_list[i]);
}
if (locked)
- tree_mod_log_write_unlock(fs_info);
+ write_unlock(&fs_info->tree_mod_log_lock);
kfree(tm_list);
return ret;
}
-static inline void
-tree_mod_log_eb_move(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
- int dst_offset, int src_offset, int nr_items)
-{
- int ret;
- ret = tree_mod_log_insert_move(fs_info, dst, dst_offset, src_offset,
- nr_items);
- BUG_ON(ret < 0);
-}
-
-static noinline void
-tree_mod_log_set_node_key(struct btrfs_fs_info *fs_info,
- struct extent_buffer *eb, int slot, int atomic)
-{
- int ret;
-
- ret = tree_mod_log_insert_key(fs_info, eb, slot,
- MOD_LOG_KEY_REPLACE,
- atomic ? GFP_ATOMIC : GFP_NOFS);
- BUG_ON(ret < 0);
-}
-
-static noinline int
-tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
+static noinline int tree_mod_log_free_eb(struct extent_buffer *eb)
{
struct tree_mod_elem **tm_list = NULL;
int nritems = 0;
if (btrfs_header_level(eb) == 0)
return 0;
- if (!tree_mod_need_log(fs_info, NULL))
+ if (!tree_mod_need_log(eb->fs_info, NULL))
return 0;
nritems = btrfs_header_nritems(eb);
}
}
- if (tree_mod_dont_log(fs_info, eb))
+ if (tree_mod_dont_log(eb->fs_info, eb))
goto free_tms;
- ret = __tree_mod_log_free_eb(fs_info, tm_list, nritems);
- tree_mod_log_write_unlock(fs_info);
+ ret = __tree_mod_log_free_eb(eb->fs_info, tm_list, nritems);
+ write_unlock(&eb->fs_info->tree_mod_log_lock);
if (ret)
goto free_tms;
kfree(tm_list);
int log_removal)
{
int ret;
- ret = tree_mod_log_insert_root(root->fs_info, root->node,
- new_root_node, log_removal);
+ ret = tree_mod_log_insert_root(root->node, new_root_node, log_removal);
BUG_ON(ret < 0);
}
add_root_to_dirty_list(root);
} else {
WARN_ON(trans->transid != btrfs_header_generation(parent));
- tree_mod_log_insert_key(fs_info, parent, parent_slot,
+ tree_mod_log_insert_key(parent, parent_slot,
MOD_LOG_KEY_REPLACE, GFP_NOFS);
btrfs_set_node_blockptr(parent, parent_slot,
cow->start);
trans->transid);
btrfs_mark_buffer_dirty(parent);
if (last_ref) {
- ret = tree_mod_log_free_eb(fs_info, buf);
+ ret = tree_mod_log_free_eb(buf);
if (ret) {
btrfs_abort_transaction(trans, ret);
return ret;
* returns the logical address of the oldest predecessor of the given root.
* entries older than time_seq are ignored.
*/
-static struct tree_mod_elem *
-__tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info,
- struct extent_buffer *eb_root, u64 time_seq)
+static struct tree_mod_elem *__tree_mod_log_oldest_root(
+ struct extent_buffer *eb_root, u64 time_seq)
{
struct tree_mod_elem *tm;
struct tree_mod_elem *found = NULL;
* first operation that's logged for this root.
*/
while (1) {
- tm = tree_mod_log_search_oldest(fs_info, root_logical,
+ tm = tree_mod_log_search_oldest(eb_root->fs_info, root_logical,
time_seq);
if (!looped && !tm)
return NULL;
unsigned long p_size = sizeof(struct btrfs_key_ptr);
n = btrfs_header_nritems(eb);
- tree_mod_log_read_lock(fs_info);
+ read_lock(&fs_info->tree_mod_log_lock);
while (tm && tm->seq >= time_seq) {
/*
* all the operations are recorded with the operator used for
if (tm->logical != first_tm->logical)
break;
}
- tree_mod_log_read_unlock(fs_info);
+ read_unlock(&fs_info->tree_mod_log_lock);
btrfs_set_header_nritems(eb, n);
}
u64 logical;
eb_root = btrfs_read_lock_root_node(root);
- tm = __tree_mod_log_oldest_root(fs_info, eb_root, time_seq);
+ tm = __tree_mod_log_oldest_root(eb_root, time_seq);
if (!tm)
return eb_root;
int level;
struct extent_buffer *eb_root = btrfs_root_node(root);
- tm = __tree_mod_log_oldest_root(root->fs_info, eb_root, time_seq);
+ tm = __tree_mod_log_oldest_root(eb_root, time_seq);
if (tm && tm->op == MOD_LOG_ROOT_REPLACE) {
level = tm->old_root.level;
} else {
} else {
struct btrfs_disk_key right_key;
btrfs_node_key(right, &right_key, 0);
- tree_mod_log_set_node_key(fs_info, parent,
- pslot + 1, 0);
+ ret = tree_mod_log_insert_key(parent, pslot + 1,
+ MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &right_key, pslot + 1);
btrfs_mark_buffer_dirty(parent);
}
/* update the parent key to reflect our changes */
struct btrfs_disk_key mid_key;
btrfs_node_key(mid, &mid_key, 0);
- tree_mod_log_set_node_key(fs_info, parent, pslot, 0);
+ ret = tree_mod_log_insert_key(parent, pslot,
+ MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &mid_key, pslot);
btrfs_mark_buffer_dirty(parent);
}
struct btrfs_disk_key disk_key;
orig_slot += left_nr;
btrfs_node_key(mid, &disk_key, 0);
- tree_mod_log_set_node_key(fs_info, parent, pslot, 0);
+ ret = tree_mod_log_insert_key(parent, pslot,
+ MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &disk_key, pslot);
btrfs_mark_buffer_dirty(parent);
if (btrfs_header_nritems(left) > orig_slot) {
struct btrfs_disk_key disk_key;
btrfs_node_key(right, &disk_key, 0);
- tree_mod_log_set_node_key(fs_info, parent,
- pslot + 1, 0);
+ ret = tree_mod_log_insert_key(parent, pslot + 1,
+ MOD_LOG_KEY_REPLACE, GFP_NOFS);
+ BUG_ON(ret < 0);
btrfs_set_node_key(parent, &disk_key, pslot + 1);
btrfs_mark_buffer_dirty(parent);
{
int i;
struct extent_buffer *t;
+ int ret;
for (i = level; i < BTRFS_MAX_LEVEL; i++) {
int tslot = path->slots[i];
+
if (!path->nodes[i])
break;
t = path->nodes[i];
- tree_mod_log_set_node_key(fs_info, t, tslot, 1);
+ ret = tree_mod_log_insert_key(t, tslot, MOD_LOG_KEY_REPLACE,
+ GFP_ATOMIC);
+ BUG_ON(ret < 0);
btrfs_set_node_key(t, key, tslot);
btrfs_mark_buffer_dirty(path->nodes[i]);
if (tslot != 0)
if (push_items < src_nritems) {
/*
- * don't call tree_mod_log_eb_move here, key removal was already
- * fully logged by tree_mod_log_eb_copy above.
+ * Don't call tree_mod_log_insert_move here, key removal was
+ * already fully logged by tree_mod_log_eb_copy above.
*/
memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0),
btrfs_node_key_ptr_offset(push_items),
if (max_push < push_items)
push_items = max_push;
- tree_mod_log_eb_move(fs_info, dst, push_items, 0, dst_nritems);
+ ret = tree_mod_log_insert_move(dst, push_items, 0, dst_nritems);
+ BUG_ON(ret < 0);
memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(push_items),
btrfs_node_key_ptr_offset(0),
(dst_nritems) *
BUG_ON(slot > nritems);
BUG_ON(nritems == BTRFS_NODEPTRS_PER_BLOCK(fs_info));
if (slot != nritems) {
- if (level)
- tree_mod_log_eb_move(fs_info, lower, slot + 1,
- slot, nritems - slot);
+ if (level) {
+ ret = tree_mod_log_insert_move(lower, slot + 1, slot,
+ nritems - slot);
+ BUG_ON(ret < 0);
+ }
memmove_extent_buffer(lower,
btrfs_node_key_ptr_offset(slot + 1),
btrfs_node_key_ptr_offset(slot),
(nritems - slot) * sizeof(struct btrfs_key_ptr));
}
if (level) {
- ret = tree_mod_log_insert_key(fs_info, lower, slot,
- MOD_LOG_KEY_ADD, GFP_NOFS);
+ ret = tree_mod_log_insert_key(lower, slot, MOD_LOG_KEY_ADD,
+ GFP_NOFS);
BUG_ON(ret < 0);
}
btrfs_set_node_key(lower, key, slot);
nritems = btrfs_header_nritems(parent);
if (slot != nritems - 1) {
- if (level)
- tree_mod_log_eb_move(fs_info, parent, slot,
- slot + 1, nritems - slot - 1);
+ if (level) {
+ ret = tree_mod_log_insert_move(parent, slot, slot + 1,
+ nritems - slot - 1);
+ BUG_ON(ret < 0);
+ }
memmove_extent_buffer(parent,
btrfs_node_key_ptr_offset(slot),
btrfs_node_key_ptr_offset(slot + 1),
sizeof(struct btrfs_key_ptr) *
(nritems - slot - 1));
} else if (level) {
- ret = tree_mod_log_insert_key(fs_info, parent, slot,
- MOD_LOG_KEY_REMOVE, GFP_NOFS);
+ ret = tree_mod_log_insert_key(parent, slot, MOD_LOG_KEY_REMOVE,
+ GFP_NOFS);
BUG_ON(ret < 0);
}