Stefan Hajnoczi
2021-Apr-12 09:17 UTC
[PATCH] virtio_blk: Add support for lifetime feature
On Tue, Mar 30, 2021 at 11:16:02PM +0000, Enrico Granata wrote:> The VirtIO TC has adopted a new feature in virtio-blk enabling > discovery of lifetime information. > > This commit adds support for the VIRTIO_BLK_T_LIFETIME command > to the virtio_blk driver, and adds two new attributes to the > sysfs entry for virtio_blk: > * pre_eol_info > * life_time > > which are defined in the same manner as the files of the same name > for the eMMC driver, in line with the VirtIO specification. > > Signed-off-by: Enrico Granata <egranata at google.com> > --- > drivers/block/virtio_blk.c | 76 ++++++++++++++++++++++++++++++++- > include/uapi/linux/virtio_blk.h | 11 +++++ > 2 files changed, 86 insertions(+), 1 deletion(-) > > diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c > index b9fa3ef5b57c..1fc0ec000b4f 100644 > --- a/drivers/block/virtio_blk.c > +++ b/drivers/block/virtio_blk.c > @@ -246,7 +246,7 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx, > unmap = !(req->cmd_flags & REQ_NOUNMAP); > break; > case REQ_OP_DRV_IN: > - type = VIRTIO_BLK_T_GET_ID; > + type = vbr->out_hdr.type;This patch changes the endianness of vbr->out_hdr.type from virtio-endian to cpu endian before virtio_queue_rq. That is error-prone because someone skimming through the code will see some accesses with cpu_to_virtio32() and others without it. They would have to audit the code carefully to understand what is going on. The following is cleaner: case REQ_OP_DRV_IN: break; /* type already set for custom requests */ ... if (req_op(req) != REQ_OP_DRV_IN) vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, type); Now vbr->out_hdr.type is virtio-endian everywhere. If we need to support REQ_OP_DRV_OUT in the future it can use the same approach. virtblk_get_id() and virtblk_get_lifetime() would be updated like this: vbreq->out_hdr.type = cpu_to_virtio32(VIRTIO_BLK_T_GET_*);> break; > default: > WARN_ON_ONCE(1); > @@ -310,11 +310,14 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) > struct virtio_blk *vblk = disk->private_data; > struct request_queue *q = vblk->disk->queue; > struct request *req; > + struct virtblk_req *vbreq;It's called vbr elsewhere in the driver. It would be nice to keep naming consistent.> int err; > > req = blk_get_request(q, REQ_OP_DRV_IN, 0); > if (IS_ERR(req)) > return PTR_ERR(req); > + vbreq = blk_mq_rq_to_pdu(req); > + vbreq->out_hdr.type = VIRTIO_BLK_T_GET_ID; > > err = blk_rq_map_kern(q, req, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL); > if (err) > @@ -327,6 +330,34 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) > return err; > } > > +static int virtblk_get_lifetime(struct gendisk *disk, struct virtio_blk_lifetime *lifetime) > +{ > + struct virtio_blk *vblk = disk->private_data; > + struct request_queue *q = vblk->disk->queue; > + struct request *req; > + struct virtblk_req *vbreq; > + int err; > + > + if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_LIFETIME)) > + return -EOPNOTSUPP; > + > + req = blk_get_request(q, REQ_OP_DRV_IN, 0); > + if (IS_ERR(req)) > + return PTR_ERR(req); > + vbreq = blk_mq_rq_to_pdu(req); > + vbreq->out_hdr.type = VIRTIO_BLK_T_GET_LIFETIME; > + > + err = blk_rq_map_kern(q, req, lifetime, sizeof(*lifetime), GFP_KERNEL); > + if (err) > + goto out; > + > + blk_execute_rq(vblk->disk, req, false); > + err = blk_status_to_errno(virtblk_result(blk_mq_rq_to_pdu(req))); > +out: > + blk_put_request(req); > + return err; > +} > + > static void virtblk_get(struct virtio_blk *vblk) > { > refcount_inc(&vblk->refs); > @@ -435,6 +466,46 @@ static ssize_t serial_show(struct device *dev, > > static DEVICE_ATTR_RO(serial); > > +static ssize_t pre_eol_info_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct gendisk *disk = dev_to_disk(dev); > + struct virtio_blk_lifetime lft; > + int err; > + > + /* sysfs gives us a PAGE_SIZE buffer */ > + BUILD_BUG_ON(sizeof(lft) >= PAGE_SIZE);Why is this necessary? In serial_show() it protects against a buffer overflow. That's not the case here since sprintf() is used to write to buf and the size of lft doesn't really matter. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: <http://lists.linuxfoundation.org/pipermail/virtualization/attachments/20210412/1038e477/attachment.sig>
Christoph Hellwig
2021-Apr-12 09:42 UTC
[PATCH] virtio_blk: Add support for lifetime feature
A note to the virtio committee: eMMC is the worst of all the currently active storage standards by a large margin. It defines very strange ad-hoc interfaces that expose very specific internals and often provides very poor abstractions. It would be great it you could reach out to the wider storage community before taking bad ideas from the eMMC standard and putting it into virtio.