This is fairly simple: we create a request pointing at the 1k kmalloc,
then just change the type so our do_req() knows to mark it as a GET_ID
for the server.

Seems to work here; the only issue is that the error didn't get passed
back from __blk_end_request_all to blk_execute_rq, so we set ->errors
to 1 on error.

Signed-off-by: Rusty Russell <[email protected]>
Cc: Jens Axboe <[email protected]>
---
 drivers/block/virtio_blk.c |   66 +++++++++++++++++++++++++++++++++++----------
 include/linux/virtio_blk.h |    4 ++
 2 files changed, 56 insertions(+), 14 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -72,6 +72,8 @@ static void blk_done(struct virtqueue *v
                        vbr->req->sense_len = vbr->in_hdr.sense_len;
                        vbr->req->errors = vbr->in_hdr.errors;
                }
+               if (blk_special_request(vbr->req))
+                       vbr->req->errors = (error != 0);
 
                __blk_end_request_all(vbr->req, error);
                list_del(&vbr->list);
@@ -105,6 +107,11 @@ static bool do_req(struct request_queue 
                vbr->out_hdr.sector = 0;
                vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
                break;
+       case REQ_TYPE_SPECIAL:
+               vbr->out_hdr.type = VIRTIO_BLK_T_GET_ID;
+               vbr->out_hdr.sector = 0;
+               vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
+               break;
        case REQ_TYPE_LINUX_BLOCK:
                if (req->cmd[0] == REQ_LB_OP_FLUSH) {
                        vbr->out_hdr.type = VIRTIO_BLK_T_FLUSH;
@@ -201,29 +208,59 @@ struct virtio_blk_config_deprecated {
        __u8 identify[VIRTIO_BLK_ID_BYTES];
 } __attribute__((packed));
 
-static int virtblk_identify(struct gendisk *disk, void *argp)
+static int virtblk_identify_deprecated(struct virtio_blk *vblk, void *opaque)
+{
+       return virtio_config_buf(vblk->vdev, VIRTIO_BLK_F_IDENTIFY,
+               offsetof(struct virtio_blk_config_deprecated, identify), opaque,
+               VIRTIO_BLK_ID_BYTES);
+}
+
+static int virtblk_get_id(struct virtio_blk *vblk, void *opaque)
+{
+       struct request *req;
+       struct bio *bio;
+
+       bio = bio_map_kern(vblk->disk->queue, opaque, VIRTIO_BLK_ID_BYTES,
+                          GFP_KERNEL);
+       if (IS_ERR(bio))
+               return PTR_ERR(bio);
+
+       req = blk_make_request(vblk->disk->queue, bio, GFP_KERNEL);
+       if (IS_ERR(req)) {
+               bio_put(bio);
+               return PTR_ERR(req);
+       }
+
+       /* This is actually a special request. */
+       req->cmd_type = REQ_TYPE_SPECIAL;
+       return blk_execute_rq(vblk->disk->queue, vblk->disk, req, false);
+}
+
+static int virtblk_identify(struct gendisk *disk, void __user *argp)
 {
        struct virtio_blk *vblk = disk->private_data;
        void *opaque;
-       int err = -ENOMEM;
+       int err;
 
        opaque = kmalloc(VIRTIO_BLK_ID_BYTES, GFP_KERNEL);
        if (!opaque)
-               goto out;
+               return -ENOMEM;
 
-       err = virtio_config_buf(vblk->vdev, VIRTIO_BLK_F_IDENTIFY,
-               offsetof(struct virtio_blk_config_deprecated, identify), opaque,
-               VIRTIO_BLK_ID_BYTES);
+       /* The modern way. */
+       if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_GET_ID))
+               err = virtblk_get_id(vblk, opaque);
+       /* The deprecated way. */
+       else if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_IDENTIFY))
+               err = virtblk_identify_deprecated(vblk, opaque);
+       /* No way. */
+       else
+               err = -ENOTTY;
 
-       if (err)
-               goto out_kfree;
+       if (!err)
+               if (copy_to_user(argp, opaque, VIRTIO_BLK_ID_BYTES))
+                       err = -EFAULT;
 
-       if (copy_to_user(argp, opaque, VIRTIO_BLK_ID_BYTES))
-               err = -EFAULT;
-
-out_kfree:
        kfree(opaque);
-out:
        return err;
 }
 
@@ -460,7 +497,8 @@ static struct virtio_device_id id_table[
 static unsigned int features[] = {
        VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
        VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
-       VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY, VIRTIO_BLK_F_FLUSH
+       VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY, VIRTIO_BLK_F_FLUSH,
+       VIRTIO_BLK_F_GET_ID
 };
 
 /*
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h
--- a/include/linux/virtio_blk.h
+++ b/include/linux/virtio_blk.h
@@ -15,6 +15,7 @@
 #define VIRTIO_BLK_F_SCSI      7       /* Supports scsi command passthru */
 #define VIRTIO_BLK_F_IDENTIFY  8       /* ATA IDENTIFY support (deprecated) */
 #define VIRTIO_BLK_F_FLUSH     9       /* Cache flush command support */
+#define VIRTIO_BLK_F_GET_ID    10      /* VIRTIO_BLK_T_GET_ID support */
 
 #define VIRTIO_BLK_ID_BYTES    (sizeof(__u16[256]))    /* IDENTIFY DATA */
 
@@ -65,6 +66,9 @@ struct virtio_blk_config {
 /* Cache flush command */
 #define VIRTIO_BLK_T_FLUSH     4
 
+/* Get ID command */
+#define VIRTIO_BLK_T_GET_ID    8
+
 /* Barrier before this op. */
 #define VIRTIO_BLK_T_BARRIER   0x80000000
 

_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/virtualization

Reply via email to