bcachefs; Fix deadlock in bch2_btree_update_start()
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 19 Mar 2024 01:36:08 +0000 (21:36 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Tue, 19 Mar 2024 03:35:42 +0000 (23:35 -0400)
BCH_TRANS_COMMIT_journal_reclaim with watermark != BCH_WATERMARK_reclaim
means nonblocking, and we need the journal_res_get() in
btree_update_start() to respect that.

In a future refactoring we'll be deleting
BCH_TRANS_COMMIT_journal_reclaim and replacing it with an explicit
BCH_TRANS_COMMIT_nonblocking.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_update_interior.c

index eb233e901d3eab0f742215d1e92d41e27c355cbf..b2f5f2e50f7e19ccd59502a1471ee9bb6d14a988 100644 (file)
@@ -1067,13 +1067,18 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
        flags &= ~BCH_WATERMARK_MASK;
        flags |= watermark;
 
-       if (!(flags & BCH_TRANS_COMMIT_journal_reclaim) &&
-           watermark < c->journal.watermark) {
+       if (watermark < c->journal.watermark) {
                struct journal_res res = { 0 };
+               unsigned journal_flags = watermark|JOURNAL_RES_GET_CHECK;
+
+               if ((flags & BCH_TRANS_COMMIT_journal_reclaim) &&
+                   watermark != BCH_WATERMARK_reclaim)
+                       journal_flags |= JOURNAL_RES_GET_NONBLOCK;
 
                ret = drop_locks_do(trans,
-                       bch2_journal_res_get(&c->journal, &res, 1,
-                                            watermark|JOURNAL_RES_GET_CHECK));
+                       bch2_journal_res_get(&c->journal, &res, 1, journal_flags));
+               if (bch2_err_matches(ret, BCH_ERR_operation_blocked))
+                       ret = -BCH_ERR_journal_reclaim_would_deadlock;
                if (ret)
                        return ERR_PTR(ret);
        }