Skip to content

Commit 31b2212

Browse files
Mikulas Patockasnitm
authored andcommitted
dm writecache: fix data corruption when reloading the target
The dm-writecache reads metadata in the target constructor. However, when we reload the target, there could be another active instance running on the same device. This is the sequence of operations when doing a reload: 1. construct new target 2. suspend old target 3. resume new target 4. destroy old target Metadata that were written by the old target between steps 1 and 2 would not be visible by the new target. Fix the data corruption by loading the metadata in the resume handler. Also, validate block_size is at least as large as both the devices' logical block size and only read 1 block from the metadata during target constructor -- no need to read entirety of metadata now that it is done during resume. Fixes: 48debaf ("dm: add writecache target") Cc: [email protected] # v4.18+ Signed-off-by: Mikulas Patocka <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent 0a2bd55 commit 31b2212

File tree

1 file changed

+37
-15
lines changed

1 file changed

+37
-15
lines changed

drivers/md/dm-writecache.c

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,24 @@ static int writecache_alloc_entries(struct dm_writecache *wc)
931931
return 0;
932932
}
933933

934+
static int writecache_read_metadata(struct dm_writecache *wc, sector_t n_sectors)
935+
{
936+
struct dm_io_region region;
937+
struct dm_io_request req;
938+
939+
region.bdev = wc->ssd_dev->bdev;
940+
region.sector = wc->start_sector;
941+
region.count = n_sectors;
942+
req.bi_op = REQ_OP_READ;
943+
req.bi_op_flags = REQ_SYNC;
944+
req.mem.type = DM_IO_VMA;
945+
req.mem.ptr.vma = (char *)wc->memory_map;
946+
req.client = wc->dm_io;
947+
req.notify.fn = NULL;
948+
949+
return dm_io(&req, 1, &region, NULL);
950+
}
951+
934952
static void writecache_resume(struct dm_target *ti)
935953
{
936954
struct dm_writecache *wc = ti->private;
@@ -941,8 +959,18 @@ static void writecache_resume(struct dm_target *ti)
941959

942960
wc_lock(wc);
943961

944-
if (WC_MODE_PMEM(wc))
962+
if (WC_MODE_PMEM(wc)) {
945963
persistent_memory_invalidate_cache(wc->memory_map, wc->memory_map_size);
964+
} else {
965+
r = writecache_read_metadata(wc, wc->metadata_sectors);
966+
if (r) {
967+
size_t sb_entries_offset;
968+
writecache_error(wc, r, "unable to read metadata: %d", r);
969+
sb_entries_offset = offsetof(struct wc_memory_superblock, entries);
970+
memset((char *)wc->memory_map + sb_entries_offset, -1,
971+
(wc->metadata_sectors << SECTOR_SHIFT) - sb_entries_offset);
972+
}
973+
}
946974

947975
wc->tree = RB_ROOT;
948976
INIT_LIST_HEAD(&wc->lru);
@@ -2102,6 +2130,12 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
21022130
ti->error = "Invalid block size";
21032131
goto bad;
21042132
}
2133+
if (wc->block_size < bdev_logical_block_size(wc->dev->bdev) ||
2134+
wc->block_size < bdev_logical_block_size(wc->ssd_dev->bdev)) {
2135+
r = -EINVAL;
2136+
ti->error = "Block size is smaller than device logical block size";
2137+
goto bad;
2138+
}
21052139
wc->block_size_bits = __ffs(wc->block_size);
21062140

21072141
wc->max_writeback_jobs = MAX_WRITEBACK_JOBS;
@@ -2200,8 +2234,6 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
22002234
goto bad;
22012235
}
22022236
} else {
2203-
struct dm_io_region region;
2204-
struct dm_io_request req;
22052237
size_t n_blocks, n_metadata_blocks;
22062238
uint64_t n_bitmap_bits;
22072239

@@ -2258,19 +2290,9 @@ static int writecache_ctr(struct dm_target *ti, unsigned argc, char **argv)
22582290
goto bad;
22592291
}
22602292

2261-
region.bdev = wc->ssd_dev->bdev;
2262-
region.sector = wc->start_sector;
2263-
region.count = wc->metadata_sectors;
2264-
req.bi_op = REQ_OP_READ;
2265-
req.bi_op_flags = REQ_SYNC;
2266-
req.mem.type = DM_IO_VMA;
2267-
req.mem.ptr.vma = (char *)wc->memory_map;
2268-
req.client = wc->dm_io;
2269-
req.notify.fn = NULL;
2270-
2271-
r = dm_io(&req, 1, &region, NULL);
2293+
r = writecache_read_metadata(wc, wc->block_size >> SECTOR_SHIFT);
22722294
if (r) {
2273-
ti->error = "Unable to read metadata";
2295+
ti->error = "Unable to read first block of metadata";
22742296
goto bad;
22752297
}
22762298
}

0 commit comments

Comments
 (0)