History

virtio-blk: add support for zoned block devices

This patch adds support for Zoned Block Devices (ZBDs) to the kernel virtio-blk driver. The patch accompanies the virtio-blk ZBD support draft that is now being proposed for standardization. The latest version of the draft is linked at https://github.com/oasis-tcs/virtio-spec/issues/143 . The QEMU zoned device code that implements these protocol extensions has been developed by Sam Li and it is currently in review at the QEMU mailing list. A number of virtblk request structure changes has been introduced to accommodate the functionality that is specific to zoned block devices and, most importantly, make room for carrying the Zoned Append sector value from the device back to the driver along with the request status. The zone-specific code in the patch is heavily influenced by NVMe ZNS code in drivers/nvme/host/zns.c, but it is simpler because the proposed virtio ZBD draft only covers the zoned device features that are relevant to the zoned functionality provided by Linux block layer. includes the following fixup: virtio-blk: fix probe without CONFIG_BLK_DEV_ZONED When building without CONFIG_BLK_DEV_ZONED, VIRTIO_BLK_F_ZONED is excluded from array of driver features. As a result virtio_has_feature panics in virtio_check_driver_offered_feature since that by design verifies that a feature we are checking for is listed in the feature array. To fix, replace the call to virtio_has_feature with a stub.

Dmitry Fomichev committed 4 years ago

Commit 95bfec41 parent d16c0cd2 files · +474 −18Browse files

Unified · Split

2 files
  1. drivers/block/virtio_blk.c +369 −18
  2. include/uapi/linux/virtio_blk.h +105 −0
drivers/block/virtio_blk.c+369−18
@@ -15,6 +15,7 @@ · 14 unmodified lines
15#include <linux/blk-mq.h>15#include <linux/blk-mq.h>
16#include <linux/blk-mq-virtio.h>16#include <linux/blk-mq-virtio.h>
17#include <linux/numa.h>17#include <linux/numa.h>
18#include <linux/vmalloc.h>
18#include <uapi/linux/virtio_ring.h>19#include <uapi/linux/virtio_ring.h>
19 20
20#define PART_BITS 421#define PART_BITS 4
@@ -80,22 +81,51 @@ struct virtio_blk { · 59 unmodified lines
80 int num_vqs;81 int num_vqs;
81 int io_queues[HCTX_MAX_TYPES];82 int io_queues[HCTX_MAX_TYPES];
82 struct virtio_blk_vq *vqs;83 struct virtio_blk_vq *vqs;
84
85 /* For zoned device */
86 unsigned int zone_sectors;
83};87};
84 88
85struct virtblk_req {89struct virtblk_req {
90 /* Out header */
86 struct virtio_blk_outhdr out_hdr;91 struct virtio_blk_outhdr out_hdr;
87 u8 status;92
93 /* In header */
94 union {
95 u8 status;
96
97 /*
98 * The zone append command has an extended in header.
99 * The status field in zone_append_in_hdr must have
100 * the same offset in virtblk_req as the non-zoned
101 * status field above.
102 */
103 struct {
104 u8 status;
105 u8 reserved[7];
106 u64 append_sector;
107 } zone_append_in_hdr;
108 };
109
110 size_t in_hdr_len;
111
88 struct sg_table sg_table;112 struct sg_table sg_table;
89 struct scatterlist sg[];113 struct scatterlist sg[];
90};114};
91 115
92static inline blk_status_t virtblk_result(struct virtblk_req *vbr)116static inline blk_status_t virtblk_result(u8 status)
93{117{
94 switch (vbr->status) {118 switch (status) {
95 case VIRTIO_BLK_S_OK:119 case VIRTIO_BLK_S_OK:
96 return BLK_STS_OK;120 return BLK_STS_OK;
97 case VIRTIO_BLK_S_UNSUPP:121 case VIRTIO_BLK_S_UNSUPP:
98 return BLK_STS_NOTSUPP;122 return BLK_STS_NOTSUPP;
123 case VIRTIO_BLK_S_ZONE_OPEN_RESOURCE:
124 return BLK_STS_ZONE_OPEN_RESOURCE;
125 case VIRTIO_BLK_S_ZONE_ACTIVE_RESOURCE:
126 return BLK_STS_ZONE_ACTIVE_RESOURCE;
127 case VIRTIO_BLK_S_IOERR:
128 case VIRTIO_BLK_S_ZONE_UNALIGNED_WP:
99 default:129 default:
100 return BLK_STS_IOERR;130 return BLK_STS_IOERR;
101 }131 }
@@ -111,11 +141,11 @@ static inline struct virtio_blk_vq *get_virtio_blk_vq(struct blk_mq_hw_ctx *hctx · 9 unmodified lines
111 141
112static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)142static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr)
113{143{
114 struct scatterlist hdr, status, *sgs[3];144 struct scatterlist out_hdr, in_hdr, *sgs[3];
115 unsigned int num_out = 0, num_in = 0;145 unsigned int num_out = 0, num_in = 0;
116 146
117 sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr));147 sg_init_one(&out_hdr, &vbr->out_hdr, sizeof(vbr->out_hdr));
118 sgs[num_out++] = &hdr;148 sgs[num_out++] = &out_hdr;
119 149
120 if (vbr->sg_table.nents) {150 if (vbr->sg_table.nents) {
121 if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT))151 if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT))
@@ -124,8 +154,8 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr) · 2 unmodified lines
124 sgs[num_out + num_in++] = vbr->sg_table.sgl;154 sgs[num_out + num_in++] = vbr->sg_table.sgl;
125 }155 }
126 156
127 sg_init_one(&status, &vbr->status, sizeof(vbr->status));157 sg_init_one(&in_hdr, &vbr->status, vbr->in_hdr_len);
128 sgs[num_out + num_in++] = &status;158 sgs[num_out + num_in++] = &in_hdr;
129 159
130 return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);160 return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
131}161}
@@ -214,21 +244,22 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, · 82 unmodified lines
214 struct request *req,244 struct request *req,
215 struct virtblk_req *vbr)245 struct virtblk_req *vbr)
216{246{
247 size_t in_hdr_len = sizeof(vbr->status);
217 bool unmap = false;248 bool unmap = false;
218 u32 type;249 u32 type;
250 u64 sector = 0;
219 251
220 vbr->out_hdr.sector = 0;252 /* Set fields for all request types */
253 vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));
221 254
222 switch (req_op(req)) {255 switch (req_op(req)) {
223 case REQ_OP_READ:256 case REQ_OP_READ:
224 type = VIRTIO_BLK_T_IN;257 type = VIRTIO_BLK_T_IN;
225 vbr->out_hdr.sector = cpu_to_virtio64(vdev,258 sector = blk_rq_pos(req);
226 blk_rq_pos(req));
227 break;259 break;
228 case REQ_OP_WRITE:260 case REQ_OP_WRITE:
229 type = VIRTIO_BLK_T_OUT;261 type = VIRTIO_BLK_T_OUT;
230 vbr->out_hdr.sector = cpu_to_virtio64(vdev,262 sector = blk_rq_pos(req);
231 blk_rq_pos(req));
232 break;263 break;
233 case REQ_OP_FLUSH:264 case REQ_OP_FLUSH:
234 type = VIRTIO_BLK_T_FLUSH;265 type = VIRTIO_BLK_T_FLUSH;
@@ -243,16 +274,42 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, · 8 unmodified lines
243 case REQ_OP_SECURE_ERASE:274 case REQ_OP_SECURE_ERASE:
244 type = VIRTIO_BLK_T_SECURE_ERASE;275 type = VIRTIO_BLK_T_SECURE_ERASE;
245 break;276 break;
246 case REQ_OP_DRV_IN:277 case REQ_OP_ZONE_OPEN:
247 type = VIRTIO_BLK_T_GET_ID;278 type = VIRTIO_BLK_T_ZONE_OPEN;
279 sector = blk_rq_pos(req);
280 break;
281 case REQ_OP_ZONE_CLOSE:
282 type = VIRTIO_BLK_T_ZONE_CLOSE;
283 sector = blk_rq_pos(req);
284 break;
285 case REQ_OP_ZONE_FINISH:
286 type = VIRTIO_BLK_T_ZONE_FINISH;
287 sector = blk_rq_pos(req);
288 break;
289 case REQ_OP_ZONE_APPEND:
290 type = VIRTIO_BLK_T_ZONE_APPEND;
291 sector = blk_rq_pos(req);
292 in_hdr_len = sizeof(vbr->zone_append_in_hdr);
248 break;293 break;
294 case REQ_OP_ZONE_RESET:
295 type = VIRTIO_BLK_T_ZONE_RESET;
296 sector = blk_rq_pos(req);
297 break;
298 case REQ_OP_ZONE_RESET_ALL:
299 type = VIRTIO_BLK_T_ZONE_RESET_ALL;
300 break;
301 case REQ_OP_DRV_IN:
302 /* Out header already filled in, nothing to do */
303 return 0;
249 default:304 default:
250 WARN_ON_ONCE(1);305 WARN_ON_ONCE(1);
251 return BLK_STS_IOERR;306 return BLK_STS_IOERR;
252 }307 }
253 308
309 /* Set fields for non-REQ_OP_DRV_IN request types */
310 vbr->in_hdr_len = in_hdr_len;
254 vbr->out_hdr.type = cpu_to_virtio32(vdev, type);311 vbr->out_hdr.type = cpu_to_virtio32(vdev, type);
255 vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req));312 vbr->out_hdr.sector = cpu_to_virtio64(vdev, sector);
256 313
257 if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES ||314 if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES ||
258 type == VIRTIO_BLK_T_SECURE_ERASE) {315 type == VIRTIO_BLK_T_SECURE_ERASE) {
@@ -266,10 +323,15 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, · 7 unmodified lines
266static inline void virtblk_request_done(struct request *req)323static inline void virtblk_request_done(struct request *req)
267{324{
268 struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);325 struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
326 int status = virtblk_result(vbr->status);
269 327
270 virtblk_unmap_data(req, vbr);328 virtblk_unmap_data(req, vbr);
271 virtblk_cleanup_cmd(req);329 virtblk_cleanup_cmd(req);
272 blk_mq_end_request(req, virtblk_result(vbr));330
331 if (req_op(req) == REQ_OP_ZONE_APPEND)
332 req->__sector = le64_to_cpu(vbr->zone_append_in_hdr.append_sector);
333
334 blk_mq_end_request(req, status);
273}335}
274 336
275static void virtblk_done(struct virtqueue *vq)337static void virtblk_done(struct virtqueue *vq)
@@ -457,6 +519,275 @@ static void virtio_queue_rqs(struct request **rqlist) · 181 unmodified lines
457 *rqlist = requeue_list;519 *rqlist = requeue_list;
458}520}
459 521
522#ifdef CONFIG_BLK_DEV_ZONED
523static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk,
524 unsigned int nr_zones,
525 unsigned int zone_sectors,
526 size_t *buflen)
527{
528 struct request_queue *q = vblk->disk->queue;
529 size_t bufsize;
530 void *buf;
531
532 nr_zones = min_t(unsigned int, nr_zones,
533 get_capacity(vblk->disk) >> ilog2(zone_sectors));
534
535 bufsize = sizeof(struct virtio_blk_zone_report) +
536 nr_zones * sizeof(struct virtio_blk_zone_descriptor);
537 bufsize = min_t(size_t, bufsize,
538 queue_max_hw_sectors(q) << SECTOR_SHIFT);
539 bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT);
540
541 while (bufsize >= sizeof(struct virtio_blk_zone_report)) {
542 buf = __vmalloc(bufsize, GFP_KERNEL | __GFP_NORETRY);
543 if (buf) {
544 *buflen = bufsize;
545 return buf;
546 }
547 bufsize >>= 1;
548 }
549
550 return NULL;
551}
552
553static int virtblk_submit_zone_report(struct virtio_blk *vblk,
554 char *report_buf, size_t report_len,
555 sector_t sector)
556{
557 struct request_queue *q = vblk->disk->queue;
558 struct request *req;
559 struct virtblk_req *vbr;
560 int err;
561
562 req = blk_mq_alloc_request(q, REQ_OP_DRV_IN, 0);
563 if (IS_ERR(req))
564 return PTR_ERR(req);
565
566 vbr = blk_mq_rq_to_pdu(req);
567 vbr->in_hdr_len = sizeof(vbr->status);
568 vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT);
569 vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector);
570
571 err = blk_rq_map_kern(q, req, report_buf, report_len, GFP_KERNEL);
572 if (err)
573 goto out;
574
575 blk_execute_rq(req, false);
576 err = blk_status_to_errno(virtblk_result(vbr->status));
577out:
578 blk_mq_free_request(req);
579 return err;
580}
581
582static int virtblk_parse_zone(struct virtio_blk *vblk,
583 struct virtio_blk_zone_descriptor *entry,
584 unsigned int idx, unsigned int zone_sectors,
585 report_zones_cb cb, void *data)
586{
587 struct blk_zone zone = { };
588
589 if (entry->z_type != VIRTIO_BLK_ZT_SWR &&
590 entry->z_type != VIRTIO_BLK_ZT_SWP &&
591 entry->z_type != VIRTIO_BLK_ZT_CONV) {
592 dev_err(&vblk->vdev->dev, "invalid zone type %#x\n",
593 entry->z_type);
594 return -EINVAL;
595 }
596
597 zone.type = entry->z_type;
598 zone.cond = entry->z_state;
599 zone.len = zone_sectors;
600 zone.capacity = le64_to_cpu(entry->z_cap);
601 zone.start = le64_to_cpu(entry->z_start);
602 if (zone.cond == BLK_ZONE_COND_FULL)
603 zone.wp = zone.start + zone.len;
604 else
605 zone.wp = le64_to_cpu(entry->z_wp);
606
607 return cb(&zone, idx, data);
608}
609
610static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
611 unsigned int nr_zones, report_zones_cb cb,
612 void *data)
613{
614 struct virtio_blk *vblk = disk->private_data;
615 struct virtio_blk_zone_report *report;
616 unsigned int zone_sectors = vblk->zone_sectors;
617 unsigned int nz, i;
618 int ret, zone_idx = 0;
619 size_t buflen;
620
621 if (WARN_ON_ONCE(!vblk->zone_sectors))
622 return -EOPNOTSUPP;
623
624 report = virtblk_alloc_report_buffer(vblk, nr_zones,
625 zone_sectors, &buflen);
626 if (!report)
627 return -ENOMEM;
628
629 while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) {
630 memset(report, 0, buflen);
631
632 ret = virtblk_submit_zone_report(vblk, (char *)report,
633 buflen, sector);
634 if (ret) {
635 if (ret > 0)
636 ret = -EIO;
637 goto out_free;
638 }
639 nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones);
640 if (!nz)
641 break;
642
643 for (i = 0; i < nz && zone_idx < nr_zones; i++) {
644 ret = virtblk_parse_zone(vblk, &report->zones[i],
645 zone_idx, zone_sectors, cb, data);
646 if (ret)
647 goto out_free;
648 sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors;
649 zone_idx++;
650 }
651 }
652
653 if (zone_idx > 0)
654 ret = zone_idx;
655 else
656 ret = -EINVAL;
657out_free:
658 kvfree(report);
659 return ret;
660}
661
662static void virtblk_revalidate_zones(struct virtio_blk *vblk)
663{
664 u8 model;
665
666 if (!vblk->zone_sectors)
667 return;
668
669 virtio_cread(vblk->vdev, struct virtio_blk_config,
670 zoned.model, &model);
671 if (!blk_revalidate_disk_zones(vblk->disk, NULL))
672 set_capacity_and_notify(vblk->disk, 0);
673}
674
675static int virtblk_probe_zoned_device(struct virtio_device *vdev,
676 struct virtio_blk *vblk,
677 struct request_queue *q)
678{
679 u32 v;
680 u8 model;
681 int ret;
682
683 virtio_cread(vdev, struct virtio_blk_config,
684 zoned.model, &model);
685
686 switch (model) {
687 case VIRTIO_BLK_Z_NONE:
688 return 0;
689 case VIRTIO_BLK_Z_HM:
690 break;
691 case VIRTIO_BLK_Z_HA:
692 /*
693 * Present the host-aware device as a regular drive.
694 * TODO It is possible to add an option to make it appear
695 * in the system as a zoned drive.
696 */
697 return 0;
698 default:
699 dev_err(&vdev->dev, "unsupported zone model %d\n", model);
700 return -EINVAL;
701 }
702
703 dev_dbg(&vdev->dev, "probing host-managed zoned device\n");
704
705 disk_set_zoned(vblk->disk, BLK_ZONED_HM);
706 blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
707
708 virtio_cread(vdev, struct virtio_blk_config,
709 zoned.max_open_zones, &v);
710 disk_set_max_open_zones(vblk->disk, le32_to_cpu(v));
711
712 dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v));
713
714 virtio_cread(vdev, struct virtio_blk_config,
715 zoned.max_active_zones, &v);
716 disk_set_max_active_zones(vblk->disk, le32_to_cpu(v));
717 dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v));
718
719 virtio_cread(vdev, struct virtio_blk_config,
720 zoned.write_granularity, &v);
721 if (!v) {
722 dev_warn(&vdev->dev, "zero write granularity reported\n");
723 return -ENODEV;
724 }
725 blk_queue_physical_block_size(q, le32_to_cpu(v));
726 blk_queue_io_min(q, le32_to_cpu(v));
727
728 dev_dbg(&vdev->dev, "write granularity = %u\n", le32_to_cpu(v));
729
730 /*
731 * virtio ZBD specification doesn't require zones to be a power of
732 * two sectors in size, but the code in this driver expects that.
733 */
734 virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, &v);
735 vblk->zone_sectors = le32_to_cpu(v);
736 if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) {
737 dev_err(&vdev->dev,
738 "zoned device with non power of two zone size %u\n",
739 vblk->zone_sectors);
740 return -ENODEV;
741 }
742 dev_dbg(&vdev->dev, "zone sectors = %u\n", vblk->zone_sectors);
743
744 if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
745 dev_warn(&vblk->vdev->dev,
746 "ignoring negotiated F_DISCARD for zoned device\n");
747 blk_queue_max_discard_sectors(q, 0);
748 }
749
750 ret = blk_revalidate_disk_zones(vblk->disk, NULL);
751 if (!ret) {
752 virtio_cread(vdev, struct virtio_blk_config,
753 zoned.max_append_sectors, &v);
754 if (!v) {
755 dev_warn(&vdev->dev, "zero max_append_sectors reported\n");
756 return -ENODEV;
757 }
758 blk_queue_max_zone_append_sectors(q, le32_to_cpu(v));
759 dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v));
760 }
761
762 return ret;
763}
764
765static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
766{
767 return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED);
768}
769#else
770
771/*
772 * Zoned block device support is not configured in this kernel.
773 * We only need to define a few symbols to avoid compilation errors.
774 */
775#define virtblk_report_zones NULL
776static inline void virtblk_revalidate_zones(struct virtio_blk *vblk)
777{
778}
779static inline int virtblk_probe_zoned_device(struct virtio_device *vdev,
780 struct virtio_blk *vblk, struct request_queue *q)
781{
782 return -EOPNOTSUPP;
783}
784
785static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev)
786{
787 return false;
788}
789#endif /* CONFIG_BLK_DEV_ZONED */
790
460/* return id (s/n) string for *disk to *id_str791/* return id (s/n) string for *disk to *id_str
461 */792 */
462static int virtblk_get_id(struct gendisk *disk, char *id_str)793static int virtblk_get_id(struct gendisk *disk, char *id_str)
@@ -464,18 +795,24 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) · 1 unmodified line
464 struct virtio_blk *vblk = disk->private_data;795 struct virtio_blk *vblk = disk->private_data;
465 struct request_queue *q = vblk->disk->queue;796 struct request_queue *q = vblk->disk->queue;
466 struct request *req;797 struct request *req;
798 struct virtblk_req *vbr;
467 int err;799 int err;
468 800
469 req = blk_mq_alloc_request(q, REQ_OP_DRV_IN, 0);801 req = blk_mq_alloc_request(q, REQ_OP_DRV_IN, 0);
470 if (IS_ERR(req))802 if (IS_ERR(req))
471 return PTR_ERR(req);803 return PTR_ERR(req);
472 804
805 vbr = blk_mq_rq_to_pdu(req);
806 vbr->in_hdr_len = sizeof(vbr->status);
807 vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
808 vbr->out_hdr.sector = 0;
809
473 err = blk_rq_map_kern(q, req, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL);810 err = blk_rq_map_kern(q, req, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL);
474 if (err)811 if (err)
475 goto out;812 goto out;
476 813
477 blk_execute_rq(req, false);814 blk_execute_rq(req, false);
478 err = blk_status_to_errno(virtblk_result(blk_mq_rq_to_pdu(req)));815 err = blk_status_to_errno(virtblk_result(vbr->status));
479out:816out:
480 blk_mq_free_request(req);817 blk_mq_free_request(req);
481 return err;818 return err;
@@ -526,6 +863,7 @@ static const struct block_device_operations virtblk_fops = { · 44 unmodified lines
526 .owner = THIS_MODULE,863 .owner = THIS_MODULE,
527 .getgeo = virtblk_getgeo,864 .getgeo = virtblk_getgeo,
528 .free_disk = virtblk_free_disk,865 .free_disk = virtblk_free_disk,
866 .report_zones = virtblk_report_zones,
529};867};
530 868
531static int index_to_minor(int index)869static int index_to_minor(int index)
@@ -596,6 +934,7 @@ static void virtblk_config_changed_work(struct work_struct *work) · 64 unmodified lines
596 struct virtio_blk *vblk =934 struct virtio_blk *vblk =
597 container_of(work, struct virtio_blk, config_work);935 container_of(work, struct virtio_blk, config_work);
598 936
937 virtblk_revalidate_zones(vblk);
599 virtblk_update_capacity(vblk, true);938 virtblk_update_capacity(vblk, true);
600}939}
601 940
@@ -1152,6 +1491,15 @@ static int virtblk_probe(struct virtio_device *vdev) · 550 unmodified lines
1152 virtblk_update_capacity(vblk, false);1491 virtblk_update_capacity(vblk, false);
1153 virtio_device_ready(vdev);1492 virtio_device_ready(vdev);
1154 1493
1494 if (virtblk_has_zoned_feature(vdev)) {
1495 err = virtblk_probe_zoned_device(vdev, vblk, q);
1496 if (err)
1497 goto out_cleanup_disk;
1498 }
1499
1500 dev_info(&vdev->dev, "blk config size: %zu\n",
1501 sizeof(struct virtio_blk_config));
1502
1155 err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);1503 err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
1156 if (err)1504 if (err)
1157 goto out_cleanup_disk;1505 goto out_cleanup_disk;
@@ -1253,6 +1601,9 @@ static unsigned int features[] = { · 95 unmodified lines
1253 VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,1601 VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
1254 VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,1602 VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES,
1255 VIRTIO_BLK_F_SECURE_ERASE,1603 VIRTIO_BLK_F_SECURE_ERASE,
1604#ifdef CONFIG_BLK_DEV_ZONED
1605 VIRTIO_BLK_F_ZONED,
1606#endif /* CONFIG_BLK_DEV_ZONED */
1256};1607};
1257 1608
1258static struct virtio_driver virtio_blk = {1609static struct virtio_driver virtio_blk = {
include/uapi/linux/virtio_blk.h+105−0
@@ -41,6 +41,7 @@ · 40 unmodified lines
41#define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */41#define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */
42#define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */42#define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */
43#define VIRTIO_BLK_F_SECURE_ERASE 16 /* Secure Erase is supported */43#define VIRTIO_BLK_F_SECURE_ERASE 16 /* Secure Erase is supported */
44#define VIRTIO_BLK_F_ZONED 17 /* Zoned block device */
44 45
45/* Legacy feature bits */46/* Legacy feature bits */
46#ifndef VIRTIO_BLK_NO_LEGACY47#ifndef VIRTIO_BLK_NO_LEGACY
@@ -137,6 +138,16 @@ struct virtio_blk_config { · 90 unmodified lines
137 /* Secure erase commands must be aligned to this number of sectors. */138 /* Secure erase commands must be aligned to this number of sectors. */
138 __virtio32 secure_erase_sector_alignment;139 __virtio32 secure_erase_sector_alignment;
139 140
141 /* Zoned block device characteristics (if VIRTIO_BLK_F_ZONED) */
142 struct virtio_blk_zoned_characteristics {
143 __virtio32 zone_sectors;
144 __virtio32 max_open_zones;
145 __virtio32 max_active_zones;
146 __virtio32 max_append_sectors;
147 __virtio32 write_granularity;
148 __u8 model;
149 __u8 unused2[3];
150 } zoned;
140} __attribute__((packed));151} __attribute__((packed));
141 152
142/*153/*
@@ -174,6 +185,27 @@ struct virtio_blk_config { · 31 unmodified lines
174/* Secure erase command */185/* Secure erase command */
175#define VIRTIO_BLK_T_SECURE_ERASE 14186#define VIRTIO_BLK_T_SECURE_ERASE 14
176 187
188/* Zone append command */
189#define VIRTIO_BLK_T_ZONE_APPEND 15
190
191/* Report zones command */
192#define VIRTIO_BLK_T_ZONE_REPORT 16
193
194/* Open zone command */
195#define VIRTIO_BLK_T_ZONE_OPEN 18
196
197/* Close zone command */
198#define VIRTIO_BLK_T_ZONE_CLOSE 20
199
200/* Finish zone command */
201#define VIRTIO_BLK_T_ZONE_FINISH 22
202
203/* Reset zone command */
204#define VIRTIO_BLK_T_ZONE_RESET 24
205
206/* Reset All zones command */
207#define VIRTIO_BLK_T_ZONE_RESET_ALL 26
208
177#ifndef VIRTIO_BLK_NO_LEGACY209#ifndef VIRTIO_BLK_NO_LEGACY
178/* Barrier before this op. */210/* Barrier before this op. */
179#define VIRTIO_BLK_T_BARRIER 0x80000000211#define VIRTIO_BLK_T_BARRIER 0x80000000
@@ -193,6 +225,72 @@ struct virtio_blk_outhdr { · 13 unmodified lines
193 __virtio64 sector;225 __virtio64 sector;
194};226};
195 227
228/*
229 * Supported zoned device models.
230 */
231
232/* Regular block device */
233#define VIRTIO_BLK_Z_NONE 0
234/* Host-managed zoned device */
235#define VIRTIO_BLK_Z_HM 1
236/* Host-aware zoned device */
237#define VIRTIO_BLK_Z_HA 2
238
239/*
240 * Zone descriptor. A part of VIRTIO_BLK_T_ZONE_REPORT command reply.
241 */
242struct virtio_blk_zone_descriptor {
243 /* Zone capacity */
244 __virtio64 z_cap;
245 /* The starting sector of the zone */
246 __virtio64 z_start;
247 /* Zone write pointer position in sectors */
248 __virtio64 z_wp;
249 /* Zone type */
250 __u8 z_type;
251 /* Zone state */
252 __u8 z_state;
253 __u8 reserved[38];
254};
255
256struct virtio_blk_zone_report {
257 __virtio64 nr_zones;
258 __u8 reserved[56];
259 struct virtio_blk_zone_descriptor zones[];
260};
261
262/*
263 * Supported zone types.
264 */
265
266/* Conventional zone */
267#define VIRTIO_BLK_ZT_CONV 1
268/* Sequential Write Required zone */
269#define VIRTIO_BLK_ZT_SWR 2
270/* Sequential Write Preferred zone */
271#define VIRTIO_BLK_ZT_SWP 3
272
273/*
274 * Zone states that are available for zones of all types.
275 */
276
277/* Not a write pointer (conventional zones only) */
278#define VIRTIO_BLK_ZS_NOT_WP 0
279/* Empty */
280#define VIRTIO_BLK_ZS_EMPTY 1
281/* Implicitly Open */
282#define VIRTIO_BLK_ZS_IOPEN 2
283/* Explicitly Open */
284#define VIRTIO_BLK_ZS_EOPEN 3
285/* Closed */
286#define VIRTIO_BLK_ZS_CLOSED 4
287/* Read-Only */
288#define VIRTIO_BLK_ZS_RDONLY 13
289/* Full */
290#define VIRTIO_BLK_ZS_FULL 14
291/* Offline */
292#define VIRTIO_BLK_ZS_OFFLINE 15
293
196/* Unmap this range (only valid for write zeroes command) */294/* Unmap this range (only valid for write zeroes command) */
197#define VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP 0x00000001295#define VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP 0x00000001
198 296
@@ -219,4 +317,11 @@ struct virtio_scsi_inhdr { · 20 unmodified lines
219#define VIRTIO_BLK_S_OK 0317#define VIRTIO_BLK_S_OK 0
220#define VIRTIO_BLK_S_IOERR 1318#define VIRTIO_BLK_S_IOERR 1
221#define VIRTIO_BLK_S_UNSUPP 2319#define VIRTIO_BLK_S_UNSUPP 2
320
321/* Error codes that are specific to zoned block devices */
322#define VIRTIO_BLK_S_ZONE_INVALID_CMD 3
323#define VIRTIO_BLK_S_ZONE_UNALIGNED_WP 4
324#define VIRTIO_BLK_S_ZONE_OPEN_RESOURCE 5
325#define VIRTIO_BLK_S_ZONE_ACTIVE_RESOURCE 6
326
222#endif /* _LINUX_VIRTIO_BLK_H */327#endif /* _LINUX_VIRTIO_BLK_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t