ack On Tue, Oct 22, 2024 at 8:12 AM Ming-Hung Tsai <mtsai@xxxxxxxxxx> wrote: > > 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 <mtsai@xxxxxxxxxx> > Fixes: c6b4fcbad044 ("dm: add cache target") > --- > drivers/md/dm-cache-target.c | 8 ++++---- > 1 file changed, 4 insertions(+), 4 deletions(-) > > diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c > index aaeeabfab09b..90772b42c234 100644 > --- a/drivers/md/dm-cache-target.c > +++ b/drivers/md/dm-cache-target.c > @@ -2003,7 +2003,6 @@ struct cache_args { > sector_t cache_sectors; > > struct dm_dev *origin_dev; > - sector_t origin_sectors; > > uint32_t block_size; > > @@ -2084,6 +2083,7 @@ static int parse_cache_dev(struct cache_args *ca, struct dm_arg_set *as, > static int parse_origin_dev(struct cache_args *ca, struct dm_arg_set *as, > char **error) > { > + sector_t origin_sectors; > int r; > > 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, > return r; > } > > - ca->origin_sectors = get_dev_size(ca->origin_dev); > - if (ca->ti->len > ca->origin_sectors) { > + origin_sectors = get_dev_size(ca->origin_dev); > + if (ca->ti->len > origin_sectors) { > *error = "Device size larger than cached device"; > return -EINVAL; > } > @@ -2407,7 +2407,7 @@ static int cache_create(struct cache_args *ca, struct cache **result) > > ca->metadata_dev = ca->origin_dev = ca->cache_dev = NULL; > > - origin_blocks = cache->origin_sectors = ca->origin_sectors; > + origin_blocks = cache->origin_sectors = ti->len; > origin_blocks = block_div(origin_blocks, ca->block_size); > cache->origin_blocks = to_oblock(origin_blocks); > > -- > 2.47.0 >