Skip to content

Commit 64d6519

Browse files
mingnusgregkh
authored andcommitted
dm cache: fix write hang in passthrough mode
[ Upstream commit 4ca8b8b ] The invalidate_remove() function has incomplete logic for handling write hit bios after cache invalidation. It sets up the remapping for the overwrite_bio but then drops it immediately without submission, causing write operations to hang. Fix by adding a new invalidate_committed() continuation that submits the remapped writes to the cache origin after metadata commit completes, while using the overwrite_endio hook to ensure proper completion sequencing. This maintains existing coherency. Also improve error handling in invalidate_complete() to preserve the original error status instead of using bio_io_error() unconditionally. Fixes: b29d498 ("dm cache: significant rework to leverage dm-bio-prison-v2") Signed-off-by: Ming-Hung Tsai <mtsai@redhat.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 90fd56d commit 64d6519

1 file changed

Lines changed: 25 additions & 5 deletions

File tree

drivers/md/dm-cache-target.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,8 +1461,14 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success)
14611461
free_prison_cell(cache, mg->cell);
14621462
}
14631463

1464-
if (!success && mg->overwrite_bio)
1465-
bio_io_error(mg->overwrite_bio);
1464+
if (mg->overwrite_bio) {
1465+
// Set generic error if the bio hasn't been issued yet,
1466+
// e.g., invalidation or metadata commit failed before bio
1467+
// submission. Otherwise preserve the bio's own error status.
1468+
if (!success && !mg->overwrite_bio->bi_status)
1469+
mg->overwrite_bio->bi_status = BLK_STS_IOERR;
1470+
bio_endio(mg->overwrite_bio);
1471+
}
14661472

14671473
free_migration(mg);
14681474
defer_bios(cache, &bios);
@@ -1502,6 +1508,22 @@ static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock)
15021508
return r;
15031509
}
15041510

1511+
static void invalidate_committed(struct work_struct *ws)
1512+
{
1513+
struct dm_cache_migration *mg = ws_to_mg(ws);
1514+
struct cache *cache = mg->cache;
1515+
struct bio *bio = mg->overwrite_bio;
1516+
struct per_bio_data *pb = get_per_bio_data(bio);
1517+
1518+
if (mg->k.input)
1519+
invalidate_complete(mg, false);
1520+
1521+
init_continuation(&mg->k, invalidate_completed);
1522+
remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock);
1523+
dm_hook_bio(&pb->hook_info, bio, overwrite_endio, mg);
1524+
dm_submit_bio_remap(bio, NULL);
1525+
}
1526+
15051527
static void invalidate_remove(struct work_struct *ws)
15061528
{
15071529
int r;
@@ -1514,10 +1536,8 @@ static void invalidate_remove(struct work_struct *ws)
15141536
return;
15151537
}
15161538

1517-
init_continuation(&mg->k, invalidate_completed);
1539+
init_continuation(&mg->k, invalidate_committed);
15181540
continue_after_commit(&cache->committer, &mg->k);
1519-
remap_to_origin_clear_discard(cache, mg->overwrite_bio, mg->invalidate_oblock);
1520-
mg->overwrite_bio = NULL;
15211541
schedule_commit(&cache->committer);
15221542
}
15231543

0 commit comments

Comments
 (0)