@@ -442,7 +442,6 @@ struct blk_revalidate_zone_args {
442442 unsigned long * conv_zones_bitmap ;
443443 unsigned long * seq_zones_wlock ;
444444 unsigned int nr_zones ;
445- sector_t zone_sectors ;
446445 sector_t sector ;
447446};
448447
@@ -456,38 +455,34 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
456455 struct gendisk * disk = args -> disk ;
457456 struct request_queue * q = disk -> queue ;
458457 sector_t capacity = get_capacity (disk );
458+ sector_t zone_sectors = q -> limits .chunk_sectors ;
459+
460+ /* Check for bad zones and holes in the zone report */
461+ if (zone -> start != args -> sector ) {
462+ pr_warn ("%s: Zone gap at sectors %llu..%llu\n" ,
463+ disk -> disk_name , args -> sector , zone -> start );
464+ return - ENODEV ;
465+ }
466+
467+ if (zone -> start >= capacity || !zone -> len ) {
468+ pr_warn ("%s: Invalid zone start %llu, length %llu\n" ,
469+ disk -> disk_name , zone -> start , zone -> len );
470+ return - ENODEV ;
471+ }
459472
460473 /*
461474 * All zones must have the same size, with the exception on an eventual
462475 * smaller last zone.
463476 */
464- if (zone -> start == 0 ) {
465- if (zone -> len == 0 || !is_power_of_2 (zone -> len )) {
466- pr_warn ("%s: Invalid zoned device with non power of two zone size (%llu)\n" ,
467- disk -> disk_name , zone -> len );
468- return - ENODEV ;
469- }
470-
471- args -> zone_sectors = zone -> len ;
472- args -> nr_zones = (capacity + zone -> len - 1 ) >> ilog2 (zone -> len );
473- } else if (zone -> start + args -> zone_sectors < capacity ) {
474- if (zone -> len != args -> zone_sectors ) {
477+ if (zone -> start + zone -> len < capacity ) {
478+ if (zone -> len != zone_sectors ) {
475479 pr_warn ("%s: Invalid zoned device with non constant zone size\n" ,
476480 disk -> disk_name );
477481 return - ENODEV ;
478482 }
479- } else {
480- if (zone -> len > args -> zone_sectors ) {
481- pr_warn ("%s: Invalid zoned device with larger last zone size\n" ,
482- disk -> disk_name );
483- return - ENODEV ;
484- }
485- }
486-
487- /* Check for holes in the zone report */
488- if (zone -> start != args -> sector ) {
489- pr_warn ("%s: Zone gap at sectors %llu..%llu\n" ,
490- disk -> disk_name , args -> sector , zone -> start );
483+ } else if (zone -> len > zone_sectors ) {
484+ pr_warn ("%s: Invalid zoned device with larger last zone size\n" ,
485+ disk -> disk_name );
491486 return - ENODEV ;
492487 }
493488
@@ -526,11 +521,13 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
526521 * @disk: Target disk
527522 * @update_driver_data: Callback to update driver data on the frozen disk
528523 *
529- * Helper function for low-level device drivers to (re) allocate and initialize
530- * a disk request queue zone bitmaps. This functions should normally be called
531- * within the disk ->revalidate method for blk-mq based drivers. For BIO based
532- * drivers only q->nr_zones needs to be updated so that the sysfs exposed value
533- * is correct.
524+ * Helper function for low-level device drivers to check and (re) allocate and
525+ * initialize a disk request queue zone bitmaps. This functions should normally
526+ * be called within the disk ->revalidate method for blk-mq based drivers.
527+ * Before calling this function, the device driver must already have set the
528+ * device zone size (chunk_sector limit) and the max zone append limit.
529+ * For BIO based drivers, this function cannot be used. BIO based device drivers
530+ * only need to set disk->nr_zones so that the sysfs exposed value is correct.
534531 * If the @update_driver_data callback function is not NULL, the callback is
535532 * executed with the device request queue frozen after all zones have been
536533 * checked.
@@ -539,9 +536,9 @@ int blk_revalidate_disk_zones(struct gendisk *disk,
539536 void (* update_driver_data )(struct gendisk * disk ))
540537{
541538 struct request_queue * q = disk -> queue ;
542- struct blk_revalidate_zone_args args = {
543- . disk = disk ,
544- };
539+ sector_t zone_sectors = q -> limits . chunk_sectors ;
540+ sector_t capacity = get_capacity ( disk );
541+ struct blk_revalidate_zone_args args = { };
545542 unsigned int noio_flag ;
546543 int ret ;
547544
@@ -550,13 +547,31 @@ int blk_revalidate_disk_zones(struct gendisk *disk,
550547 if (WARN_ON_ONCE (!queue_is_mq (q )))
551548 return - EIO ;
552549
553- if (!get_capacity (disk ))
554- return - EIO ;
550+ if (!capacity )
551+ return - ENODEV ;
552+
553+ /*
554+ * Checks that the device driver indicated a valid zone size and that
555+ * the max zone append limit is set.
556+ */
557+ if (!zone_sectors || !is_power_of_2 (zone_sectors )) {
558+ pr_warn ("%s: Invalid non power of two zone size (%llu)\n" ,
559+ disk -> disk_name , zone_sectors );
560+ return - ENODEV ;
561+ }
562+
563+ if (!q -> limits .max_zone_append_sectors ) {
564+ pr_warn ("%s: Invalid 0 maximum zone append limit\n" ,
565+ disk -> disk_name );
566+ return - ENODEV ;
567+ }
555568
556569 /*
557570 * Ensure that all memory allocations in this context are done as if
558571 * GFP_NOIO was specified.
559572 */
573+ args .disk = disk ;
574+ args .nr_zones = (capacity + zone_sectors - 1 ) >> ilog2 (zone_sectors );
560575 noio_flag = memalloc_noio_save ();
561576 ret = disk -> fops -> report_zones (disk , 0 , UINT_MAX ,
562577 blk_revalidate_zone_cb , & args );
@@ -570,7 +585,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk,
570585 * If zones where reported, make sure that the entire disk capacity
571586 * has been checked.
572587 */
573- if (ret > 0 && args .sector != get_capacity ( disk ) ) {
588+ if (ret > 0 && args .sector != capacity ) {
574589 pr_warn ("%s: Missing zones from sector %llu\n" ,
575590 disk -> disk_name , args .sector );
576591 ret = - ENODEV ;
@@ -583,7 +598,6 @@ int blk_revalidate_disk_zones(struct gendisk *disk,
583598 */
584599 blk_mq_freeze_queue (q );
585600 if (ret > 0 ) {
586- blk_queue_chunk_sectors (q , args .zone_sectors );
587601 disk -> nr_zones = args .nr_zones ;
588602 swap (disk -> seq_zones_wlock , args .seq_zones_wlock );
589603 swap (disk -> conv_zones_bitmap , args .conv_zones_bitmap );
0 commit comments