mirror of
https://github.com/torvalds/linux.git
synced 2026-05-13 08:39:31 +02:00
dm cache: fix write hang in passthrough mode
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: b29d4986d0 ("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>
This commit is contained in:
parent
0c5eef0aad
commit
4ca8b8bd95
|
|
@ -1467,8 +1467,14 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success)
|
|||
free_prison_cell(cache, mg->cell);
|
||||
}
|
||||
|
||||
if (!success && mg->overwrite_bio)
|
||||
bio_io_error(mg->overwrite_bio);
|
||||
if (mg->overwrite_bio) {
|
||||
// Set generic error if the bio hasn't been issued yet,
|
||||
// e.g., invalidation or metadata commit failed before bio
|
||||
// submission. Otherwise preserve the bio's own error status.
|
||||
if (!success && !mg->overwrite_bio->bi_status)
|
||||
mg->overwrite_bio->bi_status = BLK_STS_IOERR;
|
||||
bio_endio(mg->overwrite_bio);
|
||||
}
|
||||
|
||||
free_migration(mg);
|
||||
defer_bios(cache, &bios);
|
||||
|
|
@ -1508,6 +1514,22 @@ static int invalidate_cblock(struct cache *cache, dm_cblock_t cblock)
|
|||
return r;
|
||||
}
|
||||
|
||||
static void invalidate_committed(struct work_struct *ws)
|
||||
{
|
||||
struct dm_cache_migration *mg = ws_to_mg(ws);
|
||||
struct cache *cache = mg->cache;
|
||||
struct bio *bio = mg->overwrite_bio;
|
||||
struct per_bio_data *pb = get_per_bio_data(bio);
|
||||
|
||||
if (mg->k.input)
|
||||
invalidate_complete(mg, false);
|
||||
|
||||
init_continuation(&mg->k, invalidate_completed);
|
||||
remap_to_origin_clear_discard(cache, bio, mg->invalidate_oblock);
|
||||
dm_hook_bio(&pb->hook_info, bio, overwrite_endio, mg);
|
||||
dm_submit_bio_remap(bio, NULL);
|
||||
}
|
||||
|
||||
static void invalidate_remove(struct work_struct *ws)
|
||||
{
|
||||
int r;
|
||||
|
|
@ -1520,10 +1542,8 @@ static void invalidate_remove(struct work_struct *ws)
|
|||
return;
|
||||
}
|
||||
|
||||
init_continuation(&mg->k, invalidate_completed);
|
||||
init_continuation(&mg->k, invalidate_committed);
|
||||
continue_after_commit(&cache->committer, &mg->k);
|
||||
remap_to_origin_clear_discard(cache, mg->overwrite_bio, mg->invalidate_oblock);
|
||||
mg->overwrite_bio = NULL;
|
||||
schedule_commit(&cache->committer);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user