Re: [PATCH V5 3/3] block: Limit zone array allocation size

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Looks good.

Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni@xxxxxxx>

On 6/27/19 2:29 AM, Damien Le Moal wrote:
> Limit the size of the struct blk_zone array used in
> blk_revalidate_disk_zones() to avoid memory allocation failures leading
> to disk revalidation failure. Further reduce the likelyhood of these
> failures by using kvmalloc() instead of directly allocating contiguous
> pages.
> 
> Fixes: 515ce6061312 ("scsi: sd_zbc: Fix sd_zbc_report_zones() buffer allocation")
> Fixes: e76239a3748c ("block: add a report_zones method")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Damien Le Moal <damien.lemoal@xxxxxxx>
> Reviewed-by: Bart Van Assche <bvanassche@xxxxxxx>
> ---
>   block/blk-zoned.c      | 29 +++++++++++++----------------
>   include/linux/blkdev.h |  5 +++++
>   2 files changed, 18 insertions(+), 16 deletions(-)
> 
> diff --git a/block/blk-zoned.c b/block/blk-zoned.c
> index ae7e91bd0618..26f878b9b5f5 100644
> --- a/block/blk-zoned.c
> +++ b/block/blk-zoned.c
> @@ -373,22 +373,20 @@ static inline unsigned long *blk_alloc_zone_bitmap(int node,
>    * Allocate an array of struct blk_zone to get nr_zones zone information.
>    * The allocated array may be smaller than nr_zones.
>    */
> -static struct blk_zone *blk_alloc_zones(int node, unsigned int *nr_zones)
> +static struct blk_zone *blk_alloc_zones(unsigned int *nr_zones)
>   {
> -	size_t size = *nr_zones * sizeof(struct blk_zone);
> -	struct page *page;
> -	int order;
> -
> -	for (order = get_order(size); order >= 0; order--) {
> -		page = alloc_pages_node(node, GFP_NOIO | __GFP_ZERO, order);
> -		if (page) {
> -			*nr_zones = min_t(unsigned int, *nr_zones,
> -				(PAGE_SIZE << order) / sizeof(struct blk_zone));
> -			return page_address(page);
> -		}
> +	struct blk_zone *zones;
> +	size_t nrz = min(*nr_zones, BLK_ZONED_REPORT_MAX_ZONES);
> +
> +	zones = kvcalloc(nrz, sizeof(struct blk_zone), GFP_NOIO);
> +	if (!zones) {
> +		*nr_zones = 0;
> +		return NULL;
>   	}
>   
> -	return NULL;
> +	*nr_zones = nrz;
> +
> +	return zones;
>   }
>   
>   void blk_queue_free_zone_bitmaps(struct request_queue *q)
> @@ -443,7 +441,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
>   
>   	/* Get zone information and initialize seq_zones_bitmap */
>   	rep_nr_zones = nr_zones;
> -	zones = blk_alloc_zones(q->node, &rep_nr_zones);
> +	zones = blk_alloc_zones(&rep_nr_zones);
>   	if (!zones)
>   		goto out;
>   
> @@ -480,8 +478,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
>   	blk_mq_unfreeze_queue(q);
>   
>   out:
> -	free_pages((unsigned long)zones,
> -		   get_order(rep_nr_zones * sizeof(struct blk_zone)));
> +	kvfree(zones);
>   	kfree(seq_zones_wlock);
>   	kfree(seq_zones_bitmap);
>   
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 592669bcc536..f7faac856017 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -344,6 +344,11 @@ struct queue_limits {
>   
>   #ifdef CONFIG_BLK_DEV_ZONED
>   
> +/*
> + * Maximum number of zones to report with a single report zones command.
> + */
> +#define BLK_ZONED_REPORT_MAX_ZONES	8192U
> +
>   extern unsigned int blkdev_nr_zones(struct block_device *bdev);
>   extern int blkdev_report_zones(struct block_device *bdev,
>   			       sector_t sector, struct blk_zone *zones,
> 





[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux