@@ -353,12 +353,14 @@ void blk_queue_free_zone_bitmaps(struct request_queue *q)
}
struct blk_revalidate_zone_args {
- struct gendisk *disk;
- unsigned long *conv_zones_bitmap;
- unsigned long *seq_zones_wlock;
- unsigned int nr_zones;
- sector_t zone_sectors;
- sector_t sector;
+ struct gendisk *disk;
+ revalidate_zones_cb revalidate_cb;
+ void *revalidate_data;
+ unsigned long *conv_zones_bitmap;
+ unsigned long *seq_zones_wlock;
+ unsigned int nr_zones;
+ sector_t zone_sectors;
+ sector_t sector;
};
/*
@@ -432,25 +434,37 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
return -ENODEV;
}
+ if (args->revalidate_cb)
+ args->revalidate_cb(zone, idx, args->revalidate_data);
+
args->sector += zone->len;
return 0;
}
/**
- * blk_revalidate_disk_zones - (re)allocate and initialize zone bitmaps
- * @disk: Target disk
+ * __blk_revalidate_disk_zones - (re)allocate and initialize zone bitmaps
+ * @disk: Target disk
+ * @revalidate_cb: LLD callback
+ * @revalidate_data: LLD callback argument
*
* Helper function for low-level device drivers to (re) allocate and initialize
* a disk request queue zone bitmaps. This functions should normally be called
* within the disk ->revalidate method for blk-mq based drivers. For BIO based
* drivers only q->nr_zones needs to be updated so that the sysfs exposed value
* is correct.
+ * If driver @revalidate_cb callback function is not NULL, the callback will be
+ * executed for each zone inspected as well as a final time to apply changes
+ * under with the device request queue frozen.
*/
-int blk_revalidate_disk_zones(struct gendisk *disk)
+int __blk_revalidate_disk_zones(struct gendisk *disk,
+ revalidate_zones_cb revalidate_cb,
+ void *revalidate_data)
{
struct request_queue *q = disk->queue;
struct blk_revalidate_zone_args args = {
- .disk = disk,
+ .disk = disk,
+ .revalidate_cb = revalidate_cb,
+ .revalidate_data = revalidate_data,
};
unsigned int noio_flag;
int ret;
@@ -480,6 +494,8 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
q->nr_zones = args.nr_zones;
swap(q->seq_zones_wlock, args.seq_zones_wlock);
swap(q->conv_zones_bitmap, args.conv_zones_bitmap);
+ if (revalidate_cb)
+ revalidate_cb(NULL, 0, revalidate_data);
ret = 0;
} else {
pr_warn("%s: failed to revalidate zones\n", disk->disk_name);
@@ -491,4 +507,4 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
kfree(args.conv_zones_bitmap);
return ret;
}
-EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones);
+EXPORT_SYMBOL_GPL(__blk_revalidate_disk_zones);
@@ -353,6 +353,9 @@ struct queue_limits {
typedef int (*report_zones_cb)(struct blk_zone *zone, unsigned int idx,
void *data);
+typedef void (*revalidate_zones_cb)(struct blk_zone *zone, unsigned int idx,
+ void *data);
+
#ifdef CONFIG_BLK_DEV_ZONED
#define BLK_ALL_ZONES ((unsigned int)-1)
@@ -362,7 +365,13 @@ unsigned int blkdev_nr_zones(struct gendisk *disk);
extern int blkdev_zone_mgmt(struct block_device *bdev, enum req_opf op,
sector_t sectors, sector_t nr_sectors,
gfp_t gfp_mask);
-extern int blk_revalidate_disk_zones(struct gendisk *disk);
+int __blk_revalidate_disk_zones(struct gendisk *disk,
+ revalidate_zones_cb revalidate_cb,
+ void *revalidate_data);
+static inline int blk_revalidate_disk_zones(struct gendisk *disk)
+{
+ return __blk_revalidate_disk_zones(disk, NULL, NULL);
+}
extern int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg);