All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] virtio-blk: fix a few problems in ZBD-related code
@ 2023-03-30 21:49 ` Dmitry Fomichev
  0 siblings, 0 replies; 15+ messages in thread
From: Dmitry Fomichev @ 2023-03-30 21:49 UTC (permalink / raw)
  To: Jens Axboe, linux-block, Michael S. Tsirkin, Damien Le Moal,
	Stefan Hajnoczi, Hannes Reinecke, Sam Li
  Cc: virtio-dev, virtualization, Dmitry Fomichev

This two-part series contains code fixes that are related to the
recently added support for zoned block devices in virtio-blk
driver.

The original ZBD patchset that was merged to the kernel -next was not
the latest and greatest version. The first patch of this series is
essentially a diff between the current code and the final revision of
the original patchset.

The second patch fixes a problem that is observed when a host-managed
zoned device is virtualized via virtio-blk and the driver kernel is
configured without ZBD support (CONFIG_BLK_DEV_ZONED not set). In this
case, the driver must not allow the device scan to succeed in order to
avoid erroneous device operation that may cause data loss. The
second patch adds this currently missing functionality.

v1 -> v2:

 - address nits from Damien
 - add Review-by tags from Stefan and Damien

Dmitry Fomichev (2):
  virtio-blk: migrate to the latest patchset version
  virtio-blk: fix ZBD probe in kernels without ZBD support

 drivers/block/virtio_blk.c      | 269 ++++++++++++++++++++------------
 include/uapi/linux/virtio_blk.h |  18 +--
 2 files changed, 182 insertions(+), 105 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [virtio-dev] [PATCH v2 0/2] virtio-blk: fix a few problems in ZBD-related code
@ 2023-03-30 21:49 ` Dmitry Fomichev
  0 siblings, 0 replies; 15+ messages in thread
From: Dmitry Fomichev @ 2023-03-30 21:49 UTC (permalink / raw)
  To: Jens Axboe, linux-block, Michael S. Tsirkin, Damien Le Moal,
	Stefan Hajnoczi, Hannes Reinecke, Sam Li
  Cc: virtio-dev, virtualization, Dmitry Fomichev

This two-part series contains code fixes that are related to the
recently added support for zoned block devices in virtio-blk
driver.

The original ZBD patchset that was merged to the kernel -next was not
the latest and greatest version. The first patch of this series is
essentially a diff between the current code and the final revision of
the original patchset.

The second patch fixes a problem that is observed when a host-managed
zoned device is virtualized via virtio-blk and the driver kernel is
configured without ZBD support (CONFIG_BLK_DEV_ZONED not set). In this
case, the driver must not allow the device scan to succeed in order to
avoid erroneous device operation that may cause data loss. The
second patch adds this currently missing functionality.

v1 -> v2:

 - address nits from Damien
 - add Review-by tags from Stefan and Damien

Dmitry Fomichev (2):
  virtio-blk: migrate to the latest patchset version
  virtio-blk: fix ZBD probe in kernels without ZBD support

 drivers/block/virtio_blk.c      | 269 ++++++++++++++++++++------------
 include/uapi/linux/virtio_blk.h |  18 +--
 2 files changed, 182 insertions(+), 105 deletions(-)

-- 
2.34.1


---------------------------------------------------------------------
To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
  2023-03-30 21:49 ` [virtio-dev] " Dmitry Fomichev
@ 2023-03-30 21:49   ` Dmitry Fomichev
  -1 siblings, 0 replies; 15+ messages in thread
From: Dmitry Fomichev @ 2023-03-30 21:49 UTC (permalink / raw)
  To: Jens Axboe, linux-block, Michael S. Tsirkin, Damien Le Moal,
	Stefan Hajnoczi, Hannes Reinecke, Sam Li
  Cc: virtio-dev, virtualization, Dmitry Fomichev

The merged patch series to support zoned block devices in virtio-blk
is not the most up to date version. The merged patch can be found at

https://lore.kernel.org/linux-block/20221016034127.330942-3-dmitry.fomichev@wdc.com/

, but the latest and reviewed version is

https://lore.kernel.org/linux-block/20221110053952.3378990-3-dmitry.fomichev@wdc.com/

The differences between the two are mostly cleanups, but there is one
change that is very important in terms of compatibility with the
approved virtio-zbd specification.

Before it was approved, the OASIS virtio spec had a change in
VIRTIO_BLK_T_ZONE_APPEND request layout that is not reflected in the
current virtio-blk driver code. In the running code, the status is
the first byte of the in-header that is followed by some pad bytes
and the u64 that carries the sector at which the data has been written
to the zone back to the driver, aka the append sector.

This layout turned out to be problematic for implementing in QEMU and
the request status byte has been eventually made the last byte of the
in-header. The current code doesn't expect that and this causes the
append sector value always come as zero to the block layer. This needs
to be fixed ASAP.

Fixes: 95bfec41bd3d ("virtio-blk: add support for zoned block devices")
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
---
 drivers/block/virtio_blk.c      | 238 +++++++++++++++++++++-----------
 include/uapi/linux/virtio_blk.h |  18 +--
 2 files changed, 166 insertions(+), 90 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 2723eede6f21..4f0dbbb3d4a5 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -96,16 +96,14 @@ struct virtblk_req {
 
 		/*
 		 * The zone append command has an extended in header.
-		 * The status field in zone_append_in_hdr must have
-		 * the same offset in virtblk_req as the non-zoned
-		 * status field above.
+		 * The status field in zone_append_in_hdr must always
+		 * be the last byte.
 		 */
 		struct {
+			__virtio64 sector;
 			u8 status;
-			u8 reserved[7];
-			__le64 append_sector;
-		} zone_append_in_hdr;
-	};
+		} zone_append;
+	} in_hdr;
 
 	size_t in_hdr_len;
 
@@ -154,7 +152,7 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)
 			sgs[num_out + num_in++] = vbr->sg_table.sgl;
 	}
 
-	sg_init_one(&in_hdr, &vbr->status, vbr->in_hdr_len);
+	sg_init_one(&in_hdr, &vbr->in_hdr.status, vbr->in_hdr_len);
 	sgs[num_out + num_in++] = &in_hdr;
 
 	return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
@@ -242,11 +240,14 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
 				      struct request *req,
 				      struct virtblk_req *vbr)
 {
-	size_t in_hdr_len = sizeof(vbr->status);
+	size_t in_hdr_len = sizeof(vbr->in_hdr.status);
 	bool unmap = false;
 	u32 type;
 	u64 sector = 0;
 
+	if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) && op_is_zone_mgmt(req_op(req)))
+		return BLK_STS_NOTSUPP;
+
 	/* Set fields for all request types */
 	vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
 
@@ -287,7 +288,7 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
 	case REQ_OP_ZONE_APPEND:
 		type = VIRTIO_BLK_T_ZONE_APPEND;
 		sector = blk_rq_pos(req);
-		in_hdr_len = sizeof(vbr->zone_append_in_hdr);
+		in_hdr_len = sizeof(vbr->in_hdr.zone_append);
 		break;
 	case REQ_OP_ZONE_RESET:
 		type = VIRTIO_BLK_T_ZONE_RESET;
@@ -297,7 +298,10 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
 		type = VIRTIO_BLK_T_ZONE_RESET_ALL;
 		break;
 	case REQ_OP_DRV_IN:
-		/* Out header already filled in, nothing to do */
+		/*
+		 * Out header has already been prepared by the caller (virtblk_get_id()
+		 * or virtblk_submit_zone_report()), nothing to do here.
+		 */
 		return 0;
 	default:
 		WARN_ON_ONCE(1);
@@ -318,16 +322,28 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
 	return 0;
 }
 
+/*
+ * The status byte is always the last byte of the virtblk request
+ * in-header. This helper fetches its value for all in-header formats
+ * that are currently defined.
+ */
+static inline u8 virtblk_vbr_status(struct virtblk_req *vbr)
+{
+	return *((u8 *)&vbr->in_hdr + vbr->in_hdr_len - 1);
+}
+
 static inline void virtblk_request_done(struct request *req)
 {
 	struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
-	blk_status_t status = virtblk_result(vbr->status);
+	blk_status_t status = virtblk_result(virtblk_vbr_status(vbr));
+	struct virtio_blk *vblk = req->mq_hctx->queue->queuedata;
 
 	virtblk_unmap_data(req, vbr);
 	virtblk_cleanup_cmd(req);
 
 	if (req_op(req) == REQ_OP_ZONE_APPEND)
-		req->__sector = le64_to_cpu(vbr->zone_append_in_hdr.append_sector);
+		req->__sector = virtio64_to_cpu(vblk->vdev,
+						vbr->in_hdr.zone_append.sector);
 
 	blk_mq_end_request(req, status);
 }
@@ -355,7 +371,7 @@ static int virtblk_handle_req(struct virtio_blk_vq *vq,
 
 		if (likely(!blk_should_fake_timeout(req->q)) &&
 		    !blk_mq_complete_request_remote(req) &&
-		    !blk_mq_add_to_batch(req, iob, vbr->status,
+		    !blk_mq_add_to_batch(req, iob, virtblk_vbr_status(vbr),
 					 virtblk_complete_batch))
 			virtblk_request_done(req);
 		req_done++;
@@ -550,7 +566,6 @@ static void virtio_queue_rqs(struct request **rqlist)
 #ifdef CONFIG_BLK_DEV_ZONED
 static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
 					  unsigned int nr_zones,
-					  unsigned int zone_sectors,
 					  size_t *buflen)
 {
 	struct request_queue *q = vblk->disk->queue;
@@ -558,7 +573,7 @@ static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
 	void *buf;
 
 	nr_zones = min_t(unsigned int, nr_zones,
-			 get_capacity(vblk->disk) >> ilog2(zone_sectors));
+			 get_capacity(vblk->disk) >> ilog2(vblk->zone_sectors));
 
 	bufsize = sizeof(struct virtio_blk_zone_report) +
 		nr_zones * sizeof(struct virtio_blk_zone_descriptor);
@@ -592,7 +607,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
 		return PTR_ERR(req);
 
 	vbr = blk_mq_rq_to_pdu(req);
-	vbr->in_hdr_len = sizeof(vbr->status);
+	vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
 	vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT);
 	vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector);
 
@@ -601,7 +616,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
 		goto out;
 
 	blk_execute_rq(req, false);
-	err = blk_status_to_errno(virtblk_result(vbr->status));
+	err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
 out:
 	blk_mq_free_request(req);
 	return err;
@@ -609,29 +624,72 @@ 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, unsigned int zone_sectors,
-			       report_zones_cb cb, void *data)
+			       unsigned int idx, report_zones_cb cb, void *data)
 {
 	struct blk_zone zone = { };
 
-	if (entry->z_type != VIRTIO_BLK_ZT_SWR &&
-	    entry->z_type != VIRTIO_BLK_ZT_SWP &&
-	    entry->z_type != VIRTIO_BLK_ZT_CONV) {
-		dev_err(&vblk->vdev->dev, "invalid zone type %#x\n",
-			entry->z_type);
-		return -EINVAL;
+	zone.start = virtio64_to_cpu(vblk->vdev, entry->z_start);
+	if (zone.start + vblk->zone_sectors <= get_capacity(vblk->disk))
+		zone.len = vblk->zone_sectors;
+	else
+		zone.len = get_capacity(vblk->disk) - zone.start;
+	zone.capacity = virtio64_to_cpu(vblk->vdev, entry->z_cap);
+	zone.wp = virtio64_to_cpu(vblk->vdev, entry->z_wp);
+
+	switch (entry->z_type) {
+	case VIRTIO_BLK_ZT_SWR:
+		zone.type = BLK_ZONE_TYPE_SEQWRITE_REQ;
+		break;
+	case VIRTIO_BLK_ZT_SWP:
+		zone.type = BLK_ZONE_TYPE_SEQWRITE_PREF;
+		break;
+	case VIRTIO_BLK_ZT_CONV:
+		zone.type = BLK_ZONE_TYPE_CONVENTIONAL;
+		break;
+	default:
+		dev_err(&vblk->vdev->dev, "zone %llu: invalid type %#x\n",
+			zone.start, entry->z_type);
+		return -EIO;
 	}
 
-	zone.type = entry->z_type;
-	zone.cond = entry->z_state;
-	zone.len = zone_sectors;
-	zone.capacity = le64_to_cpu(entry->z_cap);
-	zone.start = le64_to_cpu(entry->z_start);
-	if (zone.cond == BLK_ZONE_COND_FULL)
+	switch (entry->z_state) {
+	case VIRTIO_BLK_ZS_EMPTY:
+		zone.cond = BLK_ZONE_COND_EMPTY;
+		break;
+	case VIRTIO_BLK_ZS_CLOSED:
+		zone.cond = BLK_ZONE_COND_CLOSED;
+		break;
+	case VIRTIO_BLK_ZS_FULL:
+		zone.cond = BLK_ZONE_COND_FULL;
 		zone.wp = zone.start + zone.len;
-	else
-		zone.wp = le64_to_cpu(entry->z_wp);
+		break;
+	case VIRTIO_BLK_ZS_EOPEN:
+		zone.cond = BLK_ZONE_COND_EXP_OPEN;
+		break;
+	case VIRTIO_BLK_ZS_IOPEN:
+		zone.cond = BLK_ZONE_COND_IMP_OPEN;
+		break;
+	case VIRTIO_BLK_ZS_NOT_WP:
+		zone.cond = BLK_ZONE_COND_NOT_WP;
+		break;
+	case VIRTIO_BLK_ZS_RDONLY:
+		zone.cond = BLK_ZONE_COND_READONLY;
+		zone.wp = ULONG_MAX;
+		break;
+	case VIRTIO_BLK_ZS_OFFLINE:
+		zone.cond = BLK_ZONE_COND_OFFLINE;
+		zone.wp = ULONG_MAX;
+		break;
+	default:
+		dev_err(&vblk->vdev->dev, "zone %llu: invalid condition %#x\n",
+			zone.start, entry->z_state);
+		return -EIO;
+	}
 
+	/*
+	 * The callback below checks the validity of the reported
+	 * entry data, no need to further validate it here.
+	 */
 	return cb(&zone, idx, data);
 }
 
@@ -641,39 +699,47 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
 {
 	struct virtio_blk *vblk = disk->private_data;
 	struct virtio_blk_zone_report *report;
-	unsigned int zone_sectors = vblk->zone_sectors;
-	unsigned int nz, i;
-	int ret, zone_idx = 0;
+	unsigned long long nz, i;
 	size_t buflen;
+	unsigned int zone_idx = 0;
+	int ret;
 
 	if (WARN_ON_ONCE(!vblk->zone_sectors))
 		return -EOPNOTSUPP;
 
-	report = virtblk_alloc_report_buffer(vblk, nr_zones,
-					     zone_sectors, &buflen);
+	report = virtblk_alloc_report_buffer(vblk, nr_zones, &buflen);
 	if (!report)
 		return -ENOMEM;
 
+	mutex_lock(&vblk->vdev_mutex);
+
+	if (!vblk->vdev) {
+		ret = -ENXIO;
+		goto fail_report;
+	}
+
 	while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) {
 		memset(report, 0, buflen);
 
 		ret = virtblk_submit_zone_report(vblk, (char *)report,
 						 buflen, sector);
-		if (ret) {
-			if (ret > 0)
-				ret = -EIO;
-			goto out_free;
-		}
-		nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones);
+		if (ret)
+			goto fail_report;
+
+		nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones),
+			   nr_zones);
 		if (!nz)
 			break;
 
 		for (i = 0; i < nz && zone_idx < nr_zones; i++) {
 			ret = virtblk_parse_zone(vblk, &report->zones[i],
-						 zone_idx, zone_sectors, cb, data);
+						 zone_idx, cb, data);
 			if (ret)
-				goto out_free;
-			sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors;
+				goto fail_report;
+
+			sector = virtio64_to_cpu(vblk->vdev,
+						 report->zones[i].z_start) +
+				 vblk->zone_sectors;
 			zone_idx++;
 		}
 	}
@@ -682,7 +748,8 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
 		ret = zone_idx;
 	else
 		ret = -EINVAL;
-out_free:
+fail_report:
+	mutex_unlock(&vblk->vdev_mutex);
 	kvfree(report);
 	return ret;
 }
@@ -691,20 +758,28 @@ static void virtblk_revalidate_zones(struct virtio_blk *vblk)
 {
 	u8 model;
 
-	if (!vblk->zone_sectors)
-		return;
-
 	virtio_cread(vblk->vdev, struct virtio_blk_config,
 		     zoned.model, &model);
-	if (!blk_revalidate_disk_zones(vblk->disk, NULL))
-		set_capacity_and_notify(vblk->disk, 0);
+	switch (model) {
+	default:
+		dev_err(&vblk->vdev->dev, "unknown zone model %d\n", model);
+		fallthrough;
+	case VIRTIO_BLK_Z_NONE:
+	case VIRTIO_BLK_Z_HA:
+		disk_set_zoned(vblk->disk, BLK_ZONED_NONE);
+		return;
+	case VIRTIO_BLK_Z_HM:
+		WARN_ON_ONCE(!vblk->zone_sectors);
+		if (!blk_revalidate_disk_zones(vblk->disk, NULL))
+			set_capacity_and_notify(vblk->disk, 0);
+	}
 }
 
 static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 				       struct virtio_blk *vblk,
 				       struct request_queue *q)
 {
-	u32 v;
+	u32 v, wg;
 	u8 model;
 	int ret;
 
@@ -713,16 +788,11 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 
 	switch (model) {
 	case VIRTIO_BLK_Z_NONE:
+	case VIRTIO_BLK_Z_HA:
+		/* Present the host-aware device as non-zoned */
 		return 0;
 	case VIRTIO_BLK_Z_HM:
 		break;
-	case VIRTIO_BLK_Z_HA:
-		/*
-		 * Present the host-aware device as a regular drive.
-		 * TODO It is possible to add an option to make it appear
-		 * in the system as a zoned drive.
-		 */
-		return 0;
 	default:
 		dev_err(&vdev->dev, "unsupported zone model %d\n", model);
 		return -EINVAL;
@@ -735,32 +805,31 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 
 	virtio_cread(vdev, struct virtio_blk_config,
 		     zoned.max_open_zones, &v);
-	disk_set_max_open_zones(vblk->disk, le32_to_cpu(v));
-
-	dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v));
+	disk_set_max_open_zones(vblk->disk, v);
+	dev_dbg(&vdev->dev, "max open zones = %u\n", v);
 
 	virtio_cread(vdev, struct virtio_blk_config,
 		     zoned.max_active_zones, &v);
-	disk_set_max_active_zones(vblk->disk, le32_to_cpu(v));
-	dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v));
+	disk_set_max_active_zones(vblk->disk, v);
+	dev_dbg(&vdev->dev, "max active zones = %u\n", v);
 
 	virtio_cread(vdev, struct virtio_blk_config,
-		     zoned.write_granularity, &v);
-	if (!v) {
+		     zoned.write_granularity, &wg);
+	if (!wg) {
 		dev_warn(&vdev->dev, "zero write granularity reported\n");
 		return -ENODEV;
 	}
-	blk_queue_physical_block_size(q, le32_to_cpu(v));
-	blk_queue_io_min(q, le32_to_cpu(v));
+	blk_queue_physical_block_size(q, wg);
+	blk_queue_io_min(q, wg);
 
-	dev_dbg(&vdev->dev, "write granularity = %u\n", le32_to_cpu(v));
+	dev_dbg(&vdev->dev, "write granularity = %u\n", wg);
 
 	/*
 	 * virtio ZBD specification doesn't require zones to be a power of
 	 * two sectors in size, but the code in this driver expects that.
 	 */
-	virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, &v);
-	vblk->zone_sectors = le32_to_cpu(v);
+	virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors,
+		     &vblk->zone_sectors);
 	if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) {
 		dev_err(&vdev->dev,
 			"zoned device with non power of two zone size %u\n",
@@ -783,8 +852,15 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 			dev_warn(&vdev->dev, "zero max_append_sectors reported\n");
 			return -ENODEV;
 		}
-		blk_queue_max_zone_append_sectors(q, le32_to_cpu(v));
-		dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v));
+		if ((v << SECTOR_SHIFT) < wg) {
+			dev_err(&vdev->dev,
+				"write granularity %u exceeds max_append_sectors %u limit\n",
+				wg, v);
+			return -ENODEV;
+		}
+
+		blk_queue_max_zone_append_sectors(q, v);
+		dev_dbg(&vdev->dev, "max append sectors = %u\n", v);
 	}
 
 	return ret;
@@ -794,6 +870,7 @@ static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
 {
 	return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED);
 }
+
 #else
 
 /*
@@ -801,9 +878,11 @@ static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
  * We only need to define a few symbols to avoid compilation errors.
  */
 #define virtblk_report_zones       NULL
+
 static inline void virtblk_revalidate_zones(struct virtio_blk *vblk)
 {
 }
+
 static inline int virtblk_probe_zoned_device(struct virtio_device *vdev,
 			struct virtio_blk *vblk, struct request_queue *q)
 {
@@ -831,7 +910,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
 		return PTR_ERR(req);
 
 	vbr = blk_mq_rq_to_pdu(req);
-	vbr->in_hdr_len = sizeof(vbr->status);
+	vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
 	vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
 	vbr->out_hdr.sector = 0;
 
@@ -840,7 +919,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
 		goto out;
 
 	blk_execute_rq(req, false);
-	err = blk_status_to_errno(virtblk_result(vbr->status));
+	err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
 out:
 	blk_mq_free_request(req);
 	return err;
@@ -1504,9 +1583,6 @@ static int virtblk_probe(struct virtio_device *vdev)
 			goto out_cleanup_disk;
 	}
 
-	dev_info(&vdev->dev, "blk config size: %zu\n",
-		sizeof(struct virtio_blk_config));
-
 	err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
 	if (err)
 		goto out_cleanup_disk;
diff --git a/include/uapi/linux/virtio_blk.h b/include/uapi/linux/virtio_blk.h
index 5af2a0300bb9..3744e4da1b2a 100644
--- a/include/uapi/linux/virtio_blk.h
+++ b/include/uapi/linux/virtio_blk.h
@@ -140,11 +140,11 @@ struct virtio_blk_config {
 
 	/* Zoned block device characteristics (if VIRTIO_BLK_F_ZONED) */
 	struct virtio_blk_zoned_characteristics {
-		__le32 zone_sectors;
-		__le32 max_open_zones;
-		__le32 max_active_zones;
-		__le32 max_append_sectors;
-		__le32 write_granularity;
+		__virtio32 zone_sectors;
+		__virtio32 max_open_zones;
+		__virtio32 max_active_zones;
+		__virtio32 max_append_sectors;
+		__virtio32 write_granularity;
 		__u8 model;
 		__u8 unused2[3];
 	} zoned;
@@ -241,11 +241,11 @@ struct virtio_blk_outhdr {
  */
 struct virtio_blk_zone_descriptor {
 	/* Zone capacity */
-	__le64 z_cap;
+	__virtio64 z_cap;
 	/* The starting sector of the zone */
-	__le64 z_start;
+	__virtio64 z_start;
 	/* Zone write pointer position in sectors */
-	__le64 z_wp;
+	__virtio64 z_wp;
 	/* Zone type */
 	__u8 z_type;
 	/* Zone state */
@@ -254,7 +254,7 @@ struct virtio_blk_zone_descriptor {
 };
 
 struct virtio_blk_zone_report {
-	__le64 nr_zones;
+	__virtio64 nr_zones;
 	__u8 reserved[56];
 	struct virtio_blk_zone_descriptor zones[];
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [virtio-dev] [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
@ 2023-03-30 21:49   ` Dmitry Fomichev
  0 siblings, 0 replies; 15+ messages in thread
From: Dmitry Fomichev @ 2023-03-30 21:49 UTC (permalink / raw)
  To: Jens Axboe, linux-block, Michael S. Tsirkin, Damien Le Moal,
	Stefan Hajnoczi, Hannes Reinecke, Sam Li
  Cc: virtio-dev, virtualization, Dmitry Fomichev

The merged patch series to support zoned block devices in virtio-blk
is not the most up to date version. The merged patch can be found at

https://lore.kernel.org/linux-block/20221016034127.330942-3-dmitry.fomichev@wdc.com/

, but the latest and reviewed version is

https://lore.kernel.org/linux-block/20221110053952.3378990-3-dmitry.fomichev@wdc.com/

The differences between the two are mostly cleanups, but there is one
change that is very important in terms of compatibility with the
approved virtio-zbd specification.

Before it was approved, the OASIS virtio spec had a change in
VIRTIO_BLK_T_ZONE_APPEND request layout that is not reflected in the
current virtio-blk driver code. In the running code, the status is
the first byte of the in-header that is followed by some pad bytes
and the u64 that carries the sector at which the data has been written
to the zone back to the driver, aka the append sector.

This layout turned out to be problematic for implementing in QEMU and
the request status byte has been eventually made the last byte of the
in-header. The current code doesn't expect that and this causes the
append sector value always come as zero to the block layer. This needs
to be fixed ASAP.

Fixes: 95bfec41bd3d ("virtio-blk: add support for zoned block devices")
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
---
 drivers/block/virtio_blk.c      | 238 +++++++++++++++++++++-----------
 include/uapi/linux/virtio_blk.h |  18 +--
 2 files changed, 166 insertions(+), 90 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 2723eede6f21..4f0dbbb3d4a5 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -96,16 +96,14 @@ struct virtblk_req {
 
 		/*
 		 * The zone append command has an extended in header.
-		 * The status field in zone_append_in_hdr must have
-		 * the same offset in virtblk_req as the non-zoned
-		 * status field above.
+		 * The status field in zone_append_in_hdr must always
+		 * be the last byte.
 		 */
 		struct {
+			__virtio64 sector;
 			u8 status;
-			u8 reserved[7];
-			__le64 append_sector;
-		} zone_append_in_hdr;
-	};
+		} zone_append;
+	} in_hdr;
 
 	size_t in_hdr_len;
 
@@ -154,7 +152,7 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)
 			sgs[num_out + num_in++] = vbr->sg_table.sgl;
 	}
 
-	sg_init_one(&in_hdr, &vbr->status, vbr->in_hdr_len);
+	sg_init_one(&in_hdr, &vbr->in_hdr.status, vbr->in_hdr_len);
 	sgs[num_out + num_in++] = &in_hdr;
 
 	return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
@@ -242,11 +240,14 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
 				      struct request *req,
 				      struct virtblk_req *vbr)
 {
-	size_t in_hdr_len = sizeof(vbr->status);
+	size_t in_hdr_len = sizeof(vbr->in_hdr.status);
 	bool unmap = false;
 	u32 type;
 	u64 sector = 0;
 
+	if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) && op_is_zone_mgmt(req_op(req)))
+		return BLK_STS_NOTSUPP;
+
 	/* Set fields for all request types */
 	vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
 
@@ -287,7 +288,7 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
 	case REQ_OP_ZONE_APPEND:
 		type = VIRTIO_BLK_T_ZONE_APPEND;
 		sector = blk_rq_pos(req);
-		in_hdr_len = sizeof(vbr->zone_append_in_hdr);
+		in_hdr_len = sizeof(vbr->in_hdr.zone_append);
 		break;
 	case REQ_OP_ZONE_RESET:
 		type = VIRTIO_BLK_T_ZONE_RESET;
@@ -297,7 +298,10 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
 		type = VIRTIO_BLK_T_ZONE_RESET_ALL;
 		break;
 	case REQ_OP_DRV_IN:
-		/* Out header already filled in, nothing to do */
+		/*
+		 * Out header has already been prepared by the caller (virtblk_get_id()
+		 * or virtblk_submit_zone_report()), nothing to do here.
+		 */
 		return 0;
 	default:
 		WARN_ON_ONCE(1);
@@ -318,16 +322,28 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
 	return 0;
 }
 
+/*
+ * The status byte is always the last byte of the virtblk request
+ * in-header. This helper fetches its value for all in-header formats
+ * that are currently defined.
+ */
+static inline u8 virtblk_vbr_status(struct virtblk_req *vbr)
+{
+	return *((u8 *)&vbr->in_hdr + vbr->in_hdr_len - 1);
+}
+
 static inline void virtblk_request_done(struct request *req)
 {
 	struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
-	blk_status_t status = virtblk_result(vbr->status);
+	blk_status_t status = virtblk_result(virtblk_vbr_status(vbr));
+	struct virtio_blk *vblk = req->mq_hctx->queue->queuedata;
 
 	virtblk_unmap_data(req, vbr);
 	virtblk_cleanup_cmd(req);
 
 	if (req_op(req) == REQ_OP_ZONE_APPEND)
-		req->__sector = le64_to_cpu(vbr->zone_append_in_hdr.append_sector);
+		req->__sector = virtio64_to_cpu(vblk->vdev,
+						vbr->in_hdr.zone_append.sector);
 
 	blk_mq_end_request(req, status);
 }
@@ -355,7 +371,7 @@ static int virtblk_handle_req(struct virtio_blk_vq *vq,
 
 		if (likely(!blk_should_fake_timeout(req->q)) &&
 		    !blk_mq_complete_request_remote(req) &&
-		    !blk_mq_add_to_batch(req, iob, vbr->status,
+		    !blk_mq_add_to_batch(req, iob, virtblk_vbr_status(vbr),
 					 virtblk_complete_batch))
 			virtblk_request_done(req);
 		req_done++;
@@ -550,7 +566,6 @@ static void virtio_queue_rqs(struct request **rqlist)
 #ifdef CONFIG_BLK_DEV_ZONED
 static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
 					  unsigned int nr_zones,
-					  unsigned int zone_sectors,
 					  size_t *buflen)
 {
 	struct request_queue *q = vblk->disk->queue;
@@ -558,7 +573,7 @@ static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
 	void *buf;
 
 	nr_zones = min_t(unsigned int, nr_zones,
-			 get_capacity(vblk->disk) >> ilog2(zone_sectors));
+			 get_capacity(vblk->disk) >> ilog2(vblk->zone_sectors));
 
 	bufsize = sizeof(struct virtio_blk_zone_report) +
 		nr_zones * sizeof(struct virtio_blk_zone_descriptor);
@@ -592,7 +607,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
 		return PTR_ERR(req);
 
 	vbr = blk_mq_rq_to_pdu(req);
-	vbr->in_hdr_len = sizeof(vbr->status);
+	vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
 	vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT);
 	vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector);
 
@@ -601,7 +616,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
 		goto out;
 
 	blk_execute_rq(req, false);
-	err = blk_status_to_errno(virtblk_result(vbr->status));
+	err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
 out:
 	blk_mq_free_request(req);
 	return err;
@@ -609,29 +624,72 @@ 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, unsigned int zone_sectors,
-			       report_zones_cb cb, void *data)
+			       unsigned int idx, report_zones_cb cb, void *data)
 {
 	struct blk_zone zone = { };
 
-	if (entry->z_type != VIRTIO_BLK_ZT_SWR &&
-	    entry->z_type != VIRTIO_BLK_ZT_SWP &&
-	    entry->z_type != VIRTIO_BLK_ZT_CONV) {
-		dev_err(&vblk->vdev->dev, "invalid zone type %#x\n",
-			entry->z_type);
-		return -EINVAL;
+	zone.start = virtio64_to_cpu(vblk->vdev, entry->z_start);
+	if (zone.start + vblk->zone_sectors <= get_capacity(vblk->disk))
+		zone.len = vblk->zone_sectors;
+	else
+		zone.len = get_capacity(vblk->disk) - zone.start;
+	zone.capacity = virtio64_to_cpu(vblk->vdev, entry->z_cap);
+	zone.wp = virtio64_to_cpu(vblk->vdev, entry->z_wp);
+
+	switch (entry->z_type) {
+	case VIRTIO_BLK_ZT_SWR:
+		zone.type = BLK_ZONE_TYPE_SEQWRITE_REQ;
+		break;
+	case VIRTIO_BLK_ZT_SWP:
+		zone.type = BLK_ZONE_TYPE_SEQWRITE_PREF;
+		break;
+	case VIRTIO_BLK_ZT_CONV:
+		zone.type = BLK_ZONE_TYPE_CONVENTIONAL;
+		break;
+	default:
+		dev_err(&vblk->vdev->dev, "zone %llu: invalid type %#x\n",
+			zone.start, entry->z_type);
+		return -EIO;
 	}
 
-	zone.type = entry->z_type;
-	zone.cond = entry->z_state;
-	zone.len = zone_sectors;
-	zone.capacity = le64_to_cpu(entry->z_cap);
-	zone.start = le64_to_cpu(entry->z_start);
-	if (zone.cond == BLK_ZONE_COND_FULL)
+	switch (entry->z_state) {
+	case VIRTIO_BLK_ZS_EMPTY:
+		zone.cond = BLK_ZONE_COND_EMPTY;
+		break;
+	case VIRTIO_BLK_ZS_CLOSED:
+		zone.cond = BLK_ZONE_COND_CLOSED;
+		break;
+	case VIRTIO_BLK_ZS_FULL:
+		zone.cond = BLK_ZONE_COND_FULL;
 		zone.wp = zone.start + zone.len;
-	else
-		zone.wp = le64_to_cpu(entry->z_wp);
+		break;
+	case VIRTIO_BLK_ZS_EOPEN:
+		zone.cond = BLK_ZONE_COND_EXP_OPEN;
+		break;
+	case VIRTIO_BLK_ZS_IOPEN:
+		zone.cond = BLK_ZONE_COND_IMP_OPEN;
+		break;
+	case VIRTIO_BLK_ZS_NOT_WP:
+		zone.cond = BLK_ZONE_COND_NOT_WP;
+		break;
+	case VIRTIO_BLK_ZS_RDONLY:
+		zone.cond = BLK_ZONE_COND_READONLY;
+		zone.wp = ULONG_MAX;
+		break;
+	case VIRTIO_BLK_ZS_OFFLINE:
+		zone.cond = BLK_ZONE_COND_OFFLINE;
+		zone.wp = ULONG_MAX;
+		break;
+	default:
+		dev_err(&vblk->vdev->dev, "zone %llu: invalid condition %#x\n",
+			zone.start, entry->z_state);
+		return -EIO;
+	}
 
+	/*
+	 * The callback below checks the validity of the reported
+	 * entry data, no need to further validate it here.
+	 */
 	return cb(&zone, idx, data);
 }
 
@@ -641,39 +699,47 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
 {
 	struct virtio_blk *vblk = disk->private_data;
 	struct virtio_blk_zone_report *report;
-	unsigned int zone_sectors = vblk->zone_sectors;
-	unsigned int nz, i;
-	int ret, zone_idx = 0;
+	unsigned long long nz, i;
 	size_t buflen;
+	unsigned int zone_idx = 0;
+	int ret;
 
 	if (WARN_ON_ONCE(!vblk->zone_sectors))
 		return -EOPNOTSUPP;
 
-	report = virtblk_alloc_report_buffer(vblk, nr_zones,
-					     zone_sectors, &buflen);
+	report = virtblk_alloc_report_buffer(vblk, nr_zones, &buflen);
 	if (!report)
 		return -ENOMEM;
 
+	mutex_lock(&vblk->vdev_mutex);
+
+	if (!vblk->vdev) {
+		ret = -ENXIO;
+		goto fail_report;
+	}
+
 	while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) {
 		memset(report, 0, buflen);
 
 		ret = virtblk_submit_zone_report(vblk, (char *)report,
 						 buflen, sector);
-		if (ret) {
-			if (ret > 0)
-				ret = -EIO;
-			goto out_free;
-		}
-		nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones);
+		if (ret)
+			goto fail_report;
+
+		nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones),
+			   nr_zones);
 		if (!nz)
 			break;
 
 		for (i = 0; i < nz && zone_idx < nr_zones; i++) {
 			ret = virtblk_parse_zone(vblk, &report->zones[i],
-						 zone_idx, zone_sectors, cb, data);
+						 zone_idx, cb, data);
 			if (ret)
-				goto out_free;
-			sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors;
+				goto fail_report;
+
+			sector = virtio64_to_cpu(vblk->vdev,
+						 report->zones[i].z_start) +
+				 vblk->zone_sectors;
 			zone_idx++;
 		}
 	}
@@ -682,7 +748,8 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
 		ret = zone_idx;
 	else
 		ret = -EINVAL;
-out_free:
+fail_report:
+	mutex_unlock(&vblk->vdev_mutex);
 	kvfree(report);
 	return ret;
 }
@@ -691,20 +758,28 @@ static void virtblk_revalidate_zones(struct virtio_blk *vblk)
 {
 	u8 model;
 
-	if (!vblk->zone_sectors)
-		return;
-
 	virtio_cread(vblk->vdev, struct virtio_blk_config,
 		     zoned.model, &model);
-	if (!blk_revalidate_disk_zones(vblk->disk, NULL))
-		set_capacity_and_notify(vblk->disk, 0);
+	switch (model) {
+	default:
+		dev_err(&vblk->vdev->dev, "unknown zone model %d\n", model);
+		fallthrough;
+	case VIRTIO_BLK_Z_NONE:
+	case VIRTIO_BLK_Z_HA:
+		disk_set_zoned(vblk->disk, BLK_ZONED_NONE);
+		return;
+	case VIRTIO_BLK_Z_HM:
+		WARN_ON_ONCE(!vblk->zone_sectors);
+		if (!blk_revalidate_disk_zones(vblk->disk, NULL))
+			set_capacity_and_notify(vblk->disk, 0);
+	}
 }
 
 static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 				       struct virtio_blk *vblk,
 				       struct request_queue *q)
 {
-	u32 v;
+	u32 v, wg;
 	u8 model;
 	int ret;
 
@@ -713,16 +788,11 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 
 	switch (model) {
 	case VIRTIO_BLK_Z_NONE:
+	case VIRTIO_BLK_Z_HA:
+		/* Present the host-aware device as non-zoned */
 		return 0;
 	case VIRTIO_BLK_Z_HM:
 		break;
-	case VIRTIO_BLK_Z_HA:
-		/*
-		 * Present the host-aware device as a regular drive.
-		 * TODO It is possible to add an option to make it appear
-		 * in the system as a zoned drive.
-		 */
-		return 0;
 	default:
 		dev_err(&vdev->dev, "unsupported zone model %d\n", model);
 		return -EINVAL;
@@ -735,32 +805,31 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 
 	virtio_cread(vdev, struct virtio_blk_config,
 		     zoned.max_open_zones, &v);
-	disk_set_max_open_zones(vblk->disk, le32_to_cpu(v));
-
-	dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v));
+	disk_set_max_open_zones(vblk->disk, v);
+	dev_dbg(&vdev->dev, "max open zones = %u\n", v);
 
 	virtio_cread(vdev, struct virtio_blk_config,
 		     zoned.max_active_zones, &v);
-	disk_set_max_active_zones(vblk->disk, le32_to_cpu(v));
-	dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v));
+	disk_set_max_active_zones(vblk->disk, v);
+	dev_dbg(&vdev->dev, "max active zones = %u\n", v);
 
 	virtio_cread(vdev, struct virtio_blk_config,
-		     zoned.write_granularity, &v);
-	if (!v) {
+		     zoned.write_granularity, &wg);
+	if (!wg) {
 		dev_warn(&vdev->dev, "zero write granularity reported\n");
 		return -ENODEV;
 	}
-	blk_queue_physical_block_size(q, le32_to_cpu(v));
-	blk_queue_io_min(q, le32_to_cpu(v));
+	blk_queue_physical_block_size(q, wg);
+	blk_queue_io_min(q, wg);
 
-	dev_dbg(&vdev->dev, "write granularity = %u\n", le32_to_cpu(v));
+	dev_dbg(&vdev->dev, "write granularity = %u\n", wg);
 
 	/*
 	 * virtio ZBD specification doesn't require zones to be a power of
 	 * two sectors in size, but the code in this driver expects that.
 	 */
-	virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, &v);
-	vblk->zone_sectors = le32_to_cpu(v);
+	virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors,
+		     &vblk->zone_sectors);
 	if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) {
 		dev_err(&vdev->dev,
 			"zoned device with non power of two zone size %u\n",
@@ -783,8 +852,15 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 			dev_warn(&vdev->dev, "zero max_append_sectors reported\n");
 			return -ENODEV;
 		}
-		blk_queue_max_zone_append_sectors(q, le32_to_cpu(v));
-		dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v));
+		if ((v << SECTOR_SHIFT) < wg) {
+			dev_err(&vdev->dev,
+				"write granularity %u exceeds max_append_sectors %u limit\n",
+				wg, v);
+			return -ENODEV;
+		}
+
+		blk_queue_max_zone_append_sectors(q, v);
+		dev_dbg(&vdev->dev, "max append sectors = %u\n", v);
 	}
 
 	return ret;
@@ -794,6 +870,7 @@ static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
 {
 	return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED);
 }
+
 #else
 
 /*
@@ -801,9 +878,11 @@ static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
  * We only need to define a few symbols to avoid compilation errors.
  */
 #define virtblk_report_zones       NULL
+
 static inline void virtblk_revalidate_zones(struct virtio_blk *vblk)
 {
 }
+
 static inline int virtblk_probe_zoned_device(struct virtio_device *vdev,
 			struct virtio_blk *vblk, struct request_queue *q)
 {
@@ -831,7 +910,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
 		return PTR_ERR(req);
 
 	vbr = blk_mq_rq_to_pdu(req);
-	vbr->in_hdr_len = sizeof(vbr->status);
+	vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
 	vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
 	vbr->out_hdr.sector = 0;
 
@@ -840,7 +919,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
 		goto out;
 
 	blk_execute_rq(req, false);
-	err = blk_status_to_errno(virtblk_result(vbr->status));
+	err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
 out:
 	blk_mq_free_request(req);
 	return err;
@@ -1504,9 +1583,6 @@ static int virtblk_probe(struct virtio_device *vdev)
 			goto out_cleanup_disk;
 	}
 
-	dev_info(&vdev->dev, "blk config size: %zu\n",
-		sizeof(struct virtio_blk_config));
-
 	err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
 	if (err)
 		goto out_cleanup_disk;
diff --git a/include/uapi/linux/virtio_blk.h b/include/uapi/linux/virtio_blk.h
index 5af2a0300bb9..3744e4da1b2a 100644
--- a/include/uapi/linux/virtio_blk.h
+++ b/include/uapi/linux/virtio_blk.h
@@ -140,11 +140,11 @@ struct virtio_blk_config {
 
 	/* Zoned block device characteristics (if VIRTIO_BLK_F_ZONED) */
 	struct virtio_blk_zoned_characteristics {
-		__le32 zone_sectors;
-		__le32 max_open_zones;
-		__le32 max_active_zones;
-		__le32 max_append_sectors;
-		__le32 write_granularity;
+		__virtio32 zone_sectors;
+		__virtio32 max_open_zones;
+		__virtio32 max_active_zones;
+		__virtio32 max_append_sectors;
+		__virtio32 write_granularity;
 		__u8 model;
 		__u8 unused2[3];
 	} zoned;
@@ -241,11 +241,11 @@ struct virtio_blk_outhdr {
  */
 struct virtio_blk_zone_descriptor {
 	/* Zone capacity */
-	__le64 z_cap;
+	__virtio64 z_cap;
 	/* The starting sector of the zone */
-	__le64 z_start;
+	__virtio64 z_start;
 	/* Zone write pointer position in sectors */
-	__le64 z_wp;
+	__virtio64 z_wp;
 	/* Zone type */
 	__u8 z_type;
 	/* Zone state */
@@ -254,7 +254,7 @@ struct virtio_blk_zone_descriptor {
 };
 
 struct virtio_blk_zone_report {
-	__le64 nr_zones;
+	__virtio64 nr_zones;
 	__u8 reserved[56];
 	struct virtio_blk_zone_descriptor zones[];
 };
-- 
2.34.1


---------------------------------------------------------------------
To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 2/2] virtio-blk: fix ZBD probe in kernels without ZBD support
  2023-03-30 21:49 ` [virtio-dev] " Dmitry Fomichev
@ 2023-03-30 21:49   ` Dmitry Fomichev
  -1 siblings, 0 replies; 15+ messages in thread
From: Dmitry Fomichev @ 2023-03-30 21:49 UTC (permalink / raw)
  To: Jens Axboe, linux-block, Michael S. Tsirkin, Damien Le Moal,
	Stefan Hajnoczi, Hannes Reinecke, Sam Li
  Cc: virtio-dev, virtualization, Dmitry Fomichev

When the kernel is built without support for zoned block devices,
virtio-blk probe needs to error out any host-managed device scans
to prevent such devices from appearing in the system as non-zoned.
The current virtio-blk code simply bypasses all ZBD checks if
CONFIG_BLK_DEV_ZONED is not defined and this leads to host-managed
block devices being presented as non-zoned in the OS. This is one of
the main problems this patch series is aimed to fix.

In this patch, make VIRTIO_BLK_F_ZONED feature defined even when
CONFIG_BLK_DEV_ZONED is not. This change makes the code compliant with
the voted revision of virtio-blk ZBD spec. Modify the probe code to
look at the situation when VIRTIO_BLK_F_ZONED is negotiated in a kernel
that is built without ZBD support. In this case, the code checks
the zoned model of the device and fails the probe is the device
is host-managed.

The patch also adds the comment to clarify that the call to perform
the zoned device probe is correctly placed after virtio_device ready().

Fixes: 95bfec41bd3d ("virtio-blk: add support for zoned block devices")
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
---
 drivers/block/virtio_blk.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 4f0dbbb3d4a5..2b918e28acaa 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -866,16 +866,12 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 	return ret;
 }
 
-static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
-{
-	return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED);
-}
-
 #else
 
 /*
  * Zoned block device support is not configured in this kernel.
- * We only need to define a few symbols to avoid compilation errors.
+ * Host-managed zoned devices can't be supported, but others are
+ * good to go as regular block devices.
  */
 #define virtblk_report_zones       NULL
 
@@ -886,12 +882,16 @@ static inline void virtblk_revalidate_zones(struct virtio_blk *vblk)
 static inline int virtblk_probe_zoned_device(struct virtio_device *vdev,
 			struct virtio_blk *vblk, struct request_queue *q)
 {
-	return -EOPNOTSUPP;
-}
+	u8 model;
 
-static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
-{
-	return false;
+	virtio_cread(vdev, struct virtio_blk_config, zoned.model, &model);
+	if (model == VIRTIO_BLK_Z_HM) {
+		dev_err(&vdev->dev,
+			"virtio_blk: zoned devices are not supported");
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
 }
 #endif /* CONFIG_BLK_DEV_ZONED */
 
@@ -1577,7 +1577,11 @@ static int virtblk_probe(struct virtio_device *vdev)
 	virtblk_update_capacity(vblk, false);
 	virtio_device_ready(vdev);
 
-	if (virtblk_has_zoned_feature(vdev)) {
+	/*
+	 * All steps that follow use the VQs therefore they need to be
+	 * placed after the virtio_device_ready() call above.
+	 */
+	if (virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED)) {
 		err = virtblk_probe_zoned_device(vdev, vblk, q);
 		if (err)
 			goto out_cleanup_disk;
@@ -1683,10 +1687,7 @@ static unsigned int features[] = {
 	VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
 	VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
 	VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,
-	VIRTIO_BLK_F_SECURE_ERASE,
-#ifdef CONFIG_BLK_DEV_ZONED
-	VIRTIO_BLK_F_ZONED,
-#endif /* CONFIG_BLK_DEV_ZONED */
+	VIRTIO_BLK_F_SECURE_ERASE, VIRTIO_BLK_F_ZONED,
 };
 
 static struct virtio_driver virtio_blk = {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [virtio-dev] [PATCH v2 2/2] virtio-blk: fix ZBD probe in kernels without ZBD support
@ 2023-03-30 21:49   ` Dmitry Fomichev
  0 siblings, 0 replies; 15+ messages in thread
From: Dmitry Fomichev @ 2023-03-30 21:49 UTC (permalink / raw)
  To: Jens Axboe, linux-block, Michael S. Tsirkin, Damien Le Moal,
	Stefan Hajnoczi, Hannes Reinecke, Sam Li
  Cc: virtio-dev, virtualization, Dmitry Fomichev

When the kernel is built without support for zoned block devices,
virtio-blk probe needs to error out any host-managed device scans
to prevent such devices from appearing in the system as non-zoned.
The current virtio-blk code simply bypasses all ZBD checks if
CONFIG_BLK_DEV_ZONED is not defined and this leads to host-managed
block devices being presented as non-zoned in the OS. This is one of
the main problems this patch series is aimed to fix.

In this patch, make VIRTIO_BLK_F_ZONED feature defined even when
CONFIG_BLK_DEV_ZONED is not. This change makes the code compliant with
the voted revision of virtio-blk ZBD spec. Modify the probe code to
look at the situation when VIRTIO_BLK_F_ZONED is negotiated in a kernel
that is built without ZBD support. In this case, the code checks
the zoned model of the device and fails the probe is the device
is host-managed.

The patch also adds the comment to clarify that the call to perform
the zoned device probe is correctly placed after virtio_device ready().

Fixes: 95bfec41bd3d ("virtio-blk: add support for zoned block devices")
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
---
 drivers/block/virtio_blk.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 4f0dbbb3d4a5..2b918e28acaa 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -866,16 +866,12 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
 	return ret;
 }
 
-static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
-{
-	return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED);
-}
-
 #else
 
 /*
  * Zoned block device support is not configured in this kernel.
- * We only need to define a few symbols to avoid compilation errors.
+ * Host-managed zoned devices can't be supported, but others are
+ * good to go as regular block devices.
  */
 #define virtblk_report_zones       NULL
 
@@ -886,12 +882,16 @@ static inline void virtblk_revalidate_zones(struct virtio_blk *vblk)
 static inline int virtblk_probe_zoned_device(struct virtio_device *vdev,
 			struct virtio_blk *vblk, struct request_queue *q)
 {
-	return -EOPNOTSUPP;
-}
+	u8 model;
 
-static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
-{
-	return false;
+	virtio_cread(vdev, struct virtio_blk_config, zoned.model, &model);
+	if (model == VIRTIO_BLK_Z_HM) {
+		dev_err(&vdev->dev,
+			"virtio_blk: zoned devices are not supported");
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
 }
 #endif /* CONFIG_BLK_DEV_ZONED */
 
@@ -1577,7 +1577,11 @@ static int virtblk_probe(struct virtio_device *vdev)
 	virtblk_update_capacity(vblk, false);
 	virtio_device_ready(vdev);
 
-	if (virtblk_has_zoned_feature(vdev)) {
+	/*
+	 * All steps that follow use the VQs therefore they need to be
+	 * placed after the virtio_device_ready() call above.
+	 */
+	if (virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED)) {
 		err = virtblk_probe_zoned_device(vdev, vblk, q);
 		if (err)
 			goto out_cleanup_disk;
@@ -1683,10 +1687,7 @@ static unsigned int features[] = {
 	VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
 	VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
 	VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,
-	VIRTIO_BLK_F_SECURE_ERASE,
-#ifdef CONFIG_BLK_DEV_ZONED
-	VIRTIO_BLK_F_ZONED,
-#endif /* CONFIG_BLK_DEV_ZONED */
+	VIRTIO_BLK_F_SECURE_ERASE, VIRTIO_BLK_F_ZONED,
 };
 
 static struct virtio_driver virtio_blk = {
-- 
2.34.1


---------------------------------------------------------------------
To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
@ 2023-03-31 14:38 kernel test robot
  0 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2023-03-31 14:38 UTC (permalink / raw)
  To: oe-kbuild; +Cc: lkp, Dan Carpenter

BCC: lkp@intel.com
CC: oe-kbuild-all@lists.linux.dev
In-Reply-To: <20230330214953.1088216-2-dmitry.fomichev@wdc.com>
References: <20230330214953.1088216-2-dmitry.fomichev@wdc.com>
TO: Dmitry Fomichev <dmitry.fomichev@wdc.com>
TO: Jens Axboe <axboe@kernel.dk>
TO: linux-block@vger.kernel.org
TO: "Michael S. Tsirkin" <mst@redhat.com>
TO: Damien Le Moal <damien.lemoal@opensource.wdc.com>
TO: Stefan Hajnoczi <stefanha@gmail.com>
TO: Hannes Reinecke <hare@suse.de>
TO: Sam Li <faithilikerun@gmail.com>
CC: virtio-dev@lists.oasis-open.org
CC: virtualization@lists.linux-foundation.org
CC: Dmitry Fomichev <dmitry.fomichev@wdc.com>

Hi Dmitry,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on axboe-block/for-next]
[also build test WARNING on linus/master v6.3-rc4 next-20230331]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Dmitry-Fomichev/virtio-blk-migrate-to-the-latest-patchset-version/20230331-055052
base:   https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git for-next
patch link:    https://lore.kernel.org/r/20230330214953.1088216-2-dmitry.fomichev%40wdc.com
patch subject: [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
:::::: branch date: 17 hours ago
:::::: commit date: 17 hours ago
config: parisc-randconfig-m041-20230329 (https://download.01.org/0day-ci/archive/20230331/202303312211.z4EdyM5A-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 12.1.0

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <error27@gmail.com>
| Link: https://lore.kernel.org/r/202303312211.z4EdyM5A-lkp@intel.com/

New smatch warnings:
drivers/block/virtio_blk.c:806 virtblk_probe_zoned_device() error: uninitialized symbol 'virtio_cread_v'.

Old smatch warnings:
drivers/block/virtio_blk.c:811 virtblk_probe_zoned_device() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:816 virtblk_probe_zoned_device() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:831 virtblk_probe_zoned_device() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:849 virtblk_probe_zoned_device() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:943 virtblk_getgeo() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1018 virtblk_update_capacity() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1067 init_vq() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1342 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1430 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1438 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1468 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1474 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1481 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1484 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1488 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1493 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1512 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1527 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.
drivers/block/virtio_blk.c:1542 virtblk_probe() error: uninitialized symbol 'virtio_cread_v'.

vim +/virtio_cread_v +806 drivers/block/virtio_blk.c

95bfec41bd3d39 Dmitry Fomichev 2022-10-15  777  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  778  static int virtblk_probe_zoned_device(struct virtio_device *vdev,
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  779  				       struct virtio_blk *vblk,
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  780  				       struct request_queue *q)
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  781  {
3e640fa381af05 Dmitry Fomichev 2023-03-30  782  	u32 v, wg;
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  783  	u8 model;
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  784  	int ret;
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  785  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  786  	virtio_cread(vdev, struct virtio_blk_config,
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  787  		     zoned.model, &model);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  788  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  789  	switch (model) {
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  790  	case VIRTIO_BLK_Z_NONE:
3e640fa381af05 Dmitry Fomichev 2023-03-30  791  	case VIRTIO_BLK_Z_HA:
3e640fa381af05 Dmitry Fomichev 2023-03-30  792  		/* Present the host-aware device as non-zoned */
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  793  		return 0;
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  794  	case VIRTIO_BLK_Z_HM:
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  795  		break;
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  796  	default:
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  797  		dev_err(&vdev->dev, "unsupported zone model %d\n", model);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  798  		return -EINVAL;
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  799  	}
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  800  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  801  	dev_dbg(&vdev->dev, "probing host-managed zoned device\n");
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  802  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  803  	disk_set_zoned(vblk->disk, BLK_ZONED_HM);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  804  	blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  805  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15 @806  	virtio_cread(vdev, struct virtio_blk_config,
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  807  		     zoned.max_open_zones, &v);
3e640fa381af05 Dmitry Fomichev 2023-03-30  808  	disk_set_max_open_zones(vblk->disk, v);
3e640fa381af05 Dmitry Fomichev 2023-03-30  809  	dev_dbg(&vdev->dev, "max open zones = %u\n", v);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  810  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  811  	virtio_cread(vdev, struct virtio_blk_config,
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  812  		     zoned.max_active_zones, &v);
3e640fa381af05 Dmitry Fomichev 2023-03-30  813  	disk_set_max_active_zones(vblk->disk, v);
3e640fa381af05 Dmitry Fomichev 2023-03-30  814  	dev_dbg(&vdev->dev, "max active zones = %u\n", v);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  815  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  816  	virtio_cread(vdev, struct virtio_blk_config,
3e640fa381af05 Dmitry Fomichev 2023-03-30  817  		     zoned.write_granularity, &wg);
3e640fa381af05 Dmitry Fomichev 2023-03-30  818  	if (!wg) {
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  819  		dev_warn(&vdev->dev, "zero write granularity reported\n");
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  820  		return -ENODEV;
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  821  	}
3e640fa381af05 Dmitry Fomichev 2023-03-30  822  	blk_queue_physical_block_size(q, wg);
3e640fa381af05 Dmitry Fomichev 2023-03-30  823  	blk_queue_io_min(q, wg);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  824  
3e640fa381af05 Dmitry Fomichev 2023-03-30  825  	dev_dbg(&vdev->dev, "write granularity = %u\n", wg);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  826  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  827  	/*
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  828  	 * virtio ZBD specification doesn't require zones to be a power of
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  829  	 * two sectors in size, but the code in this driver expects that.
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  830  	 */
3e640fa381af05 Dmitry Fomichev 2023-03-30  831  	virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors,
3e640fa381af05 Dmitry Fomichev 2023-03-30  832  		     &vblk->zone_sectors);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  833  	if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) {
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  834  		dev_err(&vdev->dev,
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  835  			"zoned device with non power of two zone size %u\n",
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  836  			vblk->zone_sectors);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  837  		return -ENODEV;
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  838  	}
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  839  	dev_dbg(&vdev->dev, "zone sectors = %u\n", vblk->zone_sectors);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  840  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  841  	if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  842  		dev_warn(&vblk->vdev->dev,
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  843  			 "ignoring negotiated F_DISCARD for zoned device\n");
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  844  		blk_queue_max_discard_sectors(q, 0);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  845  	}
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  846  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  847  	ret = blk_revalidate_disk_zones(vblk->disk, NULL);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  848  	if (!ret) {
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  849  		virtio_cread(vdev, struct virtio_blk_config,
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  850  			     zoned.max_append_sectors, &v);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  851  		if (!v) {
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  852  			dev_warn(&vdev->dev, "zero max_append_sectors reported\n");
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  853  			return -ENODEV;
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  854  		}
3e640fa381af05 Dmitry Fomichev 2023-03-30  855  		if ((v << SECTOR_SHIFT) < wg) {
3e640fa381af05 Dmitry Fomichev 2023-03-30  856  			dev_err(&vdev->dev,
3e640fa381af05 Dmitry Fomichev 2023-03-30  857  				"write granularity %u exceeds max_append_sectors %u limit\n",
3e640fa381af05 Dmitry Fomichev 2023-03-30  858  				wg, v);
3e640fa381af05 Dmitry Fomichev 2023-03-30  859  			return -ENODEV;
3e640fa381af05 Dmitry Fomichev 2023-03-30  860  		}
3e640fa381af05 Dmitry Fomichev 2023-03-30  861  
3e640fa381af05 Dmitry Fomichev 2023-03-30  862  		blk_queue_max_zone_append_sectors(q, v);
3e640fa381af05 Dmitry Fomichev 2023-03-30  863  		dev_dbg(&vdev->dev, "max append sectors = %u\n", v);
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  864  	}
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  865  
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  866  	return ret;
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  867  }
95bfec41bd3d39 Dmitry Fomichev 2022-10-15  868  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
  2023-03-30 21:49   ` [virtio-dev] " Dmitry Fomichev
@ 2023-04-03 15:15     ` Christoph Hellwig
  -1 siblings, 0 replies; 15+ messages in thread
From: Christoph Hellwig @ 2023-04-03 15:15 UTC (permalink / raw)
  To: Dmitry Fomichev
  Cc: Jens Axboe, linux-block, Michael S. Tsirkin, Damien Le Moal,
	Stefan Hajnoczi, Hannes Reinecke, Sam Li, virtio-dev,
	virtualization

What is "migrate to the latest patchset version" even supposed to mean?

I don't think that belongs into a kernel commit description.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
@ 2023-04-03 15:15     ` Christoph Hellwig
  0 siblings, 0 replies; 15+ messages in thread
From: Christoph Hellwig @ 2023-04-03 15:15 UTC (permalink / raw)
  To: Dmitry Fomichev
  Cc: Jens Axboe, virtio-dev, Michael S. Tsirkin, Damien Le Moal,
	Sam Li, virtualization, linux-block

What is "migrate to the latest patchset version" even supposed to mean?

I don't think that belongs into a kernel commit description.
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
  2023-04-03 15:15     ` Christoph Hellwig
  (?)
@ 2023-04-03 17:35       ` Michael S. Tsirkin
  -1 siblings, 0 replies; 15+ messages in thread
From: Michael S. Tsirkin @ 2023-04-03 17:35 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Dmitry Fomichev, Jens Axboe, virtio-dev, Damien Le Moal, Sam Li,
	virtualization, linux-block

On Mon, Apr 03, 2023 at 08:15:26AM -0700, Christoph Hellwig wrote:
> What is "migrate to the latest patchset version" even supposed to mean?
> 
> I don't think that belongs into a kernel commit description.

I think this should be something like "update to latest interface version".

-- 
MST


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [virtio-dev] Re: [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
@ 2023-04-03 17:35       ` Michael S. Tsirkin
  0 siblings, 0 replies; 15+ messages in thread
From: Michael S. Tsirkin @ 2023-04-03 17:35 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Dmitry Fomichev, Jens Axboe, virtio-dev, Damien Le Moal, Sam Li,
	virtualization, linux-block

On Mon, Apr 03, 2023 at 08:15:26AM -0700, Christoph Hellwig wrote:
> What is "migrate to the latest patchset version" even supposed to mean?
> 
> I don't think that belongs into a kernel commit description.

I think this should be something like "update to latest interface version".

-- 
MST


---------------------------------------------------------------------
To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
@ 2023-04-03 17:35       ` Michael S. Tsirkin
  0 siblings, 0 replies; 15+ messages in thread
From: Michael S. Tsirkin @ 2023-04-03 17:35 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Jens Axboe, virtio-dev, Dmitry Fomichev, Damien Le Moal, Sam Li,
	virtualization, linux-block

On Mon, Apr 03, 2023 at 08:15:26AM -0700, Christoph Hellwig wrote:
> What is "migrate to the latest patchset version" even supposed to mean?
> 
> I don't think that belongs into a kernel commit description.

I think this should be something like "update to latest interface version".

-- 
MST

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [virtio-dev] [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
  2023-03-30 21:49   ` [virtio-dev] " Dmitry Fomichev
  (?)
@ 2023-04-03 17:53     ` Michael S. Tsirkin
  -1 siblings, 0 replies; 15+ messages in thread
From: Michael S. Tsirkin @ 2023-04-03 17:53 UTC (permalink / raw)
  To: Dmitry Fomichev
  Cc: Jens Axboe, linux-block, Damien Le Moal, Stefan Hajnoczi,
	Hannes Reinecke, Sam Li, virtio-dev, virtualization

On Thu, Mar 30, 2023 at 05:49:52PM -0400, Dmitry Fomichev wrote:
> The merged patch series to support zoned block devices in virtio-blk
> is not the most up to date version. The merged patch can be found at
> 
> https://lore.kernel.org/linux-block/20221016034127.330942-3-dmitry.fomichev@wdc.com/
> 
> , but the latest and reviewed version is
> 
> https://lore.kernel.org/linux-block/20221110053952.3378990-3-dmitry.fomichev@wdc.com/

What happened here is that it was not sent to correct people or lists.

v2 happened to draw my attention by chance, I missed the
interface change and I did not see later ones and merged v2.

To: Jens Axboe <axboe@kernel.dk>,
	linux-block@vger.kernel.org,
	Damien Le Moal <damien.lemoal@opensource.wdc.com>,
	Stefan Hajnoczi <stefanha@gmail.com>,
	Hannes Reinecke <hare@suse.de>, Sam Li <faithilikerun@gmail.com>
Cc: virtio-dev@lists.oasis-open.org,
	Dmitry Fomichev <dmitry.fomichev@wdc.com>

while:

$ ./scripts/get_maintainer.pl -f drivers/block/virtio_blk.c
"Michael S. Tsirkin" <mst@redhat.com> (maintainer:VIRTIO CORE AND NET DRIVERS)
Jason Wang <jasowang@redhat.com> (maintainer:VIRTIO CORE AND NET DRIVERS)
Paolo Bonzini <pbonzini@redhat.com> (reviewer:VIRTIO BLOCK AND SCSI DRIVERS)
Stefan Hajnoczi <stefanha@redhat.com> (reviewer:VIRTIO BLOCK AND SCSI DRIVERS)
Jens Axboe <axboe@kernel.dk> (maintainer:BLOCK LAYER)
virtualization@lists.linux-foundation.org (open list:VIRTIO CORE AND NET DRIVERS)
linux-block@vger.kernel.org (open list:BLOCK LAYER)
linux-kernel@vger.kernel.org (open list)




> The differences between the two are mostly cleanups, but there is one
> change that is very important in terms of compatibility with the
> approved virtio-zbd specification.
> 
> Before it was approved, the OASIS virtio spec had a change in
> VIRTIO_BLK_T_ZONE_APPEND request layout that is not reflected in the
> current virtio-blk driver code. In the running code, the status is
> the first byte of the in-header that is followed by some pad bytes
> and the u64 that carries the sector at which the data has been written
> to the zone back to the driver, aka the append sector.
> 
> This layout turned out to be problematic for implementing in QEMU and
> the request status byte has been eventually made the last byte of the
> in-header. The current code doesn't expect that and this causes the
> append sector value always come as zero to the block layer. This needs
> to be fixed ASAP.
> 
> Fixes: 95bfec41bd3d ("virtio-blk: add support for zoned block devices")
> Cc: stable@vger.kernel.org
> Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
> ---
>  drivers/block/virtio_blk.c      | 238 +++++++++++++++++++++-----------
>  include/uapi/linux/virtio_blk.h |  18 +--
>  2 files changed, 166 insertions(+), 90 deletions(-)
> 
> diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
> index 2723eede6f21..4f0dbbb3d4a5 100644
> --- a/drivers/block/virtio_blk.c
> +++ b/drivers/block/virtio_blk.c
> @@ -96,16 +96,14 @@ struct virtblk_req {
>  
>  		/*
>  		 * The zone append command has an extended in header.
> -		 * The status field in zone_append_in_hdr must have
> -		 * the same offset in virtblk_req as the non-zoned
> -		 * status field above.
> +		 * The status field in zone_append_in_hdr must always
> +		 * be the last byte.
>  		 */
>  		struct {
> +			__virtio64 sector;
>  			u8 status;
> -			u8 reserved[7];
> -			__le64 append_sector;
> -		} zone_append_in_hdr;
> -	};
> +		} zone_append;
> +	} in_hdr;
>  
>  	size_t in_hdr_len;
>  
> @@ -154,7 +152,7 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)
>  			sgs[num_out + num_in++] = vbr->sg_table.sgl;
>  	}
>  
> -	sg_init_one(&in_hdr, &vbr->status, vbr->in_hdr_len);
> +	sg_init_one(&in_hdr, &vbr->in_hdr.status, vbr->in_hdr_len);
>  	sgs[num_out + num_in++] = &in_hdr;
>  
>  	return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
> @@ -242,11 +240,14 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  				      struct request *req,
>  				      struct virtblk_req *vbr)
>  {
> -	size_t in_hdr_len = sizeof(vbr->status);
> +	size_t in_hdr_len = sizeof(vbr->in_hdr.status);
>  	bool unmap = false;
>  	u32 type;
>  	u64 sector = 0;
>  
> +	if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) && op_is_zone_mgmt(req_op(req)))
> +		return BLK_STS_NOTSUPP;
> +
>  	/* Set fields for all request types */
>  	vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
>  
> @@ -287,7 +288,7 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  	case REQ_OP_ZONE_APPEND:
>  		type = VIRTIO_BLK_T_ZONE_APPEND;
>  		sector = blk_rq_pos(req);
> -		in_hdr_len = sizeof(vbr->zone_append_in_hdr);
> +		in_hdr_len = sizeof(vbr->in_hdr.zone_append);
>  		break;
>  	case REQ_OP_ZONE_RESET:
>  		type = VIRTIO_BLK_T_ZONE_RESET;
> @@ -297,7 +298,10 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  		type = VIRTIO_BLK_T_ZONE_RESET_ALL;
>  		break;
>  	case REQ_OP_DRV_IN:
> -		/* Out header already filled in, nothing to do */
> +		/*
> +		 * Out header has already been prepared by the caller (virtblk_get_id()
> +		 * or virtblk_submit_zone_report()), nothing to do here.
> +		 */
>  		return 0;
>  	default:
>  		WARN_ON_ONCE(1);
> @@ -318,16 +322,28 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  	return 0;
>  }
>  
> +/*
> + * The status byte is always the last byte of the virtblk request
> + * in-header. This helper fetches its value for all in-header formats
> + * that are currently defined.
> + */
> +static inline u8 virtblk_vbr_status(struct virtblk_req *vbr)
> +{
> +	return *((u8 *)&vbr->in_hdr + vbr->in_hdr_len - 1);
> +}
> +
>  static inline void virtblk_request_done(struct request *req)
>  {
>  	struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
> -	blk_status_t status = virtblk_result(vbr->status);
> +	blk_status_t status = virtblk_result(virtblk_vbr_status(vbr));
> +	struct virtio_blk *vblk = req->mq_hctx->queue->queuedata;
>  
>  	virtblk_unmap_data(req, vbr);
>  	virtblk_cleanup_cmd(req);
>  
>  	if (req_op(req) == REQ_OP_ZONE_APPEND)
> -		req->__sector = le64_to_cpu(vbr->zone_append_in_hdr.append_sector);
> +		req->__sector = virtio64_to_cpu(vblk->vdev,
> +						vbr->in_hdr.zone_append.sector);
>  
>  	blk_mq_end_request(req, status);
>  }
> @@ -355,7 +371,7 @@ static int virtblk_handle_req(struct virtio_blk_vq *vq,
>  
>  		if (likely(!blk_should_fake_timeout(req->q)) &&
>  		    !blk_mq_complete_request_remote(req) &&
> -		    !blk_mq_add_to_batch(req, iob, vbr->status,
> +		    !blk_mq_add_to_batch(req, iob, virtblk_vbr_status(vbr),
>  					 virtblk_complete_batch))
>  			virtblk_request_done(req);
>  		req_done++;
> @@ -550,7 +566,6 @@ static void virtio_queue_rqs(struct request **rqlist)
>  #ifdef CONFIG_BLK_DEV_ZONED
>  static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
>  					  unsigned int nr_zones,
> -					  unsigned int zone_sectors,
>  					  size_t *buflen)
>  {
>  	struct request_queue *q = vblk->disk->queue;
> @@ -558,7 +573,7 @@ static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
>  	void *buf;
>  
>  	nr_zones = min_t(unsigned int, nr_zones,
> -			 get_capacity(vblk->disk) >> ilog2(zone_sectors));
> +			 get_capacity(vblk->disk) >> ilog2(vblk->zone_sectors));
>  
>  	bufsize = sizeof(struct virtio_blk_zone_report) +
>  		nr_zones * sizeof(struct virtio_blk_zone_descriptor);
> @@ -592,7 +607,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
>  		return PTR_ERR(req);
>  
>  	vbr = blk_mq_rq_to_pdu(req);
> -	vbr->in_hdr_len = sizeof(vbr->status);
> +	vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
>  	vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT);
>  	vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector);
>  
> @@ -601,7 +616,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
>  		goto out;
>  
>  	blk_execute_rq(req, false);
> -	err = blk_status_to_errno(virtblk_result(vbr->status));
> +	err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
>  out:
>  	blk_mq_free_request(req);
>  	return err;
> @@ -609,29 +624,72 @@ 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, unsigned int zone_sectors,
> -			       report_zones_cb cb, void *data)
> +			       unsigned int idx, report_zones_cb cb, void *data)
>  {
>  	struct blk_zone zone = { };
>  
> -	if (entry->z_type != VIRTIO_BLK_ZT_SWR &&
> -	    entry->z_type != VIRTIO_BLK_ZT_SWP &&
> -	    entry->z_type != VIRTIO_BLK_ZT_CONV) {
> -		dev_err(&vblk->vdev->dev, "invalid zone type %#x\n",
> -			entry->z_type);
> -		return -EINVAL;
> +	zone.start = virtio64_to_cpu(vblk->vdev, entry->z_start);
> +	if (zone.start + vblk->zone_sectors <= get_capacity(vblk->disk))
> +		zone.len = vblk->zone_sectors;
> +	else
> +		zone.len = get_capacity(vblk->disk) - zone.start;
> +	zone.capacity = virtio64_to_cpu(vblk->vdev, entry->z_cap);
> +	zone.wp = virtio64_to_cpu(vblk->vdev, entry->z_wp);
> +
> +	switch (entry->z_type) {
> +	case VIRTIO_BLK_ZT_SWR:
> +		zone.type = BLK_ZONE_TYPE_SEQWRITE_REQ;
> +		break;
> +	case VIRTIO_BLK_ZT_SWP:
> +		zone.type = BLK_ZONE_TYPE_SEQWRITE_PREF;
> +		break;
> +	case VIRTIO_BLK_ZT_CONV:
> +		zone.type = BLK_ZONE_TYPE_CONVENTIONAL;
> +		break;
> +	default:
> +		dev_err(&vblk->vdev->dev, "zone %llu: invalid type %#x\n",
> +			zone.start, entry->z_type);
> +		return -EIO;
>  	}
>  
> -	zone.type = entry->z_type;
> -	zone.cond = entry->z_state;
> -	zone.len = zone_sectors;
> -	zone.capacity = le64_to_cpu(entry->z_cap);
> -	zone.start = le64_to_cpu(entry->z_start);
> -	if (zone.cond == BLK_ZONE_COND_FULL)
> +	switch (entry->z_state) {
> +	case VIRTIO_BLK_ZS_EMPTY:
> +		zone.cond = BLK_ZONE_COND_EMPTY;
> +		break;
> +	case VIRTIO_BLK_ZS_CLOSED:
> +		zone.cond = BLK_ZONE_COND_CLOSED;
> +		break;
> +	case VIRTIO_BLK_ZS_FULL:
> +		zone.cond = BLK_ZONE_COND_FULL;
>  		zone.wp = zone.start + zone.len;
> -	else
> -		zone.wp = le64_to_cpu(entry->z_wp);
> +		break;
> +	case VIRTIO_BLK_ZS_EOPEN:
> +		zone.cond = BLK_ZONE_COND_EXP_OPEN;
> +		break;
> +	case VIRTIO_BLK_ZS_IOPEN:
> +		zone.cond = BLK_ZONE_COND_IMP_OPEN;
> +		break;
> +	case VIRTIO_BLK_ZS_NOT_WP:
> +		zone.cond = BLK_ZONE_COND_NOT_WP;
> +		break;
> +	case VIRTIO_BLK_ZS_RDONLY:
> +		zone.cond = BLK_ZONE_COND_READONLY;
> +		zone.wp = ULONG_MAX;
> +		break;
> +	case VIRTIO_BLK_ZS_OFFLINE:
> +		zone.cond = BLK_ZONE_COND_OFFLINE;
> +		zone.wp = ULONG_MAX;
> +		break;
> +	default:
> +		dev_err(&vblk->vdev->dev, "zone %llu: invalid condition %#x\n",
> +			zone.start, entry->z_state);
> +		return -EIO;
> +	}
>  
> +	/*
> +	 * The callback below checks the validity of the reported
> +	 * entry data, no need to further validate it here.
> +	 */
>  	return cb(&zone, idx, data);
>  }
>  
> @@ -641,39 +699,47 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
>  {
>  	struct virtio_blk *vblk = disk->private_data;
>  	struct virtio_blk_zone_report *report;
> -	unsigned int zone_sectors = vblk->zone_sectors;
> -	unsigned int nz, i;
> -	int ret, zone_idx = 0;
> +	unsigned long long nz, i;
>  	size_t buflen;
> +	unsigned int zone_idx = 0;
> +	int ret;
>  
>  	if (WARN_ON_ONCE(!vblk->zone_sectors))
>  		return -EOPNOTSUPP;
>  
> -	report = virtblk_alloc_report_buffer(vblk, nr_zones,
> -					     zone_sectors, &buflen);
> +	report = virtblk_alloc_report_buffer(vblk, nr_zones, &buflen);
>  	if (!report)
>  		return -ENOMEM;
>  
> +	mutex_lock(&vblk->vdev_mutex);
> +
> +	if (!vblk->vdev) {
> +		ret = -ENXIO;
> +		goto fail_report;
> +	}
> +
>  	while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) {
>  		memset(report, 0, buflen);
>  
>  		ret = virtblk_submit_zone_report(vblk, (char *)report,
>  						 buflen, sector);
> -		if (ret) {
> -			if (ret > 0)
> -				ret = -EIO;
> -			goto out_free;
> -		}
> -		nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones);
> +		if (ret)
> +			goto fail_report;
> +
> +		nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones),
> +			   nr_zones);
>  		if (!nz)
>  			break;
>  
>  		for (i = 0; i < nz && zone_idx < nr_zones; i++) {
>  			ret = virtblk_parse_zone(vblk, &report->zones[i],
> -						 zone_idx, zone_sectors, cb, data);
> +						 zone_idx, cb, data);
>  			if (ret)
> -				goto out_free;
> -			sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors;
> +				goto fail_report;
> +
> +			sector = virtio64_to_cpu(vblk->vdev,
> +						 report->zones[i].z_start) +
> +				 vblk->zone_sectors;
>  			zone_idx++;
>  		}
>  	}
> @@ -682,7 +748,8 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
>  		ret = zone_idx;
>  	else
>  		ret = -EINVAL;
> -out_free:
> +fail_report:
> +	mutex_unlock(&vblk->vdev_mutex);
>  	kvfree(report);
>  	return ret;
>  }
> @@ -691,20 +758,28 @@ static void virtblk_revalidate_zones(struct virtio_blk *vblk)
>  {
>  	u8 model;
>  
> -	if (!vblk->zone_sectors)
> -		return;
> -
>  	virtio_cread(vblk->vdev, struct virtio_blk_config,
>  		     zoned.model, &model);
> -	if (!blk_revalidate_disk_zones(vblk->disk, NULL))
> -		set_capacity_and_notify(vblk->disk, 0);
> +	switch (model) {
> +	default:
> +		dev_err(&vblk->vdev->dev, "unknown zone model %d\n", model);
> +		fallthrough;
> +	case VIRTIO_BLK_Z_NONE:
> +	case VIRTIO_BLK_Z_HA:
> +		disk_set_zoned(vblk->disk, BLK_ZONED_NONE);
> +		return;
> +	case VIRTIO_BLK_Z_HM:
> +		WARN_ON_ONCE(!vblk->zone_sectors);
> +		if (!blk_revalidate_disk_zones(vblk->disk, NULL))
> +			set_capacity_and_notify(vblk->disk, 0);
> +	}
>  }
>  
>  static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  				       struct virtio_blk *vblk,
>  				       struct request_queue *q)
>  {
> -	u32 v;
> +	u32 v, wg;
>  	u8 model;
>  	int ret;
>  
> @@ -713,16 +788,11 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  
>  	switch (model) {
>  	case VIRTIO_BLK_Z_NONE:
> +	case VIRTIO_BLK_Z_HA:
> +		/* Present the host-aware device as non-zoned */
>  		return 0;
>  	case VIRTIO_BLK_Z_HM:
>  		break;
> -	case VIRTIO_BLK_Z_HA:
> -		/*
> -		 * Present the host-aware device as a regular drive.
> -		 * TODO It is possible to add an option to make it appear
> -		 * in the system as a zoned drive.
> -		 */
> -		return 0;
>  	default:
>  		dev_err(&vdev->dev, "unsupported zone model %d\n", model);
>  		return -EINVAL;
> @@ -735,32 +805,31 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  
>  	virtio_cread(vdev, struct virtio_blk_config,
>  		     zoned.max_open_zones, &v);
> -	disk_set_max_open_zones(vblk->disk, le32_to_cpu(v));
> -
> -	dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v));
> +	disk_set_max_open_zones(vblk->disk, v);
> +	dev_dbg(&vdev->dev, "max open zones = %u\n", v);
>  
>  	virtio_cread(vdev, struct virtio_blk_config,
>  		     zoned.max_active_zones, &v);
> -	disk_set_max_active_zones(vblk->disk, le32_to_cpu(v));
> -	dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v));
> +	disk_set_max_active_zones(vblk->disk, v);
> +	dev_dbg(&vdev->dev, "max active zones = %u\n", v);
>  
>  	virtio_cread(vdev, struct virtio_blk_config,
> -		     zoned.write_granularity, &v);
> -	if (!v) {
> +		     zoned.write_granularity, &wg);
> +	if (!wg) {
>  		dev_warn(&vdev->dev, "zero write granularity reported\n");
>  		return -ENODEV;
>  	}
> -	blk_queue_physical_block_size(q, le32_to_cpu(v));
> -	blk_queue_io_min(q, le32_to_cpu(v));
> +	blk_queue_physical_block_size(q, wg);
> +	blk_queue_io_min(q, wg);
>  
> -	dev_dbg(&vdev->dev, "write granularity = %u\n", le32_to_cpu(v));
> +	dev_dbg(&vdev->dev, "write granularity = %u\n", wg);
>  
>  	/*
>  	 * virtio ZBD specification doesn't require zones to be a power of
>  	 * two sectors in size, but the code in this driver expects that.
>  	 */
> -	virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, &v);
> -	vblk->zone_sectors = le32_to_cpu(v);
> +	virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors,
> +		     &vblk->zone_sectors);
>  	if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) {
>  		dev_err(&vdev->dev,
>  			"zoned device with non power of two zone size %u\n",
> @@ -783,8 +852,15 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  			dev_warn(&vdev->dev, "zero max_append_sectors reported\n");
>  			return -ENODEV;
>  		}
> -		blk_queue_max_zone_append_sectors(q, le32_to_cpu(v));
> -		dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v));
> +		if ((v << SECTOR_SHIFT) < wg) {
> +			dev_err(&vdev->dev,
> +				"write granularity %u exceeds max_append_sectors %u limit\n",
> +				wg, v);
> +			return -ENODEV;
> +		}
> +
> +		blk_queue_max_zone_append_sectors(q, v);
> +		dev_dbg(&vdev->dev, "max append sectors = %u\n", v);
>  	}
>  
>  	return ret;
> @@ -794,6 +870,7 @@ static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
>  {
>  	return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED);
>  }
> +
>  #else
>  
>  /*
> @@ -801,9 +878,11 @@ static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
>   * We only need to define a few symbols to avoid compilation errors.
>   */
>  #define virtblk_report_zones       NULL
> +
>  static inline void virtblk_revalidate_zones(struct virtio_blk *vblk)
>  {
>  }
> +
>  static inline int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  			struct virtio_blk *vblk, struct request_queue *q)
>  {
> @@ -831,7 +910,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
>  		return PTR_ERR(req);
>  
>  	vbr = blk_mq_rq_to_pdu(req);
> -	vbr->in_hdr_len = sizeof(vbr->status);
> +	vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
>  	vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
>  	vbr->out_hdr.sector = 0;
>  
> @@ -840,7 +919,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
>  		goto out;
>  
>  	blk_execute_rq(req, false);
> -	err = blk_status_to_errno(virtblk_result(vbr->status));
> +	err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
>  out:
>  	blk_mq_free_request(req);
>  	return err;
> @@ -1504,9 +1583,6 @@ static int virtblk_probe(struct virtio_device *vdev)
>  			goto out_cleanup_disk;
>  	}
>  
> -	dev_info(&vdev->dev, "blk config size: %zu\n",
> -		sizeof(struct virtio_blk_config));
> -
>  	err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
>  	if (err)
>  		goto out_cleanup_disk;
> diff --git a/include/uapi/linux/virtio_blk.h b/include/uapi/linux/virtio_blk.h
> index 5af2a0300bb9..3744e4da1b2a 100644
> --- a/include/uapi/linux/virtio_blk.h
> +++ b/include/uapi/linux/virtio_blk.h
> @@ -140,11 +140,11 @@ struct virtio_blk_config {
>  
>  	/* Zoned block device characteristics (if VIRTIO_BLK_F_ZONED) */
>  	struct virtio_blk_zoned_characteristics {
> -		__le32 zone_sectors;
> -		__le32 max_open_zones;
> -		__le32 max_active_zones;
> -		__le32 max_append_sectors;
> -		__le32 write_granularity;
> +		__virtio32 zone_sectors;
> +		__virtio32 max_open_zones;
> +		__virtio32 max_active_zones;
> +		__virtio32 max_append_sectors;
> +		__virtio32 write_granularity;
>  		__u8 model;
>  		__u8 unused2[3];
>  	} zoned;
> @@ -241,11 +241,11 @@ struct virtio_blk_outhdr {
>   */
>  struct virtio_blk_zone_descriptor {
>  	/* Zone capacity */
> -	__le64 z_cap;
> +	__virtio64 z_cap;
>  	/* The starting sector of the zone */
> -	__le64 z_start;
> +	__virtio64 z_start;
>  	/* Zone write pointer position in sectors */
> -	__le64 z_wp;
> +	__virtio64 z_wp;
>  	/* Zone type */
>  	__u8 z_type;
>  	/* Zone state */
> @@ -254,7 +254,7 @@ struct virtio_blk_zone_descriptor {
>  };
>  
>  struct virtio_blk_zone_report {
> -	__le64 nr_zones;
> +	__virtio64 nr_zones;
>  	__u8 reserved[56];
>  	struct virtio_blk_zone_descriptor zones[];
>  };
> -- 
> 2.34.1
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
> For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org
> 
> 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [virtio-dev] [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
@ 2023-04-03 17:53     ` Michael S. Tsirkin
  0 siblings, 0 replies; 15+ messages in thread
From: Michael S. Tsirkin @ 2023-04-03 17:53 UTC (permalink / raw)
  To: Dmitry Fomichev
  Cc: Jens Axboe, linux-block, Damien Le Moal, Stefan Hajnoczi,
	Hannes Reinecke, Sam Li, virtio-dev, virtualization

On Thu, Mar 30, 2023 at 05:49:52PM -0400, Dmitry Fomichev wrote:
> The merged patch series to support zoned block devices in virtio-blk
> is not the most up to date version. The merged patch can be found at
> 
> https://lore.kernel.org/linux-block/20221016034127.330942-3-dmitry.fomichev@wdc.com/
> 
> , but the latest and reviewed version is
> 
> https://lore.kernel.org/linux-block/20221110053952.3378990-3-dmitry.fomichev@wdc.com/

What happened here is that it was not sent to correct people or lists.

v2 happened to draw my attention by chance, I missed the
interface change and I did not see later ones and merged v2.

To: Jens Axboe <axboe@kernel.dk>,
	linux-block@vger.kernel.org,
	Damien Le Moal <damien.lemoal@opensource.wdc.com>,
	Stefan Hajnoczi <stefanha@gmail.com>,
	Hannes Reinecke <hare@suse.de>, Sam Li <faithilikerun@gmail.com>
Cc: virtio-dev@lists.oasis-open.org,
	Dmitry Fomichev <dmitry.fomichev@wdc.com>

while:

$ ./scripts/get_maintainer.pl -f drivers/block/virtio_blk.c
"Michael S. Tsirkin" <mst@redhat.com> (maintainer:VIRTIO CORE AND NET DRIVERS)
Jason Wang <jasowang@redhat.com> (maintainer:VIRTIO CORE AND NET DRIVERS)
Paolo Bonzini <pbonzini@redhat.com> (reviewer:VIRTIO BLOCK AND SCSI DRIVERS)
Stefan Hajnoczi <stefanha@redhat.com> (reviewer:VIRTIO BLOCK AND SCSI DRIVERS)
Jens Axboe <axboe@kernel.dk> (maintainer:BLOCK LAYER)
virtualization@lists.linux-foundation.org (open list:VIRTIO CORE AND NET DRIVERS)
linux-block@vger.kernel.org (open list:BLOCK LAYER)
linux-kernel@vger.kernel.org (open list)




> The differences between the two are mostly cleanups, but there is one
> change that is very important in terms of compatibility with the
> approved virtio-zbd specification.
> 
> Before it was approved, the OASIS virtio spec had a change in
> VIRTIO_BLK_T_ZONE_APPEND request layout that is not reflected in the
> current virtio-blk driver code. In the running code, the status is
> the first byte of the in-header that is followed by some pad bytes
> and the u64 that carries the sector at which the data has been written
> to the zone back to the driver, aka the append sector.
> 
> This layout turned out to be problematic for implementing in QEMU and
> the request status byte has been eventually made the last byte of the
> in-header. The current code doesn't expect that and this causes the
> append sector value always come as zero to the block layer. This needs
> to be fixed ASAP.
> 
> Fixes: 95bfec41bd3d ("virtio-blk: add support for zoned block devices")
> Cc: stable@vger.kernel.org
> Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
> ---
>  drivers/block/virtio_blk.c      | 238 +++++++++++++++++++++-----------
>  include/uapi/linux/virtio_blk.h |  18 +--
>  2 files changed, 166 insertions(+), 90 deletions(-)
> 
> diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
> index 2723eede6f21..4f0dbbb3d4a5 100644
> --- a/drivers/block/virtio_blk.c
> +++ b/drivers/block/virtio_blk.c
> @@ -96,16 +96,14 @@ struct virtblk_req {
>  
>  		/*
>  		 * The zone append command has an extended in header.
> -		 * The status field in zone_append_in_hdr must have
> -		 * the same offset in virtblk_req as the non-zoned
> -		 * status field above.
> +		 * The status field in zone_append_in_hdr must always
> +		 * be the last byte.
>  		 */
>  		struct {
> +			__virtio64 sector;
>  			u8 status;
> -			u8 reserved[7];
> -			__le64 append_sector;
> -		} zone_append_in_hdr;
> -	};
> +		} zone_append;
> +	} in_hdr;
>  
>  	size_t in_hdr_len;
>  
> @@ -154,7 +152,7 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)
>  			sgs[num_out + num_in++] = vbr->sg_table.sgl;
>  	}
>  
> -	sg_init_one(&in_hdr, &vbr->status, vbr->in_hdr_len);
> +	sg_init_one(&in_hdr, &vbr->in_hdr.status, vbr->in_hdr_len);
>  	sgs[num_out + num_in++] = &in_hdr;
>  
>  	return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
> @@ -242,11 +240,14 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  				      struct request *req,
>  				      struct virtblk_req *vbr)
>  {
> -	size_t in_hdr_len = sizeof(vbr->status);
> +	size_t in_hdr_len = sizeof(vbr->in_hdr.status);
>  	bool unmap = false;
>  	u32 type;
>  	u64 sector = 0;
>  
> +	if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) && op_is_zone_mgmt(req_op(req)))
> +		return BLK_STS_NOTSUPP;
> +
>  	/* Set fields for all request types */
>  	vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
>  
> @@ -287,7 +288,7 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  	case REQ_OP_ZONE_APPEND:
>  		type = VIRTIO_BLK_T_ZONE_APPEND;
>  		sector = blk_rq_pos(req);
> -		in_hdr_len = sizeof(vbr->zone_append_in_hdr);
> +		in_hdr_len = sizeof(vbr->in_hdr.zone_append);
>  		break;
>  	case REQ_OP_ZONE_RESET:
>  		type = VIRTIO_BLK_T_ZONE_RESET;
> @@ -297,7 +298,10 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  		type = VIRTIO_BLK_T_ZONE_RESET_ALL;
>  		break;
>  	case REQ_OP_DRV_IN:
> -		/* Out header already filled in, nothing to do */
> +		/*
> +		 * Out header has already been prepared by the caller (virtblk_get_id()
> +		 * or virtblk_submit_zone_report()), nothing to do here.
> +		 */
>  		return 0;
>  	default:
>  		WARN_ON_ONCE(1);
> @@ -318,16 +322,28 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  	return 0;
>  }
>  
> +/*
> + * The status byte is always the last byte of the virtblk request
> + * in-header. This helper fetches its value for all in-header formats
> + * that are currently defined.
> + */
> +static inline u8 virtblk_vbr_status(struct virtblk_req *vbr)
> +{
> +	return *((u8 *)&vbr->in_hdr + vbr->in_hdr_len - 1);
> +}
> +
>  static inline void virtblk_request_done(struct request *req)
>  {
>  	struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
> -	blk_status_t status = virtblk_result(vbr->status);
> +	blk_status_t status = virtblk_result(virtblk_vbr_status(vbr));
> +	struct virtio_blk *vblk = req->mq_hctx->queue->queuedata;
>  
>  	virtblk_unmap_data(req, vbr);
>  	virtblk_cleanup_cmd(req);
>  
>  	if (req_op(req) == REQ_OP_ZONE_APPEND)
> -		req->__sector = le64_to_cpu(vbr->zone_append_in_hdr.append_sector);
> +		req->__sector = virtio64_to_cpu(vblk->vdev,
> +						vbr->in_hdr.zone_append.sector);
>  
>  	blk_mq_end_request(req, status);
>  }
> @@ -355,7 +371,7 @@ static int virtblk_handle_req(struct virtio_blk_vq *vq,
>  
>  		if (likely(!blk_should_fake_timeout(req->q)) &&
>  		    !blk_mq_complete_request_remote(req) &&
> -		    !blk_mq_add_to_batch(req, iob, vbr->status,
> +		    !blk_mq_add_to_batch(req, iob, virtblk_vbr_status(vbr),
>  					 virtblk_complete_batch))
>  			virtblk_request_done(req);
>  		req_done++;
> @@ -550,7 +566,6 @@ static void virtio_queue_rqs(struct request **rqlist)
>  #ifdef CONFIG_BLK_DEV_ZONED
>  static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
>  					  unsigned int nr_zones,
> -					  unsigned int zone_sectors,
>  					  size_t *buflen)
>  {
>  	struct request_queue *q = vblk->disk->queue;
> @@ -558,7 +573,7 @@ static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
>  	void *buf;
>  
>  	nr_zones = min_t(unsigned int, nr_zones,
> -			 get_capacity(vblk->disk) >> ilog2(zone_sectors));
> +			 get_capacity(vblk->disk) >> ilog2(vblk->zone_sectors));
>  
>  	bufsize = sizeof(struct virtio_blk_zone_report) +
>  		nr_zones * sizeof(struct virtio_blk_zone_descriptor);
> @@ -592,7 +607,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
>  		return PTR_ERR(req);
>  
>  	vbr = blk_mq_rq_to_pdu(req);
> -	vbr->in_hdr_len = sizeof(vbr->status);
> +	vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
>  	vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT);
>  	vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector);
>  
> @@ -601,7 +616,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
>  		goto out;
>  
>  	blk_execute_rq(req, false);
> -	err = blk_status_to_errno(virtblk_result(vbr->status));
> +	err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
>  out:
>  	blk_mq_free_request(req);
>  	return err;
> @@ -609,29 +624,72 @@ 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, unsigned int zone_sectors,
> -			       report_zones_cb cb, void *data)
> +			       unsigned int idx, report_zones_cb cb, void *data)
>  {
>  	struct blk_zone zone = { };
>  
> -	if (entry->z_type != VIRTIO_BLK_ZT_SWR &&
> -	    entry->z_type != VIRTIO_BLK_ZT_SWP &&
> -	    entry->z_type != VIRTIO_BLK_ZT_CONV) {
> -		dev_err(&vblk->vdev->dev, "invalid zone type %#x\n",
> -			entry->z_type);
> -		return -EINVAL;
> +	zone.start = virtio64_to_cpu(vblk->vdev, entry->z_start);
> +	if (zone.start + vblk->zone_sectors <= get_capacity(vblk->disk))
> +		zone.len = vblk->zone_sectors;
> +	else
> +		zone.len = get_capacity(vblk->disk) - zone.start;
> +	zone.capacity = virtio64_to_cpu(vblk->vdev, entry->z_cap);
> +	zone.wp = virtio64_to_cpu(vblk->vdev, entry->z_wp);
> +
> +	switch (entry->z_type) {
> +	case VIRTIO_BLK_ZT_SWR:
> +		zone.type = BLK_ZONE_TYPE_SEQWRITE_REQ;
> +		break;
> +	case VIRTIO_BLK_ZT_SWP:
> +		zone.type = BLK_ZONE_TYPE_SEQWRITE_PREF;
> +		break;
> +	case VIRTIO_BLK_ZT_CONV:
> +		zone.type = BLK_ZONE_TYPE_CONVENTIONAL;
> +		break;
> +	default:
> +		dev_err(&vblk->vdev->dev, "zone %llu: invalid type %#x\n",
> +			zone.start, entry->z_type);
> +		return -EIO;
>  	}
>  
> -	zone.type = entry->z_type;
> -	zone.cond = entry->z_state;
> -	zone.len = zone_sectors;
> -	zone.capacity = le64_to_cpu(entry->z_cap);
> -	zone.start = le64_to_cpu(entry->z_start);
> -	if (zone.cond == BLK_ZONE_COND_FULL)
> +	switch (entry->z_state) {
> +	case VIRTIO_BLK_ZS_EMPTY:
> +		zone.cond = BLK_ZONE_COND_EMPTY;
> +		break;
> +	case VIRTIO_BLK_ZS_CLOSED:
> +		zone.cond = BLK_ZONE_COND_CLOSED;
> +		break;
> +	case VIRTIO_BLK_ZS_FULL:
> +		zone.cond = BLK_ZONE_COND_FULL;
>  		zone.wp = zone.start + zone.len;
> -	else
> -		zone.wp = le64_to_cpu(entry->z_wp);
> +		break;
> +	case VIRTIO_BLK_ZS_EOPEN:
> +		zone.cond = BLK_ZONE_COND_EXP_OPEN;
> +		break;
> +	case VIRTIO_BLK_ZS_IOPEN:
> +		zone.cond = BLK_ZONE_COND_IMP_OPEN;
> +		break;
> +	case VIRTIO_BLK_ZS_NOT_WP:
> +		zone.cond = BLK_ZONE_COND_NOT_WP;
> +		break;
> +	case VIRTIO_BLK_ZS_RDONLY:
> +		zone.cond = BLK_ZONE_COND_READONLY;
> +		zone.wp = ULONG_MAX;
> +		break;
> +	case VIRTIO_BLK_ZS_OFFLINE:
> +		zone.cond = BLK_ZONE_COND_OFFLINE;
> +		zone.wp = ULONG_MAX;
> +		break;
> +	default:
> +		dev_err(&vblk->vdev->dev, "zone %llu: invalid condition %#x\n",
> +			zone.start, entry->z_state);
> +		return -EIO;
> +	}
>  
> +	/*
> +	 * The callback below checks the validity of the reported
> +	 * entry data, no need to further validate it here.
> +	 */
>  	return cb(&zone, idx, data);
>  }
>  
> @@ -641,39 +699,47 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
>  {
>  	struct virtio_blk *vblk = disk->private_data;
>  	struct virtio_blk_zone_report *report;
> -	unsigned int zone_sectors = vblk->zone_sectors;
> -	unsigned int nz, i;
> -	int ret, zone_idx = 0;
> +	unsigned long long nz, i;
>  	size_t buflen;
> +	unsigned int zone_idx = 0;
> +	int ret;
>  
>  	if (WARN_ON_ONCE(!vblk->zone_sectors))
>  		return -EOPNOTSUPP;
>  
> -	report = virtblk_alloc_report_buffer(vblk, nr_zones,
> -					     zone_sectors, &buflen);
> +	report = virtblk_alloc_report_buffer(vblk, nr_zones, &buflen);
>  	if (!report)
>  		return -ENOMEM;
>  
> +	mutex_lock(&vblk->vdev_mutex);
> +
> +	if (!vblk->vdev) {
> +		ret = -ENXIO;
> +		goto fail_report;
> +	}
> +
>  	while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) {
>  		memset(report, 0, buflen);
>  
>  		ret = virtblk_submit_zone_report(vblk, (char *)report,
>  						 buflen, sector);
> -		if (ret) {
> -			if (ret > 0)
> -				ret = -EIO;
> -			goto out_free;
> -		}
> -		nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones);
> +		if (ret)
> +			goto fail_report;
> +
> +		nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones),
> +			   nr_zones);
>  		if (!nz)
>  			break;
>  
>  		for (i = 0; i < nz && zone_idx < nr_zones; i++) {
>  			ret = virtblk_parse_zone(vblk, &report->zones[i],
> -						 zone_idx, zone_sectors, cb, data);
> +						 zone_idx, cb, data);
>  			if (ret)
> -				goto out_free;
> -			sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors;
> +				goto fail_report;
> +
> +			sector = virtio64_to_cpu(vblk->vdev,
> +						 report->zones[i].z_start) +
> +				 vblk->zone_sectors;
>  			zone_idx++;
>  		}
>  	}
> @@ -682,7 +748,8 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
>  		ret = zone_idx;
>  	else
>  		ret = -EINVAL;
> -out_free:
> +fail_report:
> +	mutex_unlock(&vblk->vdev_mutex);
>  	kvfree(report);
>  	return ret;
>  }
> @@ -691,20 +758,28 @@ static void virtblk_revalidate_zones(struct virtio_blk *vblk)
>  {
>  	u8 model;
>  
> -	if (!vblk->zone_sectors)
> -		return;
> -
>  	virtio_cread(vblk->vdev, struct virtio_blk_config,
>  		     zoned.model, &model);
> -	if (!blk_revalidate_disk_zones(vblk->disk, NULL))
> -		set_capacity_and_notify(vblk->disk, 0);
> +	switch (model) {
> +	default:
> +		dev_err(&vblk->vdev->dev, "unknown zone model %d\n", model);
> +		fallthrough;
> +	case VIRTIO_BLK_Z_NONE:
> +	case VIRTIO_BLK_Z_HA:
> +		disk_set_zoned(vblk->disk, BLK_ZONED_NONE);
> +		return;
> +	case VIRTIO_BLK_Z_HM:
> +		WARN_ON_ONCE(!vblk->zone_sectors);
> +		if (!blk_revalidate_disk_zones(vblk->disk, NULL))
> +			set_capacity_and_notify(vblk->disk, 0);
> +	}
>  }
>  
>  static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  				       struct virtio_blk *vblk,
>  				       struct request_queue *q)
>  {
> -	u32 v;
> +	u32 v, wg;
>  	u8 model;
>  	int ret;
>  
> @@ -713,16 +788,11 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  
>  	switch (model) {
>  	case VIRTIO_BLK_Z_NONE:
> +	case VIRTIO_BLK_Z_HA:
> +		/* Present the host-aware device as non-zoned */
>  		return 0;
>  	case VIRTIO_BLK_Z_HM:
>  		break;
> -	case VIRTIO_BLK_Z_HA:
> -		/*
> -		 * Present the host-aware device as a regular drive.
> -		 * TODO It is possible to add an option to make it appear
> -		 * in the system as a zoned drive.
> -		 */
> -		return 0;
>  	default:
>  		dev_err(&vdev->dev, "unsupported zone model %d\n", model);
>  		return -EINVAL;
> @@ -735,32 +805,31 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  
>  	virtio_cread(vdev, struct virtio_blk_config,
>  		     zoned.max_open_zones, &v);
> -	disk_set_max_open_zones(vblk->disk, le32_to_cpu(v));
> -
> -	dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v));
> +	disk_set_max_open_zones(vblk->disk, v);
> +	dev_dbg(&vdev->dev, "max open zones = %u\n", v);
>  
>  	virtio_cread(vdev, struct virtio_blk_config,
>  		     zoned.max_active_zones, &v);
> -	disk_set_max_active_zones(vblk->disk, le32_to_cpu(v));
> -	dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v));
> +	disk_set_max_active_zones(vblk->disk, v);
> +	dev_dbg(&vdev->dev, "max active zones = %u\n", v);
>  
>  	virtio_cread(vdev, struct virtio_blk_config,
> -		     zoned.write_granularity, &v);
> -	if (!v) {
> +		     zoned.write_granularity, &wg);
> +	if (!wg) {
>  		dev_warn(&vdev->dev, "zero write granularity reported\n");
>  		return -ENODEV;
>  	}
> -	blk_queue_physical_block_size(q, le32_to_cpu(v));
> -	blk_queue_io_min(q, le32_to_cpu(v));
> +	blk_queue_physical_block_size(q, wg);
> +	blk_queue_io_min(q, wg);
>  
> -	dev_dbg(&vdev->dev, "write granularity = %u\n", le32_to_cpu(v));
> +	dev_dbg(&vdev->dev, "write granularity = %u\n", wg);
>  
>  	/*
>  	 * virtio ZBD specification doesn't require zones to be a power of
>  	 * two sectors in size, but the code in this driver expects that.
>  	 */
> -	virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, &v);
> -	vblk->zone_sectors = le32_to_cpu(v);
> +	virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors,
> +		     &vblk->zone_sectors);
>  	if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) {
>  		dev_err(&vdev->dev,
>  			"zoned device with non power of two zone size %u\n",
> @@ -783,8 +852,15 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  			dev_warn(&vdev->dev, "zero max_append_sectors reported\n");
>  			return -ENODEV;
>  		}
> -		blk_queue_max_zone_append_sectors(q, le32_to_cpu(v));
> -		dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v));
> +		if ((v << SECTOR_SHIFT) < wg) {
> +			dev_err(&vdev->dev,
> +				"write granularity %u exceeds max_append_sectors %u limit\n",
> +				wg, v);
> +			return -ENODEV;
> +		}
> +
> +		blk_queue_max_zone_append_sectors(q, v);
> +		dev_dbg(&vdev->dev, "max append sectors = %u\n", v);
>  	}
>  
>  	return ret;
> @@ -794,6 +870,7 @@ static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
>  {
>  	return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED);
>  }
> +
>  #else
>  
>  /*
> @@ -801,9 +878,11 @@ static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
>   * We only need to define a few symbols to avoid compilation errors.
>   */
>  #define virtblk_report_zones       NULL
> +
>  static inline void virtblk_revalidate_zones(struct virtio_blk *vblk)
>  {
>  }
> +
>  static inline int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  			struct virtio_blk *vblk, struct request_queue *q)
>  {
> @@ -831,7 +910,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
>  		return PTR_ERR(req);
>  
>  	vbr = blk_mq_rq_to_pdu(req);
> -	vbr->in_hdr_len = sizeof(vbr->status);
> +	vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
>  	vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
>  	vbr->out_hdr.sector = 0;
>  
> @@ -840,7 +919,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
>  		goto out;
>  
>  	blk_execute_rq(req, false);
> -	err = blk_status_to_errno(virtblk_result(vbr->status));
> +	err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
>  out:
>  	blk_mq_free_request(req);
>  	return err;
> @@ -1504,9 +1583,6 @@ static int virtblk_probe(struct virtio_device *vdev)
>  			goto out_cleanup_disk;
>  	}
>  
> -	dev_info(&vdev->dev, "blk config size: %zu\n",
> -		sizeof(struct virtio_blk_config));
> -
>  	err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
>  	if (err)
>  		goto out_cleanup_disk;
> diff --git a/include/uapi/linux/virtio_blk.h b/include/uapi/linux/virtio_blk.h
> index 5af2a0300bb9..3744e4da1b2a 100644
> --- a/include/uapi/linux/virtio_blk.h
> +++ b/include/uapi/linux/virtio_blk.h
> @@ -140,11 +140,11 @@ struct virtio_blk_config {
>  
>  	/* Zoned block device characteristics (if VIRTIO_BLK_F_ZONED) */
>  	struct virtio_blk_zoned_characteristics {
> -		__le32 zone_sectors;
> -		__le32 max_open_zones;
> -		__le32 max_active_zones;
> -		__le32 max_append_sectors;
> -		__le32 write_granularity;
> +		__virtio32 zone_sectors;
> +		__virtio32 max_open_zones;
> +		__virtio32 max_active_zones;
> +		__virtio32 max_append_sectors;
> +		__virtio32 write_granularity;
>  		__u8 model;
>  		__u8 unused2[3];
>  	} zoned;
> @@ -241,11 +241,11 @@ struct virtio_blk_outhdr {
>   */
>  struct virtio_blk_zone_descriptor {
>  	/* Zone capacity */
> -	__le64 z_cap;
> +	__virtio64 z_cap;
>  	/* The starting sector of the zone */
> -	__le64 z_start;
> +	__virtio64 z_start;
>  	/* Zone write pointer position in sectors */
> -	__le64 z_wp;
> +	__virtio64 z_wp;
>  	/* Zone type */
>  	__u8 z_type;
>  	/* Zone state */
> @@ -254,7 +254,7 @@ struct virtio_blk_zone_descriptor {
>  };
>  
>  struct virtio_blk_zone_report {
> -	__le64 nr_zones;
> +	__virtio64 nr_zones;
>  	__u8 reserved[56];
>  	struct virtio_blk_zone_descriptor zones[];
>  };
> -- 
> 2.34.1
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
> For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [virtio-dev] [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version
@ 2023-04-03 17:53     ` Michael S. Tsirkin
  0 siblings, 0 replies; 15+ messages in thread
From: Michael S. Tsirkin @ 2023-04-03 17:53 UTC (permalink / raw)
  To: Dmitry Fomichev
  Cc: Jens Axboe, virtio-dev, Damien Le Moal, Sam Li, virtualization,
	linux-block

On Thu, Mar 30, 2023 at 05:49:52PM -0400, Dmitry Fomichev wrote:
> The merged patch series to support zoned block devices in virtio-blk
> is not the most up to date version. The merged patch can be found at
> 
> https://lore.kernel.org/linux-block/20221016034127.330942-3-dmitry.fomichev@wdc.com/
> 
> , but the latest and reviewed version is
> 
> https://lore.kernel.org/linux-block/20221110053952.3378990-3-dmitry.fomichev@wdc.com/

What happened here is that it was not sent to correct people or lists.

v2 happened to draw my attention by chance, I missed the
interface change and I did not see later ones and merged v2.

To: Jens Axboe <axboe@kernel.dk>,
	linux-block@vger.kernel.org,
	Damien Le Moal <damien.lemoal@opensource.wdc.com>,
	Stefan Hajnoczi <stefanha@gmail.com>,
	Hannes Reinecke <hare@suse.de>, Sam Li <faithilikerun@gmail.com>
Cc: virtio-dev@lists.oasis-open.org,
	Dmitry Fomichev <dmitry.fomichev@wdc.com>

while:

$ ./scripts/get_maintainer.pl -f drivers/block/virtio_blk.c
"Michael S. Tsirkin" <mst@redhat.com> (maintainer:VIRTIO CORE AND NET DRIVERS)
Jason Wang <jasowang@redhat.com> (maintainer:VIRTIO CORE AND NET DRIVERS)
Paolo Bonzini <pbonzini@redhat.com> (reviewer:VIRTIO BLOCK AND SCSI DRIVERS)
Stefan Hajnoczi <stefanha@redhat.com> (reviewer:VIRTIO BLOCK AND SCSI DRIVERS)
Jens Axboe <axboe@kernel.dk> (maintainer:BLOCK LAYER)
virtualization@lists.linux-foundation.org (open list:VIRTIO CORE AND NET DRIVERS)
linux-block@vger.kernel.org (open list:BLOCK LAYER)
linux-kernel@vger.kernel.org (open list)




> The differences between the two are mostly cleanups, but there is one
> change that is very important in terms of compatibility with the
> approved virtio-zbd specification.
> 
> Before it was approved, the OASIS virtio spec had a change in
> VIRTIO_BLK_T_ZONE_APPEND request layout that is not reflected in the
> current virtio-blk driver code. In the running code, the status is
> the first byte of the in-header that is followed by some pad bytes
> and the u64 that carries the sector at which the data has been written
> to the zone back to the driver, aka the append sector.
> 
> This layout turned out to be problematic for implementing in QEMU and
> the request status byte has been eventually made the last byte of the
> in-header. The current code doesn't expect that and this causes the
> append sector value always come as zero to the block layer. This needs
> to be fixed ASAP.
> 
> Fixes: 95bfec41bd3d ("virtio-blk: add support for zoned block devices")
> Cc: stable@vger.kernel.org
> Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
> ---
>  drivers/block/virtio_blk.c      | 238 +++++++++++++++++++++-----------
>  include/uapi/linux/virtio_blk.h |  18 +--
>  2 files changed, 166 insertions(+), 90 deletions(-)
> 
> diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
> index 2723eede6f21..4f0dbbb3d4a5 100644
> --- a/drivers/block/virtio_blk.c
> +++ b/drivers/block/virtio_blk.c
> @@ -96,16 +96,14 @@ struct virtblk_req {
>  
>  		/*
>  		 * The zone append command has an extended in header.
> -		 * The status field in zone_append_in_hdr must have
> -		 * the same offset in virtblk_req as the non-zoned
> -		 * status field above.
> +		 * The status field in zone_append_in_hdr must always
> +		 * be the last byte.
>  		 */
>  		struct {
> +			__virtio64 sector;
>  			u8 status;
> -			u8 reserved[7];
> -			__le64 append_sector;
> -		} zone_append_in_hdr;
> -	};
> +		} zone_append;
> +	} in_hdr;
>  
>  	size_t in_hdr_len;
>  
> @@ -154,7 +152,7 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)
>  			sgs[num_out + num_in++] = vbr->sg_table.sgl;
>  	}
>  
> -	sg_init_one(&in_hdr, &vbr->status, vbr->in_hdr_len);
> +	sg_init_one(&in_hdr, &vbr->in_hdr.status, vbr->in_hdr_len);
>  	sgs[num_out + num_in++] = &in_hdr;
>  
>  	return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
> @@ -242,11 +240,14 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  				      struct request *req,
>  				      struct virtblk_req *vbr)
>  {
> -	size_t in_hdr_len = sizeof(vbr->status);
> +	size_t in_hdr_len = sizeof(vbr->in_hdr.status);
>  	bool unmap = false;
>  	u32 type;
>  	u64 sector = 0;
>  
> +	if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) && op_is_zone_mgmt(req_op(req)))
> +		return BLK_STS_NOTSUPP;
> +
>  	/* Set fields for all request types */
>  	vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
>  
> @@ -287,7 +288,7 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  	case REQ_OP_ZONE_APPEND:
>  		type = VIRTIO_BLK_T_ZONE_APPEND;
>  		sector = blk_rq_pos(req);
> -		in_hdr_len = sizeof(vbr->zone_append_in_hdr);
> +		in_hdr_len = sizeof(vbr->in_hdr.zone_append);
>  		break;
>  	case REQ_OP_ZONE_RESET:
>  		type = VIRTIO_BLK_T_ZONE_RESET;
> @@ -297,7 +298,10 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  		type = VIRTIO_BLK_T_ZONE_RESET_ALL;
>  		break;
>  	case REQ_OP_DRV_IN:
> -		/* Out header already filled in, nothing to do */
> +		/*
> +		 * Out header has already been prepared by the caller (virtblk_get_id()
> +		 * or virtblk_submit_zone_report()), nothing to do here.
> +		 */
>  		return 0;
>  	default:
>  		WARN_ON_ONCE(1);
> @@ -318,16 +322,28 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev,
>  	return 0;
>  }
>  
> +/*
> + * The status byte is always the last byte of the virtblk request
> + * in-header. This helper fetches its value for all in-header formats
> + * that are currently defined.
> + */
> +static inline u8 virtblk_vbr_status(struct virtblk_req *vbr)
> +{
> +	return *((u8 *)&vbr->in_hdr + vbr->in_hdr_len - 1);
> +}
> +
>  static inline void virtblk_request_done(struct request *req)
>  {
>  	struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
> -	blk_status_t status = virtblk_result(vbr->status);
> +	blk_status_t status = virtblk_result(virtblk_vbr_status(vbr));
> +	struct virtio_blk *vblk = req->mq_hctx->queue->queuedata;
>  
>  	virtblk_unmap_data(req, vbr);
>  	virtblk_cleanup_cmd(req);
>  
>  	if (req_op(req) == REQ_OP_ZONE_APPEND)
> -		req->__sector = le64_to_cpu(vbr->zone_append_in_hdr.append_sector);
> +		req->__sector = virtio64_to_cpu(vblk->vdev,
> +						vbr->in_hdr.zone_append.sector);
>  
>  	blk_mq_end_request(req, status);
>  }
> @@ -355,7 +371,7 @@ static int virtblk_handle_req(struct virtio_blk_vq *vq,
>  
>  		if (likely(!blk_should_fake_timeout(req->q)) &&
>  		    !blk_mq_complete_request_remote(req) &&
> -		    !blk_mq_add_to_batch(req, iob, vbr->status,
> +		    !blk_mq_add_to_batch(req, iob, virtblk_vbr_status(vbr),
>  					 virtblk_complete_batch))
>  			virtblk_request_done(req);
>  		req_done++;
> @@ -550,7 +566,6 @@ static void virtio_queue_rqs(struct request **rqlist)
>  #ifdef CONFIG_BLK_DEV_ZONED
>  static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
>  					  unsigned int nr_zones,
> -					  unsigned int zone_sectors,
>  					  size_t *buflen)
>  {
>  	struct request_queue *q = vblk->disk->queue;
> @@ -558,7 +573,7 @@ static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
>  	void *buf;
>  
>  	nr_zones = min_t(unsigned int, nr_zones,
> -			 get_capacity(vblk->disk) >> ilog2(zone_sectors));
> +			 get_capacity(vblk->disk) >> ilog2(vblk->zone_sectors));
>  
>  	bufsize = sizeof(struct virtio_blk_zone_report) +
>  		nr_zones * sizeof(struct virtio_blk_zone_descriptor);
> @@ -592,7 +607,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
>  		return PTR_ERR(req);
>  
>  	vbr = blk_mq_rq_to_pdu(req);
> -	vbr->in_hdr_len = sizeof(vbr->status);
> +	vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
>  	vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT);
>  	vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector);
>  
> @@ -601,7 +616,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk,
>  		goto out;
>  
>  	blk_execute_rq(req, false);
> -	err = blk_status_to_errno(virtblk_result(vbr->status));
> +	err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
>  out:
>  	blk_mq_free_request(req);
>  	return err;
> @@ -609,29 +624,72 @@ 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, unsigned int zone_sectors,
> -			       report_zones_cb cb, void *data)
> +			       unsigned int idx, report_zones_cb cb, void *data)
>  {
>  	struct blk_zone zone = { };
>  
> -	if (entry->z_type != VIRTIO_BLK_ZT_SWR &&
> -	    entry->z_type != VIRTIO_BLK_ZT_SWP &&
> -	    entry->z_type != VIRTIO_BLK_ZT_CONV) {
> -		dev_err(&vblk->vdev->dev, "invalid zone type %#x\n",
> -			entry->z_type);
> -		return -EINVAL;
> +	zone.start = virtio64_to_cpu(vblk->vdev, entry->z_start);
> +	if (zone.start + vblk->zone_sectors <= get_capacity(vblk->disk))
> +		zone.len = vblk->zone_sectors;
> +	else
> +		zone.len = get_capacity(vblk->disk) - zone.start;
> +	zone.capacity = virtio64_to_cpu(vblk->vdev, entry->z_cap);
> +	zone.wp = virtio64_to_cpu(vblk->vdev, entry->z_wp);
> +
> +	switch (entry->z_type) {
> +	case VIRTIO_BLK_ZT_SWR:
> +		zone.type = BLK_ZONE_TYPE_SEQWRITE_REQ;
> +		break;
> +	case VIRTIO_BLK_ZT_SWP:
> +		zone.type = BLK_ZONE_TYPE_SEQWRITE_PREF;
> +		break;
> +	case VIRTIO_BLK_ZT_CONV:
> +		zone.type = BLK_ZONE_TYPE_CONVENTIONAL;
> +		break;
> +	default:
> +		dev_err(&vblk->vdev->dev, "zone %llu: invalid type %#x\n",
> +			zone.start, entry->z_type);
> +		return -EIO;
>  	}
>  
> -	zone.type = entry->z_type;
> -	zone.cond = entry->z_state;
> -	zone.len = zone_sectors;
> -	zone.capacity = le64_to_cpu(entry->z_cap);
> -	zone.start = le64_to_cpu(entry->z_start);
> -	if (zone.cond == BLK_ZONE_COND_FULL)
> +	switch (entry->z_state) {
> +	case VIRTIO_BLK_ZS_EMPTY:
> +		zone.cond = BLK_ZONE_COND_EMPTY;
> +		break;
> +	case VIRTIO_BLK_ZS_CLOSED:
> +		zone.cond = BLK_ZONE_COND_CLOSED;
> +		break;
> +	case VIRTIO_BLK_ZS_FULL:
> +		zone.cond = BLK_ZONE_COND_FULL;
>  		zone.wp = zone.start + zone.len;
> -	else
> -		zone.wp = le64_to_cpu(entry->z_wp);
> +		break;
> +	case VIRTIO_BLK_ZS_EOPEN:
> +		zone.cond = BLK_ZONE_COND_EXP_OPEN;
> +		break;
> +	case VIRTIO_BLK_ZS_IOPEN:
> +		zone.cond = BLK_ZONE_COND_IMP_OPEN;
> +		break;
> +	case VIRTIO_BLK_ZS_NOT_WP:
> +		zone.cond = BLK_ZONE_COND_NOT_WP;
> +		break;
> +	case VIRTIO_BLK_ZS_RDONLY:
> +		zone.cond = BLK_ZONE_COND_READONLY;
> +		zone.wp = ULONG_MAX;
> +		break;
> +	case VIRTIO_BLK_ZS_OFFLINE:
> +		zone.cond = BLK_ZONE_COND_OFFLINE;
> +		zone.wp = ULONG_MAX;
> +		break;
> +	default:
> +		dev_err(&vblk->vdev->dev, "zone %llu: invalid condition %#x\n",
> +			zone.start, entry->z_state);
> +		return -EIO;
> +	}
>  
> +	/*
> +	 * The callback below checks the validity of the reported
> +	 * entry data, no need to further validate it here.
> +	 */
>  	return cb(&zone, idx, data);
>  }
>  
> @@ -641,39 +699,47 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
>  {
>  	struct virtio_blk *vblk = disk->private_data;
>  	struct virtio_blk_zone_report *report;
> -	unsigned int zone_sectors = vblk->zone_sectors;
> -	unsigned int nz, i;
> -	int ret, zone_idx = 0;
> +	unsigned long long nz, i;
>  	size_t buflen;
> +	unsigned int zone_idx = 0;
> +	int ret;
>  
>  	if (WARN_ON_ONCE(!vblk->zone_sectors))
>  		return -EOPNOTSUPP;
>  
> -	report = virtblk_alloc_report_buffer(vblk, nr_zones,
> -					     zone_sectors, &buflen);
> +	report = virtblk_alloc_report_buffer(vblk, nr_zones, &buflen);
>  	if (!report)
>  		return -ENOMEM;
>  
> +	mutex_lock(&vblk->vdev_mutex);
> +
> +	if (!vblk->vdev) {
> +		ret = -ENXIO;
> +		goto fail_report;
> +	}
> +
>  	while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) {
>  		memset(report, 0, buflen);
>  
>  		ret = virtblk_submit_zone_report(vblk, (char *)report,
>  						 buflen, sector);
> -		if (ret) {
> -			if (ret > 0)
> -				ret = -EIO;
> -			goto out_free;
> -		}
> -		nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones);
> +		if (ret)
> +			goto fail_report;
> +
> +		nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones),
> +			   nr_zones);
>  		if (!nz)
>  			break;
>  
>  		for (i = 0; i < nz && zone_idx < nr_zones; i++) {
>  			ret = virtblk_parse_zone(vblk, &report->zones[i],
> -						 zone_idx, zone_sectors, cb, data);
> +						 zone_idx, cb, data);
>  			if (ret)
> -				goto out_free;
> -			sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors;
> +				goto fail_report;
> +
> +			sector = virtio64_to_cpu(vblk->vdev,
> +						 report->zones[i].z_start) +
> +				 vblk->zone_sectors;
>  			zone_idx++;
>  		}
>  	}
> @@ -682,7 +748,8 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
>  		ret = zone_idx;
>  	else
>  		ret = -EINVAL;
> -out_free:
> +fail_report:
> +	mutex_unlock(&vblk->vdev_mutex);
>  	kvfree(report);
>  	return ret;
>  }
> @@ -691,20 +758,28 @@ static void virtblk_revalidate_zones(struct virtio_blk *vblk)
>  {
>  	u8 model;
>  
> -	if (!vblk->zone_sectors)
> -		return;
> -
>  	virtio_cread(vblk->vdev, struct virtio_blk_config,
>  		     zoned.model, &model);
> -	if (!blk_revalidate_disk_zones(vblk->disk, NULL))
> -		set_capacity_and_notify(vblk->disk, 0);
> +	switch (model) {
> +	default:
> +		dev_err(&vblk->vdev->dev, "unknown zone model %d\n", model);
> +		fallthrough;
> +	case VIRTIO_BLK_Z_NONE:
> +	case VIRTIO_BLK_Z_HA:
> +		disk_set_zoned(vblk->disk, BLK_ZONED_NONE);
> +		return;
> +	case VIRTIO_BLK_Z_HM:
> +		WARN_ON_ONCE(!vblk->zone_sectors);
> +		if (!blk_revalidate_disk_zones(vblk->disk, NULL))
> +			set_capacity_and_notify(vblk->disk, 0);
> +	}
>  }
>  
>  static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  				       struct virtio_blk *vblk,
>  				       struct request_queue *q)
>  {
> -	u32 v;
> +	u32 v, wg;
>  	u8 model;
>  	int ret;
>  
> @@ -713,16 +788,11 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  
>  	switch (model) {
>  	case VIRTIO_BLK_Z_NONE:
> +	case VIRTIO_BLK_Z_HA:
> +		/* Present the host-aware device as non-zoned */
>  		return 0;
>  	case VIRTIO_BLK_Z_HM:
>  		break;
> -	case VIRTIO_BLK_Z_HA:
> -		/*
> -		 * Present the host-aware device as a regular drive.
> -		 * TODO It is possible to add an option to make it appear
> -		 * in the system as a zoned drive.
> -		 */
> -		return 0;
>  	default:
>  		dev_err(&vdev->dev, "unsupported zone model %d\n", model);
>  		return -EINVAL;
> @@ -735,32 +805,31 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  
>  	virtio_cread(vdev, struct virtio_blk_config,
>  		     zoned.max_open_zones, &v);
> -	disk_set_max_open_zones(vblk->disk, le32_to_cpu(v));
> -
> -	dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v));
> +	disk_set_max_open_zones(vblk->disk, v);
> +	dev_dbg(&vdev->dev, "max open zones = %u\n", v);
>  
>  	virtio_cread(vdev, struct virtio_blk_config,
>  		     zoned.max_active_zones, &v);
> -	disk_set_max_active_zones(vblk->disk, le32_to_cpu(v));
> -	dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v));
> +	disk_set_max_active_zones(vblk->disk, v);
> +	dev_dbg(&vdev->dev, "max active zones = %u\n", v);
>  
>  	virtio_cread(vdev, struct virtio_blk_config,
> -		     zoned.write_granularity, &v);
> -	if (!v) {
> +		     zoned.write_granularity, &wg);
> +	if (!wg) {
>  		dev_warn(&vdev->dev, "zero write granularity reported\n");
>  		return -ENODEV;
>  	}
> -	blk_queue_physical_block_size(q, le32_to_cpu(v));
> -	blk_queue_io_min(q, le32_to_cpu(v));
> +	blk_queue_physical_block_size(q, wg);
> +	blk_queue_io_min(q, wg);
>  
> -	dev_dbg(&vdev->dev, "write granularity = %u\n", le32_to_cpu(v));
> +	dev_dbg(&vdev->dev, "write granularity = %u\n", wg);
>  
>  	/*
>  	 * virtio ZBD specification doesn't require zones to be a power of
>  	 * two sectors in size, but the code in this driver expects that.
>  	 */
> -	virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, &v);
> -	vblk->zone_sectors = le32_to_cpu(v);
> +	virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors,
> +		     &vblk->zone_sectors);
>  	if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) {
>  		dev_err(&vdev->dev,
>  			"zoned device with non power of two zone size %u\n",
> @@ -783,8 +852,15 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  			dev_warn(&vdev->dev, "zero max_append_sectors reported\n");
>  			return -ENODEV;
>  		}
> -		blk_queue_max_zone_append_sectors(q, le32_to_cpu(v));
> -		dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v));
> +		if ((v << SECTOR_SHIFT) < wg) {
> +			dev_err(&vdev->dev,
> +				"write granularity %u exceeds max_append_sectors %u limit\n",
> +				wg, v);
> +			return -ENODEV;
> +		}
> +
> +		blk_queue_max_zone_append_sectors(q, v);
> +		dev_dbg(&vdev->dev, "max append sectors = %u\n", v);
>  	}
>  
>  	return ret;
> @@ -794,6 +870,7 @@ static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
>  {
>  	return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED);
>  }
> +
>  #else
>  
>  /*
> @@ -801,9 +878,11 @@ static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
>   * We only need to define a few symbols to avoid compilation errors.
>   */
>  #define virtblk_report_zones       NULL
> +
>  static inline void virtblk_revalidate_zones(struct virtio_blk *vblk)
>  {
>  }
> +
>  static inline int virtblk_probe_zoned_device(struct virtio_device *vdev,
>  			struct virtio_blk *vblk, struct request_queue *q)
>  {
> @@ -831,7 +910,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
>  		return PTR_ERR(req);
>  
>  	vbr = blk_mq_rq_to_pdu(req);
> -	vbr->in_hdr_len = sizeof(vbr->status);
> +	vbr->in_hdr_len = sizeof(vbr->in_hdr.status);
>  	vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
>  	vbr->out_hdr.sector = 0;
>  
> @@ -840,7 +919,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
>  		goto out;
>  
>  	blk_execute_rq(req, false);
> -	err = blk_status_to_errno(virtblk_result(vbr->status));
> +	err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status));
>  out:
>  	blk_mq_free_request(req);
>  	return err;
> @@ -1504,9 +1583,6 @@ static int virtblk_probe(struct virtio_device *vdev)
>  			goto out_cleanup_disk;
>  	}
>  
> -	dev_info(&vdev->dev, "blk config size: %zu\n",
> -		sizeof(struct virtio_blk_config));
> -
>  	err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
>  	if (err)
>  		goto out_cleanup_disk;
> diff --git a/include/uapi/linux/virtio_blk.h b/include/uapi/linux/virtio_blk.h
> index 5af2a0300bb9..3744e4da1b2a 100644
> --- a/include/uapi/linux/virtio_blk.h
> +++ b/include/uapi/linux/virtio_blk.h
> @@ -140,11 +140,11 @@ struct virtio_blk_config {
>  
>  	/* Zoned block device characteristics (if VIRTIO_BLK_F_ZONED) */
>  	struct virtio_blk_zoned_characteristics {
> -		__le32 zone_sectors;
> -		__le32 max_open_zones;
> -		__le32 max_active_zones;
> -		__le32 max_append_sectors;
> -		__le32 write_granularity;
> +		__virtio32 zone_sectors;
> +		__virtio32 max_open_zones;
> +		__virtio32 max_active_zones;
> +		__virtio32 max_append_sectors;
> +		__virtio32 write_granularity;
>  		__u8 model;
>  		__u8 unused2[3];
>  	} zoned;
> @@ -241,11 +241,11 @@ struct virtio_blk_outhdr {
>   */
>  struct virtio_blk_zone_descriptor {
>  	/* Zone capacity */
> -	__le64 z_cap;
> +	__virtio64 z_cap;
>  	/* The starting sector of the zone */
> -	__le64 z_start;
> +	__virtio64 z_start;
>  	/* Zone write pointer position in sectors */
> -	__le64 z_wp;
> +	__virtio64 z_wp;
>  	/* Zone type */
>  	__u8 z_type;
>  	/* Zone state */
> @@ -254,7 +254,7 @@ struct virtio_blk_zone_descriptor {
>  };
>  
>  struct virtio_blk_zone_report {
> -	__le64 nr_zones;
> +	__virtio64 nr_zones;
>  	__u8 reserved[56];
>  	struct virtio_blk_zone_descriptor zones[];
>  };
> -- 
> 2.34.1
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
> For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org
> 
> 

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2023-04-03 17:54 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-30 21:49 [PATCH v2 0/2] virtio-blk: fix a few problems in ZBD-related code Dmitry Fomichev
2023-03-30 21:49 ` [virtio-dev] " Dmitry Fomichev
2023-03-30 21:49 ` [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version Dmitry Fomichev
2023-03-30 21:49   ` [virtio-dev] " Dmitry Fomichev
2023-04-03 15:15   ` Christoph Hellwig
2023-04-03 15:15     ` Christoph Hellwig
2023-04-03 17:35     ` Michael S. Tsirkin
2023-04-03 17:35       ` Michael S. Tsirkin
2023-04-03 17:35       ` [virtio-dev] " Michael S. Tsirkin
2023-04-03 17:53   ` [virtio-dev] " Michael S. Tsirkin
2023-04-03 17:53     ` Michael S. Tsirkin
2023-04-03 17:53     ` Michael S. Tsirkin
2023-03-30 21:49 ` [PATCH v2 2/2] virtio-blk: fix ZBD probe in kernels without ZBD support Dmitry Fomichev
2023-03-30 21:49   ` [virtio-dev] " Dmitry Fomichev
  -- strict thread matches above, loose matches on Subject: below --
2023-03-31 14:38 [PATCH v2 1/2] virtio-blk: migrate to the latest patchset version kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.