diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-01-03 01:53:02 +0300 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-23 00:09:52 +0300 |
commit | 7ffb6a7ec6712eb1ba84a80137c2f712e67c4171 (patch) | |
tree | 0d05e725b41817a28164f1ba6ee19747d010bbf6 /fs/bcachefs/data_update.c | |
parent | dbe17f18838df6d0facf51b43cdc5efd372c28d6 (diff) | |
download | linux-7ffb6a7ec6712eb1ba84a80137c2f712e67c4171.tar.xz |
bcachefs: Fix deadlock on nocow locks in data move path
The recent nocow locking rework introduced a deadlock in the data move
path: the new nocow locking scheme uses a hash table with a fixed size
array for chaining, meaning on hash collision we may have to wait for
other locks to be released before we can lock a bucket.
And since the data move path needs to submit writes from the same thread
that's taking nocow locks and submitting reads, this introduces a
deadlock.
This shouldn't happen often in practice, but since the data move path
can keep large numbers of IOs in flight simultaneously, it's something
we have to handle.
This patch makes move_ctxt_wait_event() available to
bch2_data_update_init() and uses it when appropriate, which is our
normal solution to this kind of thing.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/data_update.c')
-rw-r--r-- | fs/bcachefs/data_update.c | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/fs/bcachefs/data_update.c b/fs/bcachefs/data_update.c index eb248968de48..91bc95b8ecb9 100644 --- a/fs/bcachefs/data_update.c +++ b/fs/bcachefs/data_update.c @@ -397,13 +397,16 @@ void bch2_update_unwritten_extent(struct btree_trans *trans, } } -int bch2_data_update_init(struct bch_fs *c, struct data_update *m, +int bch2_data_update_init(struct btree_trans *trans, + struct moving_context *ctxt, + struct data_update *m, struct write_point_specifier wp, struct bch_io_opts io_opts, struct data_update_opts data_opts, enum btree_id btree_id, struct bkey_s_c k) { + struct bch_fs *c = trans->c; struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k); const union bch_extent_entry *entry; struct extent_ptr_decoded p; @@ -460,8 +463,21 @@ int bch2_data_update_init(struct bch_fs *c, struct data_update *m, i++; - bch2_bucket_nocow_lock(&c->nocow_locks, - PTR_BUCKET_POS(c, &p.ptr), 0); + 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)) || + !atomic_read(&ctxt->read_sectors)); + + if (!locked) + 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 (reserve_sectors) { |