diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2022-07-05 18:37:42 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2022-08-17 16:29:55 -0400 |
commit | 577e88c8e822c9cadf59c61286e52854c93cfc11 (patch) | |
tree | d39133e3ff0b20c244d070f275913e18aae11272 | |
parent | e222af1d60b60db5a49efb000e93a5e45c9d089a (diff) |
bcachefs: Don't drop locks unnecessarily in bch2_btree_update_start()
This is to fix a livelock in the btree split path described by the
previous patch.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r-- | fs/bcachefs/btree_update_interior.c | 71 | ||||
-rw-r--r-- | include/trace/events/bcachefs.h | 23 |
2 files changed, 54 insertions, 40 deletions
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c index 8df1e8f007b5..0409737f757a 100644 --- a/fs/bcachefs/btree_update_interior.c +++ b/fs/bcachefs/btree_update_interior.c @@ -416,16 +416,13 @@ static void bch2_btree_reserve_put(struct btree_update *as) static int bch2_btree_reserve_get(struct btree_trans *trans, struct btree_update *as, unsigned nr_nodes[2], - unsigned flags) + unsigned flags, + struct closure *cl) { struct bch_fs *c = as->c; - struct closure cl; struct btree *b; unsigned interior; - int ret; - - closure_init_stack(&cl); -retry: + int ret = 0; BUG_ON(nr_nodes[0] + nr_nodes[1] > BTREE_RESERVE_MAX); @@ -436,18 +433,17 @@ retry: * BTREE_INSERT_NOWAIT only applies to btree node allocation, not * blocking on this lock: */ - ret = bch2_btree_cache_cannibalize_lock(c, &cl); + ret = bch2_btree_cache_cannibalize_lock(c, cl); if (ret) - goto err; + return ret; for (interior = 0; interior < 2; interior++) { struct prealloc_nodes *p = as->prealloc_nodes + interior; while (p->nr < nr_nodes[interior]) { b = __bch2_btree_node_alloc(trans, &as->disk_res, - flags & BTREE_INSERT_NOWAIT - ? NULL : &cl, - interior, flags); + flags & BTREE_INSERT_NOWAIT ? NULL : cl, + interior, flags); if (IS_ERR(b)) { ret = PTR_ERR(b); goto err; @@ -456,18 +452,8 @@ retry: p->b[p->nr++] = b; } } - - bch2_btree_cache_cannibalize_unlock(c); - closure_sync(&cl); - return 0; err: bch2_btree_cache_cannibalize_unlock(c); - closure_sync(&cl); - - if (ret == -EAGAIN) - goto retry; - - trace_btree_reserve_get_fail(c, nr_nodes[0] + nr_nodes[1], &cl); return ret; } @@ -1056,16 +1042,24 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path, if (ret) goto err; - bch2_trans_unlock(trans); - ret = bch2_journal_preres_get(&c->journal, &as->journal_preres, BTREE_UPDATE_JOURNAL_RES, - journal_flags); + journal_flags|JOURNAL_RES_GET_NONBLOCK); if (ret) { - bch2_btree_update_free(as); - trace_trans_restart_journal_preres_get(trans, _RET_IP_); - ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_journal_preres_get); - return ERR_PTR(ret); + bch2_trans_unlock(trans); + + ret = bch2_journal_preres_get(&c->journal, &as->journal_preres, + BTREE_UPDATE_JOURNAL_RES, + journal_flags); + if (ret) { + trace_trans_restart_journal_preres_get(trans, _RET_IP_); + ret = btree_trans_restart(trans, BCH_ERR_transaction_restart_journal_preres_get); + goto err; + } + + ret = bch2_trans_relock(trans); + if (ret) + goto err; } ret = bch2_disk_reservation_get(c, &as->disk_res, @@ -1075,9 +1069,26 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path, if (ret) goto err; - ret = bch2_btree_reserve_get(trans, as, nr_nodes, flags); - if (ret) + ret = bch2_btree_reserve_get(trans, as, nr_nodes, flags, NULL); + if (ret == -EAGAIN || + ret == -ENOMEM) { + struct closure cl; + + closure_init_stack(&cl); + + bch2_trans_unlock(trans); + + do { + ret = bch2_btree_reserve_get(trans, as, nr_nodes, flags, &cl); + closure_sync(&cl); + } while (ret == -EAGAIN); + } + + if (ret) { + trace_btree_reserve_get_fail(trans->fn, _RET_IP_, + nr_nodes[0] + nr_nodes[1]); goto err; + } ret = bch2_trans_relock(trans); if (ret) diff --git a/include/trace/events/bcachefs.h b/include/trace/events/bcachefs.h index 2c9807426930..a18c59a3e2e7 100644 --- a/include/trace/events/bcachefs.h +++ b/include/trace/events/bcachefs.h @@ -317,24 +317,27 @@ DEFINE_EVENT(bch_fs, btree_node_cannibalize_unlock, ); TRACE_EVENT(btree_reserve_get_fail, - TP_PROTO(struct bch_fs *c, size_t required, struct closure *cl), - TP_ARGS(c, required, cl), + TP_PROTO(const char *trans_fn, + unsigned long caller_ip, + size_t required), + TP_ARGS(trans_fn, caller_ip, required), TP_STRUCT__entry( - __field(dev_t, dev ) + __array(char, trans_fn, 24 ) + __field(unsigned long, caller_ip ) __field(size_t, required ) - __field(struct closure *, cl ) ), TP_fast_assign( - __entry->dev = c->dev; - __entry->required = required; - __entry->cl = cl; + strlcpy(__entry->trans_fn, trans_fn, sizeof(__entry->trans_fn)); + __entry->caller_ip = caller_ip; + __entry->required = required; ), - TP_printk("%d,%d required %zu by %p", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->required, __entry->cl) + TP_printk("%s %pS required %zu", + __entry->trans_fn, + (void *) __entry->caller_ip, + __entry->required) ); DEFINE_EVENT(btree_node, btree_split, |