Commit fdb9aed8 authored by Damien Le Moal's avatar Damien Le Moal Committed by Jens Axboe
Browse files

block: introduce disk_report_zone()



Commit b76b840f ("dm: Fix dm-zoned-reclaim zone write pointer
alignment") introduced an indirect call for the callback function of a
report zones executed with blkdev_report_zones(). This is necessary so
that the function disk_zone_wplug_sync_wp_offset() can be called to
refresh a zone write plug zone write pointer offset after a write error.
However, this solution makes following the path of a zone information
harder to understand.

Clean this up by introducing the new blk_report_zones_args structure to
define a zone report callback and its private data and introduce the
helper function disk_report_zone() which calls both
disk_zone_wplug_sync_wp_offset() and the zone report user callback
function for all zones of a zone report. This helper function must be
called by all block device drivers that implement the report zones
block operation in order to correctly report a zone information.

All block device drivers supporting the report_zones block operation are
updated to use this new scheme.

Signed-off-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: default avatarChaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent e8ecb21f
Loading
Loading
Loading
Loading
+42 −37
Original line number Diff line number Diff line
@@ -114,30 +114,16 @@ const char *blk_zone_cond_str(enum blk_zone_cond zone_cond)
}
EXPORT_SYMBOL_GPL(blk_zone_cond_str);

struct disk_report_zones_cb_args {
	struct gendisk	*disk;
	report_zones_cb	user_cb;
	void		*user_data;
/*
 * Zone report arguments for block device drivers report_zones operation.
 * @cb: report_zones_cb callback for each reported zone.
 * @data: Private data passed to report_zones_cb.
 */
struct blk_report_zones_args {
	report_zones_cb cb;
	void		*data;
};

static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk,
					   struct blk_zone *zone);

static int disk_report_zones_cb(struct blk_zone *zone, unsigned int idx,
				void *data)
{
	struct disk_report_zones_cb_args *args = data;
	struct gendisk *disk = args->disk;

	if (disk->zone_wplugs_hash)
		disk_zone_wplug_sync_wp_offset(disk, zone);

	if (!args->user_cb)
		return 0;

	return args->user_cb(zone, idx, args->user_data);
}

/**
 * blkdev_report_zones - Get zones information
 * @bdev:	Target block device
@@ -161,10 +147,9 @@ int blkdev_report_zones(struct block_device *bdev, sector_t sector,
			unsigned int nr_zones, report_zones_cb cb, void *data)
{
	struct gendisk *disk = bdev->bd_disk;
	struct disk_report_zones_cb_args args = {
		.disk = disk,
		.user_cb = cb,
		.user_data = data,
	struct blk_report_zones_args args = {
		.cb = cb,
		.data = data,
	};

	if (!bdev_is_zoned(bdev) || WARN_ON_ONCE(!disk->fops->report_zones))
@@ -173,8 +158,7 @@ int blkdev_report_zones(struct block_device *bdev, sector_t sector,
	if (!nr_zones || sector >= get_capacity(disk))
		return 0;

	return disk->fops->report_zones(disk, sector, nr_zones,
					disk_report_zones_cb, &args);
	return disk->fops->report_zones(disk, sector, nr_zones, &args);
}
EXPORT_SYMBOL_GPL(blkdev_report_zones);

@@ -692,15 +676,32 @@ static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk,
	disk_put_zone_wplug(zwplug);
}

static int disk_zone_sync_wp_offset(struct gendisk *disk, sector_t sector)
/**
 * disk_report_zone - Report one zone
 * @disk:	Target disk
 * @zone:	The zone to report
 * @idx:	The index of the zone in the overall zone report
 * @args:	report zones callback and data
 *
 * Description:
 *    Helper function for block device drivers to report one zone of a zone
 *    report initiated with blkdev_report_zones(). The zone being reported is
 *    specified by @zone and used to update, if necessary, the zone write plug
 *    information for the zone. If @args specifies a user callback function,
 *    this callback is executed.
 */
int disk_report_zone(struct gendisk *disk, struct blk_zone *zone,
		     unsigned int idx, struct blk_report_zones_args *args)
{
	struct disk_report_zones_cb_args args = {
		.disk = disk,
	};
	if (disk->zone_wplugs_hash)
		disk_zone_wplug_sync_wp_offset(disk, zone);

	if (args && args->cb)
		return args->cb(zone, idx, args->data);

	return disk->fops->report_zones(disk, sector, 1,
					disk_report_zones_cb, &args);
	return 0;
}
EXPORT_SYMBOL_GPL(disk_report_zone);

static void blk_zone_reset_bio_endio(struct bio *bio)
{
@@ -1786,6 +1787,10 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
	sector_t capacity = get_capacity(disk);
	struct blk_revalidate_zone_args args = { };
	unsigned int memflags, noio_flag;
	struct blk_report_zones_args rep_args = {
		.cb = blk_revalidate_zone_cb,
		.data = &args,
	};
	int ret = -ENOMEM;

	if (WARN_ON_ONCE(!blk_queue_is_zoned(q)))
@@ -1817,8 +1822,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk)
		return ret;
	}

	ret = disk->fops->report_zones(disk, 0, UINT_MAX,
				       blk_revalidate_zone_cb, &args);
	ret = disk->fops->report_zones(disk, 0, UINT_MAX, &rep_args);
	if (!ret) {
		pr_warn("%s: No zones reported\n", disk->disk_name);
		ret = -ENODEV;
@@ -1863,6 +1867,7 @@ EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones);
int blk_zone_issue_zeroout(struct block_device *bdev, sector_t sector,
			   sector_t nr_sects, gfp_t gfp_mask)
{
	struct gendisk *disk = bdev->bd_disk;
	int ret;

	if (WARN_ON_ONCE(!bdev_is_zoned(bdev)))
@@ -1878,7 +1883,7 @@ int blk_zone_issue_zeroout(struct block_device *bdev, sector_t sector,
	 * pointer. Undo this using a report zone to update the zone write
	 * pointer to the correct current value.
	 */
	ret = disk_zone_sync_wp_offset(bdev->bd_disk, sector);
	ret = disk->fops->report_zones(disk, sector, 1, NULL);
	if (ret != 1)
		return ret < 0 ? ret : -EIO;

+2 −1
Original line number Diff line number Diff line
@@ -143,7 +143,8 @@ int null_init_zoned_dev(struct nullb_device *dev, struct queue_limits *lim);
int null_register_zoned_dev(struct nullb *nullb);
void null_free_zoned_dev(struct nullb_device *dev);
int null_report_zones(struct gendisk *disk, sector_t sector,
		      unsigned int nr_zones, report_zones_cb cb, void *data);
		      unsigned int nr_zones,
		      struct blk_report_zones_args *args);
blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
				    sector_t sector, sector_t nr_sectors);
size_t null_zone_valid_read_len(struct nullb *nullb,
+2 −2
Original line number Diff line number Diff line
@@ -191,7 +191,7 @@ void null_free_zoned_dev(struct nullb_device *dev)
}

int null_report_zones(struct gendisk *disk, sector_t sector,
		unsigned int nr_zones, report_zones_cb cb, void *data)
		unsigned int nr_zones, struct blk_report_zones_args *args)
{
	struct nullb *nullb = disk->private_data;
	struct nullb_device *dev = nullb->dev;
@@ -225,7 +225,7 @@ int null_report_zones(struct gendisk *disk, sector_t sector,
		blkz.capacity = zone->capacity;
		null_unlock_zone(dev, zone);

		error = cb(&blkz, i, data);
		error = disk_report_zone(disk, &blkz, i, args);
		if (error)
			return error;
	}
+2 −2
Original line number Diff line number Diff line
@@ -367,7 +367,7 @@ static void *ublk_alloc_report_buffer(struct ublk_device *ublk,
}

static int ublk_report_zones(struct gendisk *disk, sector_t sector,
		      unsigned int nr_zones, report_zones_cb cb, void *data)
		      unsigned int nr_zones, struct blk_report_zones_args *args)
{
	struct ublk_device *ub = disk->private_data;
	unsigned int zone_size_sectors = disk->queue->limits.chunk_sectors;
@@ -430,7 +430,7 @@ static int ublk_report_zones(struct gendisk *disk, sector_t sector,
			if (!zone->len)
				break;

			ret = cb(zone, i, data);
			ret = disk_report_zone(disk, zone, i, args);
			if (ret)
				goto out;

+6 −5
Original line number Diff line number Diff line
@@ -584,7 +584,8 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,

static int virtblk_parse_zone(struct virtio_blk *vblk,
			       struct virtio_blk_zone_descriptor *entry,
			       unsigned int idx, report_zones_cb cb, void *data)
			       unsigned int idx,
			       struct blk_report_zones_args *args)
{
	struct blk_zone zone = { };

@@ -650,12 +651,12 @@ static int virtblk_parse_zone(struct virtio_blk *vblk,
	 * The callback below checks the validity of the reported
	 * entry data, no need to further validate it here.
	 */
	return cb(&zone, idx, data);
	return disk_report_zone(vblk->disk, &zone, idx, args);
}

static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
				 unsigned int nr_zones, report_zones_cb cb,
				 void *data)
				 unsigned int nr_zones,
				 struct blk_report_zones_args *args)
{
	struct virtio_blk *vblk = disk->private_data;
	struct virtio_blk_zone_report *report;
@@ -693,7 +694,7 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,

		for (i = 0; i < nz && zone_idx < nr_zones; i++) {
			ret = virtblk_parse_zone(vblk, &report->zones[i],
						 zone_idx, cb, data);
						 zone_idx, args);
			if (ret)
				goto fail_report;

Loading