summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2022-02-18 00:47:45 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2022-04-17 15:44:22 -0400
commite67afc22d44eebeeb029fd5af721d76fa663a4d4 (patch)
tree39ff79fe3062890d74cb7ab1bb23daa2b4ea16eb
parent231bd097449f7ddba5093f162049a52a13b6309c (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.c9
-rw-r--r--fs/bcachefs/btree_iter.c22
-rw-r--r--fs/bcachefs/btree_types.h1
-rw-r--r--include/trace/events/bcachefs.h8
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,