Commit 8f9ad91a authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Fix failure to allocate btree node in cache

The error code when we fail to allocate a node in the btree node cache
doesn't make it to bch2_btree_path_traverse_all(). Instead, we need to
stash a flag in btree_trans so we know we have to take the cannibalize
lock.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
parent bf7e49a4
...@@ -672,6 +672,15 @@ static noinline struct btree *bch2_btree_node_fill(struct bch_fs *c, ...@@ -672,6 +672,15 @@ static noinline struct btree *bch2_btree_node_fill(struct bch_fs *c,
} }
b = bch2_btree_node_mem_alloc(c); b = bch2_btree_node_mem_alloc(c);
if (trans && b == ERR_PTR(-ENOMEM)) {
trans->memory_allocation_failure = true;
trace_trans_restart_memory_allocation_failure(trans->fn,
_THIS_IP_, btree_id, &path->pos);
btree_trans_restart(trans);
return ERR_PTR(-EINTR);
}
if (IS_ERR(b)) if (IS_ERR(b))
return b; return b;
......
...@@ -1407,12 +1407,12 @@ static __always_inline int btree_path_down(struct btree_trans *trans, ...@@ -1407,12 +1407,12 @@ static __always_inline int btree_path_down(struct btree_trans *trans,
static int btree_path_traverse_one(struct btree_trans *, struct btree_path *, static int btree_path_traverse_one(struct btree_trans *, struct btree_path *,
unsigned, unsigned long); unsigned, unsigned long);
static int __btree_path_traverse_all(struct btree_trans *trans, int ret, static int bch2_btree_path_traverse_all(struct btree_trans *trans)
unsigned long trace_ip)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct btree_path *path, *prev = NULL; struct btree_path *path, *prev = NULL;
int i; unsigned long trace_ip = _RET_IP_;
int i, ret = 0;
if (trans->in_traverse_all) if (trans->in_traverse_all)
return -EINTR; return -EINTR;
...@@ -1441,7 +1441,7 @@ static int __btree_path_traverse_all(struct btree_trans *trans, int ret, ...@@ -1441,7 +1441,7 @@ static int __btree_path_traverse_all(struct btree_trans *trans, int ret,
bch2_trans_unlock(trans); bch2_trans_unlock(trans);
cond_resched(); cond_resched();
if (unlikely(ret == -ENOMEM)) { if (unlikely(trans->memory_allocation_failure)) {
struct closure cl; struct closure cl;
closure_init_stack(&cl); closure_init_stack(&cl);
...@@ -1452,11 +1452,6 @@ static int __btree_path_traverse_all(struct btree_trans *trans, int ret, ...@@ -1452,11 +1452,6 @@ static int __btree_path_traverse_all(struct btree_trans *trans, int ret,
} while (ret); } while (ret);
} }
if (unlikely(ret == -EIO))
goto out;
BUG_ON(ret && ret != -EINTR);
/* Now, redo traversals in correct order: */ /* Now, redo traversals in correct order: */
i = 0; i = 0;
while (i < trans->nr_sorted) { while (i < trans->nr_sorted) {
...@@ -1482,7 +1477,7 @@ static int __btree_path_traverse_all(struct btree_trans *trans, int ret, ...@@ -1482,7 +1477,7 @@ static int __btree_path_traverse_all(struct btree_trans *trans, int ret,
*/ */
trans_for_each_path(trans, path) trans_for_each_path(trans, path)
BUG_ON(path->uptodate >= BTREE_ITER_NEED_TRAVERSE); BUG_ON(path->uptodate >= BTREE_ITER_NEED_TRAVERSE);
out:
bch2_btree_cache_cannibalize_unlock(c); bch2_btree_cache_cannibalize_unlock(c);
trans->in_traverse_all = false; trans->in_traverse_all = false;
...@@ -1491,11 +1486,6 @@ static int __btree_path_traverse_all(struct btree_trans *trans, int ret, ...@@ -1491,11 +1486,6 @@ static int __btree_path_traverse_all(struct btree_trans *trans, int ret,
return ret; return ret;
} }
static int bch2_btree_path_traverse_all(struct btree_trans *trans)
{
return __btree_path_traverse_all(trans, 0, _RET_IP_);
}
static inline bool btree_path_good_node(struct btree_trans *trans, static inline bool btree_path_good_node(struct btree_trans *trans,
struct btree_path *path, struct btree_path *path,
unsigned l, int check_pos) unsigned l, int check_pos)
...@@ -1619,8 +1609,6 @@ static int btree_path_traverse_one(struct btree_trans *trans, ...@@ -1619,8 +1609,6 @@ static int btree_path_traverse_one(struct btree_trans *trans,
return ret; return ret;
} }
static int __btree_path_traverse_all(struct btree_trans *, int, unsigned long);
int __must_check bch2_btree_path_traverse(struct btree_trans *trans, int __must_check bch2_btree_path_traverse(struct btree_trans *trans,
struct btree_path *path, unsigned flags) struct btree_path *path, unsigned flags)
{ {
......
...@@ -393,6 +393,7 @@ struct btree_trans { ...@@ -393,6 +393,7 @@ struct btree_trans {
bool in_traverse_all:1; bool in_traverse_all:1;
bool restarted:1; bool restarted:1;
bool paths_sorted:1; bool paths_sorted:1;
bool memory_allocation_failure:1;
bool journal_transaction_names:1; bool journal_transaction_names:1;
bool journal_replay_not_finished:1; bool journal_replay_not_finished:1;
/* /*
......
...@@ -802,6 +802,14 @@ DEFINE_EVENT(transaction_restart_iter, trans_restart_traverse, ...@@ -802,6 +802,14 @@ DEFINE_EVENT(transaction_restart_iter, trans_restart_traverse,
TP_ARGS(trans_fn, caller_ip, btree_id, pos) TP_ARGS(trans_fn, caller_ip, btree_id, pos)
); );
DEFINE_EVENT(transaction_restart_iter, trans_restart_memory_allocation_failure,
TP_PROTO(const char *trans_fn,
unsigned long caller_ip,
enum btree_id btree_id,
struct bpos *pos),
TP_ARGS(trans_fn, caller_ip, btree_id, pos)
);
TRACE_EVENT(trans_restart_would_deadlock, TRACE_EVENT(trans_restart_would_deadlock,
TP_PROTO(const char *trans_fn, TP_PROTO(const char *trans_fn,
unsigned long caller_ip, unsigned long caller_ip,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment