Skip to content

Commit 235d2e7

Browse files
mingnusMikulas Patocka
authored andcommitted
dm cache: correct the number of origin blocks to match the target length
When creating a cache device, the actual size of the cache origin might be greater than the specified cache target length. In such case, the number of origin blocks should match the cache target length, not the full size of the origin device, since access beyond the cache target is not possible. This issue occurs when reducing the origin device size using lvm, as lvreduce preloads the new cache table before resuming the cache origin, which can result in incorrect sizes for the discard bitset and smq hotspot blocks. Reproduce steps: 1. create a cache device consists of 4096 origin blocks dmsetup create cmeta --table "0 8192 linear /dev/sdc 0" dmsetup create cdata --table "0 65536 linear /dev/sdc 8192" dmsetup create corig --table "0 524288 linear /dev/sdc 262144" dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct dmsetup create cache --table "0 524288 cache /dev/mapper/cmeta \ /dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" 2. reduce the cache origin to 2048 oblocks, in lvreduce's approach dmsetup reload corig --table "0 262144 linear /dev/sdc 262144" dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \ /dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0" dmsetup suspend cache dmsetup suspend corig dmsetup suspend cdata dmsetup suspend cmeta dmsetup resume corig dmsetup resume cdata dmsetup resume cmeta dmsetup resume cache 3. shutdown the cache, and check the number of discard blocks in superblock. The value is expected to be 2048, but actually is 4096. dmsetup remove cache corig cdata cmeta dd if=/dev/sdc bs=1c count=8 skip=224 2>/dev/null | hexdump -e '1/8 "%u\n"' Fix by correcting the origin_blocks initialization in cache_create and removing the unused origin_sectors from struct cache_args accordingly. Signed-off-by: Ming-Hung Tsai <[email protected]> Fixes: c6b4fcb ("dm: add cache target") Cc: [email protected] Signed-off-by: Mikulas Patocka <[email protected]> Acked-by: Joe Thornber <[email protected]>
1 parent a674d0c commit 235d2e7

File tree

1 file changed

+4
-4
lines changed

1 file changed

+4
-4
lines changed

drivers/md/dm-cache-target.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,7 +2003,6 @@ struct cache_args {
20032003
sector_t cache_sectors;
20042004

20052005
struct dm_dev *origin_dev;
2006-
sector_t origin_sectors;
20072006

20082007
uint32_t block_size;
20092008

@@ -2084,6 +2083,7 @@ static int parse_cache_dev(struct cache_args *ca, struct dm_arg_set *as,
20842083
static int parse_origin_dev(struct cache_args *ca, struct dm_arg_set *as,
20852084
char **error)
20862085
{
2086+
sector_t origin_sectors;
20872087
int r;
20882088

20892089
if (!at_least_one_arg(as, error))
@@ -2096,8 +2096,8 @@ static int parse_origin_dev(struct cache_args *ca, struct dm_arg_set *as,
20962096
return r;
20972097
}
20982098

2099-
ca->origin_sectors = get_dev_size(ca->origin_dev);
2100-
if (ca->ti->len > ca->origin_sectors) {
2099+
origin_sectors = get_dev_size(ca->origin_dev);
2100+
if (ca->ti->len > origin_sectors) {
21012101
*error = "Device size larger than cached device";
21022102
return -EINVAL;
21032103
}
@@ -2407,7 +2407,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
24072407

24082408
ca->metadata_dev = ca->origin_dev = ca->cache_dev = NULL;
24092409

2410-
origin_blocks = cache->origin_sectors = ca->origin_sectors;
2410+
origin_blocks = cache->origin_sectors = ti->len;
24112411
origin_blocks = block_div(origin_blocks, ca->block_size);
24122412
cache->origin_blocks = to_oblock(origin_blocks);
24132413

0 commit comments

Comments
 (0)