Skip to content

Commit 05798d0

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 2ed94c8 commit 05798d0

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
@@ -1467,8 +1467,14 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success)
14671467
free_prison_cell(cache, mg->cell);
14681468
}
14691469

1470-
if (!success && mg->overwrite_bio)
1471-
bio_io_error(mg->overwrite_bio);
1470+
if (mg->overwrite_bio) {
1471+
// Set generic error if the bio hasn't been issued yet,
1472+
// e.g., invalidation or metadata commit failed before bio
1473+
// submission. Otherwise preserve the bio's own error status.
1474+
if (!success && !mg->overwrite_bio->bi_status)
1475+
mg->overwrite_bio->bi_status = BLK_STS_IOERR;
1476+
bio_endio(mg->overwrite_bio);
1477+
}
14721478

14731479
free_migration(mg);
14741480
defer_bios(cache, &bios);
@@ -1508,6 +1514,22 @@ static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock)
15081514
return r;
15091515
}
15101516

1517+
static void invalidate_committed(struct work_struct *ws)
1518+
{
1519+
struct dm_cache_migration *mg = ws_to_mg(ws);
1520+
struct cache *cache = mg->cache;
1521+
struct bio *bio = mg->overwrite_bio;
1522+
struct per_bio_data *pb = get_per_bio_data(bio);
1523+
1524+
if (mg->k.input)
1525+
invalidate_complete(mg, false);
1526+
1527+
init_continuation(&mg->k, invalidate_completed);
1528+
remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock);
1529+
dm_hook_bio(&pb->hook_info, bio, overwrite_endio, mg);
1530+
dm_submit_bio_remap(bio, NULL);
1531+
}
1532+
15111533
static void invalidate_remove(struct work_struct *ws)
15121534
{
15131535
int r;
@@ -1520,10 +1542,8 @@ static void invalidate_remove(struct work_struct *ws)
15201542
return;
15211543
}
15221544

1523-
init_continuation(&mg->k, invalidate_completed);
1545+
init_continuation(&mg->k, invalidate_committed);
15241546
continue_after_commit(&cache->committer, &mg->k);
1525-
remap_to_origin_clear_discard(cache, mg->overwrite_bio, mg->invalidate_oblock);
1526-
mg->overwrite_bio = NULL;
15271547
schedule_commit(&cache->committer);
15281548
}
15291549

0 commit comments

Comments
 (0)