Looks good.

Reviewed-by: Chaitanya Kulkarni <[email protected]>

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: [email protected]
> Signed-off-by: Damien Le Moal <[email protected]>
> Reviewed-by: Bart Van Assche <[email protected]>
> ---
>   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,
> 

Reply via email to