All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] dm-zoned: support zone sizes smaller than 128MiB
@ 2019-12-24  1:05 Dmitry Fomichev
  2019-12-25  4:33 ` Damien Le Moal
  0 siblings, 1 reply; 2+ messages in thread
From: Dmitry Fomichev @ 2019-12-24  1:05 UTC (permalink / raw)
  To: dm-devel, Mike Snitzer; +Cc: Dmitry Fomichev, Damien Le Moal

dm-zoned is observed to log failed kernel assertions and not to work
correctly when operating against a device with a zone size smaller
than 128MiB (4K block size times 32768 bits per 4K block). The reason
is that the bitmap size per zone is calculated as zero with such a
small zone size. This patch fixes this problem and also makes 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 and this patch is being posted
separately.

Fixes: 3b1a94c88b79 ("dm zoned: drive-managed zoned block device target")
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
 drivers/md/dm-zoned-metadata.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c
index 069e4675da6b..91512eb40458 100644
--- a/drivers/md/dm-zoned-metadata.c
+++ b/drivers/md/dm-zoned-metadata.c
@@ -134,6 +134,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;
@@ -1153,7 +1154,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);
@@ -1947,7 +1951,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;
@@ -2008,7 +2012,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) {
@@ -2087,7 +2091,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);
@@ -2147,6 +2151,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;
 
@@ -2161,15 +2166,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;
@@ -2272,7 +2277,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);
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] dm-zoned: support zone sizes smaller than 128MiB
  2019-12-24  1:05 [PATCH] dm-zoned: support zone sizes smaller than 128MiB Dmitry Fomichev
@ 2019-12-25  4:33 ` Damien Le Moal
  0 siblings, 0 replies; 2+ messages in thread
From: Damien Le Moal @ 2019-12-25  4:33 UTC (permalink / raw)
  To: Dmitry Fomichev, dm-devel, Mike Snitzer

On 2019/12/24 10:05, Dmitry Fomichev wrote:
> dm-zoned is observed to log failed kernel assertions and not to work
> correctly when operating against a device with a zone size smaller
> than 128MiB (4K block size times 32768 bits per 4K block). The reason
> is that the bitmap size per zone is calculated as zero with such a
> small zone size. This patch fixes this problem and also makes 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 and this patch is being posted
> separately.
> 
> Fixes: 3b1a94c88b79 ("dm zoned: drive-managed zoned block device target")
> Cc: stable@vger.kernel.org
> Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>

Looks good to me.

Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>


> ---
>  drivers/md/dm-zoned-metadata.c | 23 ++++++++++++++---------
>  1 file changed, 14 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c
> index 069e4675da6b..91512eb40458 100644
> --- a/drivers/md/dm-zoned-metadata.c
> +++ b/drivers/md/dm-zoned-metadata.c
> @@ -134,6 +134,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;
> @@ -1153,7 +1154,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);
> @@ -1947,7 +1951,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;
> @@ -2008,7 +2012,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) {
> @@ -2087,7 +2091,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);
> @@ -2147,6 +2151,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;
>  
> @@ -2161,15 +2166,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;
> @@ -2272,7 +2277,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);
> 


-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-12-25  4:33 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-24  1:05 [PATCH] dm-zoned: support zone sizes smaller than 128MiB Dmitry Fomichev
2019-12-25  4:33 ` Damien Le Moal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.