Commit 52eef42c authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Fix locking in data move path

We need to ensure we don't have any btree locks held when calling
do_pending_writes() - besides issuing IOs, upcoming allocator changes
will have allocations doing btree lookups directly.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
parent 2ce8fbd9
...@@ -486,19 +486,22 @@ static void move_read_endio(struct bio *bio) ...@@ -486,19 +486,22 @@ static void move_read_endio(struct bio *bio)
closure_put(&ctxt->cl); closure_put(&ctxt->cl);
} }
static void do_pending_writes(struct moving_context *ctxt) static void do_pending_writes(struct moving_context *ctxt, struct btree_trans *trans)
{ {
struct moving_io *io; struct moving_io *io;
if (trans)
bch2_trans_unlock(trans);
while ((io = next_pending_write(ctxt))) { while ((io = next_pending_write(ctxt))) {
list_del(&io->list); list_del(&io->list);
move_write(io); move_write(io);
} }
} }
#define move_ctxt_wait_event(_ctxt, _cond) \ #define move_ctxt_wait_event(_ctxt, _trans, _cond) \
do { \ do { \
do_pending_writes(_ctxt); \ do_pending_writes(_ctxt, _trans); \
\ \
if (_cond) \ if (_cond) \
break; \ break; \
...@@ -506,11 +509,12 @@ do { \ ...@@ -506,11 +509,12 @@ do { \
next_pending_write(_ctxt) || (_cond)); \ next_pending_write(_ctxt) || (_cond)); \
} while (1) } while (1)
static void bch2_move_ctxt_wait_for_io(struct moving_context *ctxt) static void bch2_move_ctxt_wait_for_io(struct moving_context *ctxt,
struct btree_trans *trans)
{ {
unsigned sectors_pending = atomic_read(&ctxt->write_sectors); unsigned sectors_pending = atomic_read(&ctxt->write_sectors);
move_ctxt_wait_event(ctxt, move_ctxt_wait_event(ctxt, trans,
!atomic_read(&ctxt->write_sectors) || !atomic_read(&ctxt->write_sectors) ||
atomic_read(&ctxt->write_sectors) != sectors_pending); atomic_read(&ctxt->write_sectors) != sectors_pending);
} }
...@@ -532,14 +536,6 @@ static int bch2_move_extent(struct btree_trans *trans, ...@@ -532,14 +536,6 @@ static int bch2_move_extent(struct btree_trans *trans,
unsigned sectors = k.k->size, pages; unsigned sectors = k.k->size, pages;
int ret = -ENOMEM; int ret = -ENOMEM;
move_ctxt_wait_event(ctxt,
atomic_read(&ctxt->write_sectors) <
SECTORS_IN_FLIGHT_PER_DEVICE);
move_ctxt_wait_event(ctxt,
atomic_read(&ctxt->read_sectors) <
SECTORS_IN_FLIGHT_PER_DEVICE);
/* write path might have to decompress data: */ /* write path might have to decompress data: */
bkey_for_each_ptr_decode(k.k, ptrs, p, entry) bkey_for_each_ptr_decode(k.k, ptrs, p, entry)
sectors = max_t(unsigned, sectors, p.crc.uncompressed_size); sectors = max_t(unsigned, sectors, p.crc.uncompressed_size);
...@@ -692,12 +688,19 @@ static int __bch2_move_data(struct bch_fs *c, ...@@ -692,12 +688,19 @@ static int __bch2_move_data(struct bch_fs *c,
schedule_timeout(delay); schedule_timeout(delay);
if (unlikely(freezing(current))) { if (unlikely(freezing(current))) {
bch2_trans_unlock(&trans); move_ctxt_wait_event(ctxt, &trans, list_empty(&ctxt->reads));
move_ctxt_wait_event(ctxt, list_empty(&ctxt->reads));
try_to_freeze(); try_to_freeze();
} }
} while (delay); } while (delay);
move_ctxt_wait_event(ctxt, &trans,
atomic_read(&ctxt->write_sectors) <
SECTORS_IN_FLIGHT_PER_DEVICE);
move_ctxt_wait_event(ctxt, &trans,
atomic_read(&ctxt->read_sectors) <
SECTORS_IN_FLIGHT_PER_DEVICE);
bch2_trans_begin(&trans); bch2_trans_begin(&trans);
k = bch2_btree_iter_peek(&iter); k = bch2_btree_iter_peek(&iter);
...@@ -762,7 +765,7 @@ static int __bch2_move_data(struct bch_fs *c, ...@@ -762,7 +765,7 @@ static int __bch2_move_data(struct bch_fs *c,
if (ret2 == -ENOMEM) { if (ret2 == -ENOMEM) {
/* memory allocation failure, wait for some IO to finish */ /* memory allocation failure, wait for some IO to finish */
bch2_move_ctxt_wait_for_io(ctxt); bch2_move_ctxt_wait_for_io(ctxt, &trans);
continue; continue;
} }
...@@ -847,7 +850,7 @@ int bch2_move_data(struct bch_fs *c, ...@@ -847,7 +850,7 @@ int bch2_move_data(struct bch_fs *c,
} }
move_ctxt_wait_event(&ctxt, list_empty(&ctxt.reads)); move_ctxt_wait_event(&ctxt, NULL, list_empty(&ctxt.reads));
closure_sync(&ctxt.cl); closure_sync(&ctxt.cl);
EBUG_ON(atomic_read(&ctxt.write_sectors)); EBUG_ON(atomic_read(&ctxt.write_sectors));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment