dm zoned: support zone sizes smaller than 128MiB
commit b39962950339912978484cdac50069258545d753 upstream. 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: 3b1a94c88b79 ("dm zoned: drive-managed zoned block device target") Cc: stable@vger.kernel.org Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
a687c3bfdc
commit
9b52f0b54d
@ -132,6 +132,7 @@ struct dmz_metadata {
|
||||
|
||||
sector_t zone_bitmap_size;
|
||||
unsigned int zone_nr_bitmap_blocks;
|
||||
unsigned int zone_bits_per_mblk;
|
||||
|
||||
unsigned int nr_bitmap_blocks;
|
||||
unsigned int nr_map_blocks;
|
||||
@ -1165,7 +1166,10 @@ static int dmz_init_zones(struct dmz_metadata *zmd)
|
||||
|
||||
/* Init */
|
||||
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 */
|
||||
zmd->zones = kcalloc(dev->nr_zones, sizeof(struct dm_zone), GFP_KERNEL);
|
||||
@ -1982,7 +1986,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, from_mblk);
|
||||
|
||||
chunk_block += DMZ_BLOCK_SIZE_BITS;
|
||||
chunk_block += zmd->zone_bits_per_mblk;
|
||||
}
|
||||
|
||||
to_zone->weight = from_zone->weight;
|
||||
@ -2043,7 +2047,7 @@ int dmz_validate_blocks(struct dmz_metadata *zmd, struct dm_zone *zone,
|
||||
|
||||
/* Set 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);
|
||||
if (count) {
|
||||
@ -2122,7 +2126,7 @@ int dmz_invalidate_blocks(struct dmz_metadata *zmd, struct dm_zone *zone,
|
||||
|
||||
/* Clear 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,
|
||||
bit, nr_bits);
|
||||
@ -2182,6 +2186,7 @@ static int dmz_to_next_set_block(struct dmz_metadata *zmd, struct dm_zone *zone,
|
||||
{
|
||||
struct dmz_mblock *mblk;
|
||||
unsigned int bit, set_bit, nr_bits;
|
||||
unsigned int zone_bits = zmd->zone_bits_per_mblk;
|
||||
unsigned long *bitmap;
|
||||
int n = 0;
|
||||
|
||||
@ -2196,15 +2201,15 @@ static int dmz_to_next_set_block(struct dmz_metadata *zmd, struct dm_zone *zone,
|
||||
/* Get offset */
|
||||
bitmap = (unsigned long *) mblk->data;
|
||||
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)
|
||||
set_bit = find_next_bit(bitmap, DMZ_BLOCK_SIZE_BITS, bit);
|
||||
set_bit = find_next_bit(bitmap, zone_bits, bit);
|
||||
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);
|
||||
|
||||
n += set_bit - bit;
|
||||
if (set_bit < DMZ_BLOCK_SIZE_BITS)
|
||||
if (set_bit < zone_bits)
|
||||
break;
|
||||
|
||||
nr_blocks -= nr_bits;
|
||||
@ -2307,7 +2312,7 @@ static void dmz_get_zone_weight(struct dmz_metadata *zmd, struct dm_zone *zone)
|
||||
/* Count bits in this block */
|
||||
bitmap = mblk->data;
|
||||
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);
|
||||
|
||||
dmz_release_mblock(zmd, mblk);
|
||||
|
Loading…
x
Reference in New Issue
Block a user