Commit b3996295 authored by Dmitry Fomichev's avatar Dmitry Fomichev Committed by Mike Snitzer

dm zoned: support zone sizes smaller than 128MiB

dm-zoned is observed to log failed kernel assertions and not work
correctly when operating against a device with a zone size smaller
than 128MiB (e.g. 32768 bits per 4K block). The reason is that the
bitmap size per zone is calculated as zero with such a small zone
size. Fix this problem and also make the code related to zone bitmap
management be able to handle per zone bitmaps smaller than a single
block.

A dm-zoned-tools patch is required to properly format dm-zoned devices
with zone sizes smaller than 128MiB.

Fixes: 3b1a94c8 ("dm zoned: drive-managed zoned block device target")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarDmitry Fomichev <dmitry.fomichev@wdc.com>
Reviewed-by: default avatarDamien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent 43f3952a
...@@ -134,6 +134,7 @@ struct dmz_metadata { ...@@ -134,6 +134,7 @@ struct dmz_metadata {
sector_t zone_bitmap_size; sector_t zone_bitmap_size;
unsigned int zone_nr_bitmap_blocks; unsigned int zone_nr_bitmap_blocks;
unsigned int zone_bits_per_mblk;
unsigned int nr_bitmap_blocks; unsigned int nr_bitmap_blocks;
unsigned int nr_map_blocks; unsigned int nr_map_blocks;
...@@ -1161,7 +1162,10 @@ static int dmz_init_zones(struct dmz_metadata *zmd) ...@@ -1161,7 +1162,10 @@ static int dmz_init_zones(struct dmz_metadata *zmd)
/* Init */ /* Init */
zmd->zone_bitmap_size = dev->zone_nr_blocks >> 3; zmd->zone_bitmap_size = dev->zone_nr_blocks >> 3;
zmd->zone_nr_bitmap_blocks = zmd->zone_bitmap_size >> DMZ_BLOCK_SHIFT; zmd->zone_nr_bitmap_blocks =
max_t(sector_t, 1, zmd->zone_bitmap_size >> DMZ_BLOCK_SHIFT);
zmd->zone_bits_per_mblk = min_t(sector_t, dev->zone_nr_blocks,
DMZ_BLOCK_SIZE_BITS);
/* Allocate zone array */ /* Allocate zone array */
zmd->zones = kcalloc(dev->nr_zones, sizeof(struct dm_zone), GFP_KERNEL); zmd->zones = kcalloc(dev->nr_zones, sizeof(struct dm_zone), GFP_KERNEL);
...@@ -1956,7 +1960,7 @@ int dmz_copy_valid_blocks(struct dmz_metadata *zmd, struct dm_zone *from_zone, ...@@ -1956,7 +1960,7 @@ int dmz_copy_valid_blocks(struct dmz_metadata *zmd, struct dm_zone *from_zone,
dmz_release_mblock(zmd, to_mblk); dmz_release_mblock(zmd, to_mblk);
dmz_release_mblock(zmd, from_mblk); dmz_release_mblock(zmd, from_mblk);
chunk_block += DMZ_BLOCK_SIZE_BITS; chunk_block += zmd->zone_bits_per_mblk;
} }
to_zone->weight = from_zone->weight; to_zone->weight = from_zone->weight;
...@@ -2017,7 +2021,7 @@ int dmz_validate_blocks(struct dmz_metadata *zmd, struct dm_zone *zone, ...@@ -2017,7 +2021,7 @@ int dmz_validate_blocks(struct dmz_metadata *zmd, struct dm_zone *zone,
/* Set bits */ /* Set bits */
bit = chunk_block & DMZ_BLOCK_MASK_BITS; bit = chunk_block & DMZ_BLOCK_MASK_BITS;
nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit); nr_bits = min(nr_blocks, zmd->zone_bits_per_mblk - bit);
count = dmz_set_bits((unsigned long *)mblk->data, bit, nr_bits); count = dmz_set_bits((unsigned long *)mblk->data, bit, nr_bits);
if (count) { if (count) {
...@@ -2096,7 +2100,7 @@ int dmz_invalidate_blocks(struct dmz_metadata *zmd, struct dm_zone *zone, ...@@ -2096,7 +2100,7 @@ int dmz_invalidate_blocks(struct dmz_metadata *zmd, struct dm_zone *zone,
/* Clear bits */ /* Clear bits */
bit = chunk_block & DMZ_BLOCK_MASK_BITS; bit = chunk_block & DMZ_BLOCK_MASK_BITS;
nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit); nr_bits = min(nr_blocks, zmd->zone_bits_per_mblk - bit);
count = dmz_clear_bits((unsigned long *)mblk->data, count = dmz_clear_bits((unsigned long *)mblk->data,
bit, nr_bits); bit, nr_bits);
...@@ -2156,6 +2160,7 @@ static int dmz_to_next_set_block(struct dmz_metadata *zmd, struct dm_zone *zone, ...@@ -2156,6 +2160,7 @@ static int dmz_to_next_set_block(struct dmz_metadata *zmd, struct dm_zone *zone,
{ {
struct dmz_mblock *mblk; struct dmz_mblock *mblk;
unsigned int bit, set_bit, nr_bits; unsigned int bit, set_bit, nr_bits;
unsigned int zone_bits = zmd->zone_bits_per_mblk;
unsigned long *bitmap; unsigned long *bitmap;
int n = 0; int n = 0;
...@@ -2170,15 +2175,15 @@ static int dmz_to_next_set_block(struct dmz_metadata *zmd, struct dm_zone *zone, ...@@ -2170,15 +2175,15 @@ static int dmz_to_next_set_block(struct dmz_metadata *zmd, struct dm_zone *zone,
/* Get offset */ /* Get offset */
bitmap = (unsigned long *) mblk->data; bitmap = (unsigned long *) mblk->data;
bit = chunk_block & DMZ_BLOCK_MASK_BITS; bit = chunk_block & DMZ_BLOCK_MASK_BITS;
nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit); nr_bits = min(nr_blocks, zone_bits - bit);
if (set) if (set)
set_bit = find_next_bit(bitmap, DMZ_BLOCK_SIZE_BITS, bit); set_bit = find_next_bit(bitmap, zone_bits, bit);
else else
set_bit = find_next_zero_bit(bitmap, DMZ_BLOCK_SIZE_BITS, bit); set_bit = find_next_zero_bit(bitmap, zone_bits, bit);
dmz_release_mblock(zmd, mblk); dmz_release_mblock(zmd, mblk);
n += set_bit - bit; n += set_bit - bit;
if (set_bit < DMZ_BLOCK_SIZE_BITS) if (set_bit < zone_bits)
break; break;
nr_blocks -= nr_bits; nr_blocks -= nr_bits;
...@@ -2281,7 +2286,7 @@ static void dmz_get_zone_weight(struct dmz_metadata *zmd, struct dm_zone *zone) ...@@ -2281,7 +2286,7 @@ static void dmz_get_zone_weight(struct dmz_metadata *zmd, struct dm_zone *zone)
/* Count bits in this block */ /* Count bits in this block */
bitmap = mblk->data; bitmap = mblk->data;
bit = chunk_block & DMZ_BLOCK_MASK_BITS; bit = chunk_block & DMZ_BLOCK_MASK_BITS;
nr_bits = min(nr_blocks, DMZ_BLOCK_SIZE_BITS - bit); nr_bits = min(nr_blocks, zmd->zone_bits_per_mblk - bit);
n += dmz_count_bits(bitmap, bit, nr_bits); n += dmz_count_bits(bitmap, bit, nr_bits);
dmz_release_mblock(zmd, mblk); dmz_release_mblock(zmd, mblk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment