bcachefs: don't block reads if we're promoting
authorDaniel Hill <daniel@gluo.nz>
Fri, 6 Jan 2023 08:11:07 +0000 (21:11 +1300)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:52 +0000 (17:09 -0400)
The promote path calls data_update_init() and now that we take locks here,
there's potential for promote to block our read path, just error
when we can't take the lock instead of blocking.

Signed-off-by: Daniel Hill <daniel@gluo.nz>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/data_update.c
fs/bcachefs/errcode.h
fs/bcachefs/io.c

index 91bc95b8ecb943c22e5303e8ac8f17ed84b0e658..8ff20a4587d960415dee2067c3eee4703b18933e 100644 (file)
@@ -411,6 +411,7 @@ int bch2_data_update_init(struct btree_trans *trans,
        const union bch_extent_entry *entry;
        struct extent_ptr_decoded p;
        unsigned i, reserve_sectors = k.k->size * data_opts.extra_replicas;
+       unsigned int ptrs_locked = 0;
        int ret;
 
        bch2_bkey_buf_init(&m->k);
@@ -436,6 +437,8 @@ int bch2_data_update_init(struct btree_trans *trans,
 
        i = 0;
        bkey_for_each_ptr_decode(k.k, ptrs, p, entry) {
+               bool locked;
+
                if (((1U << i) & m->data_opts.rewrite_ptrs) &&
                    p.ptr.cached)
                        BUG();
@@ -461,11 +464,7 @@ int bch2_data_update_init(struct btree_trans *trans,
                if (p.crc.compression_type == BCH_COMPRESSION_TYPE_incompressible)
                        m->op.incompressible = true;
 
-               i++;
-
                if (ctxt) {
-                       bool locked;
-
                        move_ctxt_wait_event(ctxt, trans,
                                        (locked = bch2_bucket_nocow_trylock(&c->nocow_locks,
                                                                  PTR_BUCKET_POS(c, &p.ptr), 0)) ||
@@ -475,9 +474,14 @@ int bch2_data_update_init(struct btree_trans *trans,
                                bch2_bucket_nocow_lock(&c->nocow_locks,
                                                       PTR_BUCKET_POS(c, &p.ptr), 0);
                } else {
-                       bch2_bucket_nocow_lock(&c->nocow_locks,
-                                              PTR_BUCKET_POS(c, &p.ptr), 0);
+                       if (!bch2_bucket_nocow_trylock(&c->nocow_locks,
+                                                      PTR_BUCKET_POS(c, &p.ptr), 0)) {
+                               ret = -BCH_ERR_nocow_lock_blocked;
+                               goto err;
+                       }
                }
+               ptrs_locked |= (1U << i);
+               i++;
        }
 
        if (reserve_sectors) {
@@ -499,9 +503,13 @@ int bch2_data_update_init(struct btree_trans *trans,
                return -BCH_ERR_unwritten_extent_update;
        return 0;
 err:
-       bkey_for_each_ptr_decode(k.k, ptrs, p, entry)
-               bch2_bucket_nocow_unlock(&c->nocow_locks,
-                                      PTR_BUCKET_POS(c, &p.ptr), 0);
+       i = 0;
+       bkey_for_each_ptr_decode(k.k, ptrs, p, entry) {
+               if ((1U << i) & ptrs_locked)
+                       bch2_bucket_nocow_unlock(&c->nocow_locks,
+                                               PTR_BUCKET_POS(c, &p.ptr), 0);
+               i++;
+       }
 
        bch2_bkey_buf_exit(&m->k, c);
        bch2_bio_free_pages_pool(c, &m->op.wbio.bio);
index 57f1d0a6a490b59250a65cc8a72538dc33926f27..6129af6129c3992148ee8a926fd7f443f7d4f87e 100644 (file)
        x(BCH_ERR_invalid_sb,           invalid_sb_clean)                       \
        x(BCH_ERR_invalid_sb,           invalid_sb_quota)                       \
        x(BCH_ERR_invalid,              invalid_bkey)                           \
+       x(BCH_ERR_operation_blocked,    nocow_lock_blocked)                     \
 
 enum bch_errcode {
        BCH_ERR_START           = 2048,
index 1436863fe418a79b67a7299f83e3cd4805a9c07f..6f7e4dac4268fcab811145f2736c9308c6f77227 100644 (file)
@@ -2023,6 +2023,13 @@ static struct promote_op *__promote_alloc(struct btree_trans *trans,
                                .write_flags    = BCH_WRITE_ALLOC_NOWAIT|BCH_WRITE_CACHED,
                        },
                        btree_id, k);
+       if (ret == -BCH_ERR_nocow_lock_blocked) {
+               ret = rhashtable_remove_fast(&c->promote_table, &op->hash,
+                                       bch_promote_params);
+               BUG_ON(ret);
+               goto err;
+       }
+
        BUG_ON(ret);
        op->write.op.end_io = promote_done;