|
@@ -484,8 +484,27 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
|
|
struct rb_node **new;
|
|
struct rb_node **new;
|
|
struct rb_node *parent = NULL;
|
|
struct rb_node *parent = NULL;
|
|
struct tree_mod_elem *cur;
|
|
struct tree_mod_elem *cur;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ BUG_ON(!tm);
|
|
|
|
+
|
|
|
|
+ tree_mod_log_write_lock(fs_info);
|
|
|
|
+ if (list_empty(&fs_info->tree_mod_seq_list)) {
|
|
|
|
+ tree_mod_log_write_unlock(fs_info);
|
|
|
|
+ /*
|
|
|
|
+ * Ok we no longer care about logging modifications, free up tm
|
|
|
|
+ * and return 0. Any callers shouldn't be using tm after
|
|
|
|
+ * calling tree_mod_log_insert, but if they do we can just
|
|
|
|
+ * change this to return a special error code to let the callers
|
|
|
|
+ * do their own thing.
|
|
|
|
+ */
|
|
|
|
+ kfree(tm);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
|
|
- BUG_ON(!tm || !tm->seq);
|
|
|
|
|
|
+ spin_lock(&fs_info->tree_mod_seq_lock);
|
|
|
|
+ tm->seq = btrfs_inc_tree_mod_seq_minor(fs_info);
|
|
|
|
+ spin_unlock(&fs_info->tree_mod_seq_lock);
|
|
|
|
|
|
tm_root = &fs_info->tree_mod_log;
|
|
tm_root = &fs_info->tree_mod_log;
|
|
new = &tm_root->rb_node;
|
|
new = &tm_root->rb_node;
|
|
@@ -501,14 +520,17 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
|
|
else if (cur->seq > tm->seq)
|
|
else if (cur->seq > tm->seq)
|
|
new = &((*new)->rb_right);
|
|
new = &((*new)->rb_right);
|
|
else {
|
|
else {
|
|
|
|
+ ret = -EEXIST;
|
|
kfree(tm);
|
|
kfree(tm);
|
|
- return -EEXIST;
|
|
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
rb_link_node(&tm->node, parent, new);
|
|
rb_link_node(&tm->node, parent, new);
|
|
rb_insert_color(&tm->node, tm_root);
|
|
rb_insert_color(&tm->node, tm_root);
|
|
- return 0;
|
|
|
|
|
|
+out:
|
|
|
|
+ tree_mod_log_write_unlock(fs_info);
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -524,57 +546,19 @@ static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info,
|
|
return 1;
|
|
return 1;
|
|
if (eb && btrfs_header_level(eb) == 0)
|
|
if (eb && btrfs_header_level(eb) == 0)
|
|
return 1;
|
|
return 1;
|
|
-
|
|
|
|
- tree_mod_log_write_lock(fs_info);
|
|
|
|
- if (list_empty(&fs_info->tree_mod_seq_list)) {
|
|
|
|
- /*
|
|
|
|
- * someone emptied the list while we were waiting for the lock.
|
|
|
|
- * we must not add to the list when no blocker exists.
|
|
|
|
- */
|
|
|
|
- tree_mod_log_write_unlock(fs_info);
|
|
|
|
- return 1;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * This allocates memory and gets a tree modification sequence number.
|
|
|
|
- *
|
|
|
|
- * Returns <0 on error.
|
|
|
|
- * Returns >0 (the added sequence number) on success.
|
|
|
|
- */
|
|
|
|
-static inline int tree_mod_alloc(struct btrfs_fs_info *fs_info, gfp_t flags,
|
|
|
|
- struct tree_mod_elem **tm_ret)
|
|
|
|
-{
|
|
|
|
- struct tree_mod_elem *tm;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * once we switch from spin locks to something different, we should
|
|
|
|
- * honor the flags parameter here.
|
|
|
|
- */
|
|
|
|
- tm = *tm_ret = kzalloc(sizeof(*tm), GFP_ATOMIC);
|
|
|
|
- if (!tm)
|
|
|
|
- return -ENOMEM;
|
|
|
|
-
|
|
|
|
- spin_lock(&fs_info->tree_mod_seq_lock);
|
|
|
|
- tm->seq = btrfs_inc_tree_mod_seq_minor(fs_info);
|
|
|
|
- spin_unlock(&fs_info->tree_mod_seq_lock);
|
|
|
|
-
|
|
|
|
- return tm->seq;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static inline int
|
|
static inline int
|
|
__tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
|
|
__tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
|
|
struct extent_buffer *eb, int slot,
|
|
struct extent_buffer *eb, int slot,
|
|
enum mod_log_op op, gfp_t flags)
|
|
enum mod_log_op op, gfp_t flags)
|
|
{
|
|
{
|
|
- int ret;
|
|
|
|
struct tree_mod_elem *tm;
|
|
struct tree_mod_elem *tm;
|
|
|
|
|
|
- ret = tree_mod_alloc(fs_info, flags, &tm);
|
|
|
|
- if (ret < 0)
|
|
|
|
- return ret;
|
|
|
|
|
|
+ tm = kzalloc(sizeof(*tm), flags);
|
|
|
|
+ if (!tm)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
tm->index = eb->start >> PAGE_CACHE_SHIFT;
|
|
tm->index = eb->start >> PAGE_CACHE_SHIFT;
|
|
if (op != MOD_LOG_KEY_ADD) {
|
|
if (op != MOD_LOG_KEY_ADD) {
|
|
@@ -589,34 +573,14 @@ __tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
|
|
}
|
|
}
|
|
|
|
|
|
static noinline int
|
|
static noinline int
|
|
-tree_mod_log_insert_key_mask(struct btrfs_fs_info *fs_info,
|
|
|
|
- struct extent_buffer *eb, int slot,
|
|
|
|
- enum mod_log_op op, gfp_t flags)
|
|
|
|
|
|
+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)
|
|
{
|
|
{
|
|
- int ret;
|
|
|
|
-
|
|
|
|
if (tree_mod_dont_log(fs_info, eb))
|
|
if (tree_mod_dont_log(fs_info, eb))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- ret = __tree_mod_log_insert_key(fs_info, eb, slot, op, flags);
|
|
|
|
-
|
|
|
|
- tree_mod_log_write_unlock(fs_info);
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-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)
|
|
|
|
-{
|
|
|
|
- return tree_mod_log_insert_key_mask(fs_info, eb, slot, op, GFP_NOFS);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static noinline int
|
|
|
|
-tree_mod_log_insert_key_locked(struct btrfs_fs_info *fs_info,
|
|
|
|
- struct extent_buffer *eb, int slot,
|
|
|
|
- enum mod_log_op op)
|
|
|
|
-{
|
|
|
|
- return __tree_mod_log_insert_key(fs_info, eb, slot, op, GFP_NOFS);
|
|
|
|
|
|
+ return __tree_mod_log_insert_key(fs_info, eb, slot, op, flags);
|
|
}
|
|
}
|
|
|
|
|
|
static noinline int
|
|
static noinline int
|
|
@@ -637,14 +601,14 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
|
|
* buffer, i.e. dst_slot < src_slot.
|
|
* buffer, i.e. dst_slot < src_slot.
|
|
*/
|
|
*/
|
|
for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
|
|
for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
|
|
- ret = tree_mod_log_insert_key_locked(fs_info, eb, i + dst_slot,
|
|
|
|
- MOD_LOG_KEY_REMOVE_WHILE_MOVING);
|
|
|
|
|
|
+ ret = __tree_mod_log_insert_key(fs_info, eb, i + dst_slot,
|
|
|
|
+ MOD_LOG_KEY_REMOVE_WHILE_MOVING, GFP_NOFS);
|
|
BUG_ON(ret < 0);
|
|
BUG_ON(ret < 0);
|
|
}
|
|
}
|
|
|
|
|
|
- ret = tree_mod_alloc(fs_info, flags, &tm);
|
|
|
|
- if (ret < 0)
|
|
|
|
- goto out;
|
|
|
|
|
|
+ tm = kzalloc(sizeof(*tm), flags);
|
|
|
|
+ if (!tm)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
tm->index = eb->start >> PAGE_CACHE_SHIFT;
|
|
tm->index = eb->start >> PAGE_CACHE_SHIFT;
|
|
tm->slot = src_slot;
|
|
tm->slot = src_slot;
|
|
@@ -652,10 +616,7 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
|
|
tm->move.nr_items = nr_items;
|
|
tm->move.nr_items = nr_items;
|
|
tm->op = MOD_LOG_MOVE_KEYS;
|
|
tm->op = MOD_LOG_MOVE_KEYS;
|
|
|
|
|
|
- ret = __tree_mod_log_insert(fs_info, tm);
|
|
|
|
-out:
|
|
|
|
- tree_mod_log_write_unlock(fs_info);
|
|
|
|
- return ret;
|
|
|
|
|
|
+ return __tree_mod_log_insert(fs_info, tm);
|
|
}
|
|
}
|
|
|
|
|
|
static inline void
|
|
static inline void
|
|
@@ -670,8 +631,8 @@ __tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
|
|
|
|
|
|
nritems = btrfs_header_nritems(eb);
|
|
nritems = btrfs_header_nritems(eb);
|
|
for (i = nritems - 1; i >= 0; i--) {
|
|
for (i = nritems - 1; i >= 0; i--) {
|
|
- ret = tree_mod_log_insert_key_locked(fs_info, eb, i,
|
|
|
|
- MOD_LOG_KEY_REMOVE_WHILE_FREEING);
|
|
|
|
|
|
+ ret = __tree_mod_log_insert_key(fs_info, eb, i,
|
|
|
|
+ MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS);
|
|
BUG_ON(ret < 0);
|
|
BUG_ON(ret < 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -683,7 +644,6 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
|
|
int log_removal)
|
|
int log_removal)
|
|
{
|
|
{
|
|
struct tree_mod_elem *tm;
|
|
struct tree_mod_elem *tm;
|
|
- int ret;
|
|
|
|
|
|
|
|
if (tree_mod_dont_log(fs_info, NULL))
|
|
if (tree_mod_dont_log(fs_info, NULL))
|
|
return 0;
|
|
return 0;
|
|
@@ -691,9 +651,9 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
|
|
if (log_removal)
|
|
if (log_removal)
|
|
__tree_mod_log_free_eb(fs_info, old_root);
|
|
__tree_mod_log_free_eb(fs_info, old_root);
|
|
|
|
|
|
- ret = tree_mod_alloc(fs_info, flags, &tm);
|
|
|
|
- if (ret < 0)
|
|
|
|
- goto out;
|
|
|
|
|
|
+ tm = kzalloc(sizeof(*tm), flags);
|
|
|
|
+ if (!tm)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
tm->index = new_root->start >> PAGE_CACHE_SHIFT;
|
|
tm->index = new_root->start >> PAGE_CACHE_SHIFT;
|
|
tm->old_root.logical = old_root->start;
|
|
tm->old_root.logical = old_root->start;
|
|
@@ -701,10 +661,7 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
|
|
tm->generation = btrfs_header_generation(old_root);
|
|
tm->generation = btrfs_header_generation(old_root);
|
|
tm->op = MOD_LOG_ROOT_REPLACE;
|
|
tm->op = MOD_LOG_ROOT_REPLACE;
|
|
|
|
|
|
- ret = __tree_mod_log_insert(fs_info, tm);
|
|
|
|
-out:
|
|
|
|
- tree_mod_log_write_unlock(fs_info);
|
|
|
|
- return ret;
|
|
|
|
|
|
+ return __tree_mod_log_insert(fs_info, tm);
|
|
}
|
|
}
|
|
|
|
|
|
static struct tree_mod_elem *
|
|
static struct tree_mod_elem *
|
|
@@ -784,23 +741,20 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
|
|
if (tree_mod_dont_log(fs_info, NULL))
|
|
if (tree_mod_dont_log(fs_info, NULL))
|
|
return;
|
|
return;
|
|
|
|
|
|
- if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0) {
|
|
|
|
- tree_mod_log_write_unlock(fs_info);
|
|
|
|
|
|
+ if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0)
|
|
return;
|
|
return;
|
|
- }
|
|
|
|
|
|
|
|
for (i = 0; i < nr_items; i++) {
|
|
for (i = 0; i < nr_items; i++) {
|
|
- ret = tree_mod_log_insert_key_locked(fs_info, src,
|
|
|
|
|
|
+ ret = __tree_mod_log_insert_key(fs_info, src,
|
|
i + src_offset,
|
|
i + src_offset,
|
|
- MOD_LOG_KEY_REMOVE);
|
|
|
|
|
|
+ MOD_LOG_KEY_REMOVE, GFP_NOFS);
|
|
BUG_ON(ret < 0);
|
|
BUG_ON(ret < 0);
|
|
- ret = tree_mod_log_insert_key_locked(fs_info, dst,
|
|
|
|
|
|
+ ret = __tree_mod_log_insert_key(fs_info, dst,
|
|
i + dst_offset,
|
|
i + dst_offset,
|
|
- MOD_LOG_KEY_ADD);
|
|
|
|
|
|
+ MOD_LOG_KEY_ADD,
|
|
|
|
+ GFP_NOFS);
|
|
BUG_ON(ret < 0);
|
|
BUG_ON(ret < 0);
|
|
}
|
|
}
|
|
-
|
|
|
|
- tree_mod_log_write_unlock(fs_info);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static inline void
|
|
static inline void
|
|
@@ -819,9 +773,9 @@ tree_mod_log_set_node_key(struct btrfs_fs_info *fs_info,
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- ret = tree_mod_log_insert_key_mask(fs_info, eb, slot,
|
|
|
|
- MOD_LOG_KEY_REPLACE,
|
|
|
|
- atomic ? GFP_ATOMIC : GFP_NOFS);
|
|
|
|
|
|
+ ret = __tree_mod_log_insert_key(fs_info, eb, slot,
|
|
|
|
+ MOD_LOG_KEY_REPLACE,
|
|
|
|
+ atomic ? GFP_ATOMIC : GFP_NOFS);
|
|
BUG_ON(ret < 0);
|
|
BUG_ON(ret < 0);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -830,10 +784,7 @@ tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
|
|
{
|
|
{
|
|
if (tree_mod_dont_log(fs_info, eb))
|
|
if (tree_mod_dont_log(fs_info, eb))
|
|
return;
|
|
return;
|
|
-
|
|
|
|
__tree_mod_log_free_eb(fs_info, eb);
|
|
__tree_mod_log_free_eb(fs_info, eb);
|
|
-
|
|
|
|
- tree_mod_log_write_unlock(fs_info);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static noinline void
|
|
static noinline void
|
|
@@ -1083,7 +1034,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
WARN_ON(trans->transid != btrfs_header_generation(parent));
|
|
WARN_ON(trans->transid != btrfs_header_generation(parent));
|
|
tree_mod_log_insert_key(root->fs_info, parent, parent_slot,
|
|
tree_mod_log_insert_key(root->fs_info, parent, parent_slot,
|
|
- MOD_LOG_KEY_REPLACE);
|
|
|
|
|
|
+ MOD_LOG_KEY_REPLACE, GFP_NOFS);
|
|
btrfs_set_node_blockptr(parent, parent_slot,
|
|
btrfs_set_node_blockptr(parent, parent_slot,
|
|
cow->start);
|
|
cow->start);
|
|
btrfs_set_node_ptr_generation(parent, parent_slot,
|
|
btrfs_set_node_ptr_generation(parent, parent_slot,
|
|
@@ -3208,7 +3159,7 @@ static void insert_ptr(struct btrfs_trans_handle *trans,
|
|
}
|
|
}
|
|
if (level) {
|
|
if (level) {
|
|
ret = tree_mod_log_insert_key(root->fs_info, lower, slot,
|
|
ret = tree_mod_log_insert_key(root->fs_info, lower, slot,
|
|
- MOD_LOG_KEY_ADD);
|
|
|
|
|
|
+ MOD_LOG_KEY_ADD, GFP_NOFS);
|
|
BUG_ON(ret < 0);
|
|
BUG_ON(ret < 0);
|
|
}
|
|
}
|
|
btrfs_set_node_key(lower, key, slot);
|
|
btrfs_set_node_key(lower, key, slot);
|
|
@@ -4642,7 +4593,7 @@ static void del_ptr(struct btrfs_root *root, struct btrfs_path *path,
|
|
(nritems - slot - 1));
|
|
(nritems - slot - 1));
|
|
} else if (level) {
|
|
} else if (level) {
|
|
ret = tree_mod_log_insert_key(root->fs_info, parent, slot,
|
|
ret = tree_mod_log_insert_key(root->fs_info, parent, slot,
|
|
- MOD_LOG_KEY_REMOVE);
|
|
|
|
|
|
+ MOD_LOG_KEY_REMOVE, GFP_NOFS);
|
|
BUG_ON(ret < 0);
|
|
BUG_ON(ret < 0);
|
|
}
|
|
}
|
|
|
|
|