diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2022-02-18 00:47:45 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2022-04-17 15:44:22 -0400 |
commit | e67afc22d44eebeeb029fd5af721d76fa663a4d4 (patch) | |
tree | 39ff79fe3062890d74cb7ab1bb23daa2b4ea16eb | |
parent | 231bd097449f7ddba5093f162049a52a13b6309c (diff) |
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: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r-- | fs/bcachefs/btree_cache.c | 9 | ||||
-rw-r--r-- | fs/bcachefs/btree_iter.c | 22 | ||||
-rw-r--r-- | fs/bcachefs/btree_types.h | 1 | ||||
-rw-r--r-- | include/trace/events/bcachefs.h | 8 |
4 files changed, 23 insertions, 17 deletions
diff --git a/fs/bcachefs/btree_cache.c b/fs/bcachefs/btree_cache.c index 986d08d708cc..6e6a8e5bcdaf 100644 --- a/fs/bcachefs/btree_cache.c +++ b/fs/bcachefs/btree_cache.c @@ -673,6 +673,15 @@ static noinline struct btree *bch2_btree_node_fill(struct bch_fs *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)) return b; diff --git a/fs/bcachefs/btree_iter.c b/fs/bcachefs/btree_iter.c index 1160fbad7748..66778bd92066 100644 --- a/fs/bcachefs/btree_iter.c +++ b/fs/bcachefs/btree_iter.c @@ -1420,12 +1420,12 @@ err: static int btree_path_traverse_one(struct btree_trans *, struct btree_path *, unsigned, unsigned long); -static int __btree_path_traverse_all(struct btree_trans *trans, int ret, - unsigned long trace_ip) +static int bch2_btree_path_traverse_all(struct btree_trans *trans) { struct bch_fs *c = trans->c; struct btree_path *path; - int i; + unsigned long trace_ip = _RET_IP_; + int i, ret = 0; if (trans->in_traverse_all) return -EINTR; @@ -1453,7 +1453,7 @@ retry_all: bch2_trans_unlock(trans); cond_resched(); - if (unlikely(ret == -ENOMEM)) { + if (unlikely(trans->memory_allocation_failure)) { struct closure cl; closure_init_stack(&cl); @@ -1464,11 +1464,6 @@ retry_all: } while (ret); } - if (unlikely(ret == -EIO)) - goto out; - - BUG_ON(ret && ret != -EINTR); - /* Now, redo traversals in correct order: */ i = 0; while (i < trans->nr_sorted) { @@ -1494,7 +1489,7 @@ retry_all: */ trans_for_each_path(trans, path) BUG_ON(path->uptodate >= BTREE_ITER_NEED_TRAVERSE); -out: + bch2_btree_cache_cannibalize_unlock(c); trans->in_traverse_all = false; @@ -1503,11 +1498,6 @@ out: 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, struct btree_path *path, unsigned l, int check_pos) @@ -1631,8 +1621,6 @@ out: 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, struct btree_path *path, unsigned flags) { diff --git a/fs/bcachefs/btree_types.h b/fs/bcachefs/btree_types.h index 68272f26f017..9ae5c8d56b2a 100644 --- a/fs/bcachefs/btree_types.h +++ b/fs/bcachefs/btree_types.h @@ -386,6 +386,7 @@ struct btree_trans { bool used_mempool:1; bool in_traverse_all:1; bool restarted:1; + bool memory_allocation_failure:1; bool journal_transaction_names:1; /* * For when bch2_trans_update notices we'll be splitting a compressed diff --git a/include/trace/events/bcachefs.h b/include/trace/events/bcachefs.h index a21a39230a09..8cf6669e2830 100644 --- a/include/trace/events/bcachefs.h +++ b/include/trace/events/bcachefs.h @@ -802,6 +802,14 @@ DEFINE_EVENT(transaction_restart_iter, trans_restart_traverse, 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, TP_PROTO(const char *trans_fn, unsigned long caller_ip, |