qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Anthony Liguori <aliguori@us.ibm.com>
To: qemu-devel@nongnu.org, Avi Kivity <avi@qumranet.com>,
	Dor Laor <dor.laor@qumranet.com>,
	Rusty Russell <rusty@rustcorp.com.au>
Subject: [Qemu-devel] [PATCH 3/3] virtio block device
Date: Tue, 04 Dec 2007 15:54:53 -0600	[thread overview]
Message-ID: <4755CCAD.7010403@us.ibm.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 3 bytes --]





[-- Attachment #2: virtio-blk.diff --]
[-- Type: text/x-patch, Size: 7217 bytes --]

Subject: [PATCH 3/3] virtio block device
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Avi Kivity <avi@qumranet.com>
Cc: Dor Laor <dor.laor@qumranet.com>

This patch implements the backend support for the virtio block device.  It's
designed to support in-order queueing of a virtually unlimited size so it will
be able to perform better than SCSI.  Besides performance, the virtio block
interface passes through guest SCSI commands so it can be used to expose any
type of block device (although only normal disks are supported in this patch).

Index: qemu/Makefile.target
===================================================================
--- qemu.orig/Makefile.target	2007-12-04 14:17:37.000000000 -0600
+++ qemu/Makefile.target	2007-12-04 14:18:57.000000000 -0600
@@ -436,7 +436,7 @@
 VL_OBJS += rtl8139.o
 
 # virtio devices
-VL_OBJS += virtio.o virtio-net.o
+VL_OBJS += virtio.o virtio-net.o virtio-blk.o
 
 ifeq ($(TARGET_BASE_ARCH), i386)
 # Hardware support
Index: qemu/hw/virtio-blk.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ qemu/hw/virtio-blk.c	2007-12-04 14:22:36.000000000 -0600
@@ -0,0 +1,163 @@
+/*
+ * Virtio Block Device
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio.h"
+#include "block.h"
+#include "pc.h"
+
+/* from Linux's linux/virtio_blk.h */
+
+/* The ID for virtio_block */
+#define VIRTIO_ID_BLOCK	2
+
+/* Feature bits */
+#define VIRTIO_BLK_F_BARRIER	0	/* Does host support barriers? */
+#define VIRTIO_BLK_F_SIZE_MAX	1	/* Indicates maximum segment size */
+#define VIRTIO_BLK_F_SEG_MAX	2	/* Indicates maximum # of segments */
+
+struct virtio_blk_config
+{
+    uint64_t capacity;
+    uint32_t size_max;
+    uint32_t seg_max;
+};
+
+/* These two define direction. */
+#define VIRTIO_BLK_T_IN		0
+#define VIRTIO_BLK_T_OUT	1
+
+/* This bit says it's a scsi command, not an actual read or write. */
+#define VIRTIO_BLK_T_SCSI_CMD	2
+
+/* Barrier before this op. */
+#define VIRTIO_BLK_T_BARRIER	0x80000000
+
+/* This is the first element of the read scatter-gather list. */
+struct virtio_blk_outhdr
+{
+    /* VIRTIO_BLK_T* */
+    uint32_t type;
+    /* io priority. */
+    uint32_t ioprio;
+    /* Sector (ie. 512 byte offset) */
+    uint64_t sector;
+    /* Where to put reply. */
+    uint64_t id;
+};
+
+#define VIRTIO_BLK_S_OK		0
+#define VIRTIO_BLK_S_IOERR	1
+#define VIRTIO_BLK_S_UNSUPP	2
+
+/* This is the first element of the write scatter-gather list */
+struct virtio_blk_inhdr
+{
+    unsigned char status;
+};
+
+typedef struct VirtIOBlock
+{
+    VirtIODevice vdev;
+    BlockDriverState *bs;
+} VirtIOBlock;
+
+static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
+{
+    return (VirtIOBlock *)vdev;
+}
+
+static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOBlock *s = to_virtio_blk(vdev);
+    VirtQueueElement elem;
+    unsigned int count;
+
+    while ((count = virtqueue_pop(vq, &elem)) != 0) {
+	struct virtio_blk_inhdr *in;
+	struct virtio_blk_outhdr *out;
+	unsigned int wlen;
+	off_t off;
+	int i;
+
+	out = (void *)elem.out_sg[0].iov_base;
+	in = (void *)elem.in_sg[elem.in_num - 1].iov_base;
+	off = out->sector;
+
+	if (out->type & VIRTIO_BLK_T_SCSI_CMD) {
+	    wlen = sizeof(*in);
+	    in->status = VIRTIO_BLK_S_UNSUPP;
+	} else if (out->type & VIRTIO_BLK_T_OUT) {
+	    wlen = sizeof(*in);
+
+	    for (i = 1; i < elem.out_num; i++) {
+		bdrv_write(s->bs, off,
+			   elem.out_sg[i].iov_base,
+			   elem.out_sg[i].iov_len / 512);
+		off += elem.out_sg[i].iov_len / 512;
+	    }
+
+	    in->status = VIRTIO_BLK_S_OK;
+	} else {
+	    wlen = sizeof(*in);
+
+	    for (i = 0; i < elem.in_num - 1; i++) {
+		bdrv_read(s->bs, off,
+			  elem.in_sg[i].iov_base,
+			  elem.in_sg[i].iov_len / 512);
+		off += elem.in_sg[i].iov_len / 512;
+		wlen += elem.in_sg[i].iov_len;
+	    }
+
+	    in->status = VIRTIO_BLK_S_OK;
+	}
+
+	virtqueue_push(vq, &elem, wlen);
+	virtio_notify(vdev, vq);
+    }
+}
+
+static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
+{
+    VirtIOBlock *s = to_virtio_blk(vdev);
+    struct virtio_blk_config blkcfg;
+    int64_t capacity;
+
+    bdrv_get_geometry(s->bs, &capacity);
+    blkcfg.capacity = capacity;
+    blkcfg.seg_max = 128 - 2;
+    memcpy(config, &blkcfg, sizeof(blkcfg));
+}
+
+static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
+{
+    return (1 << VIRTIO_BLK_F_SEG_MAX);
+}
+
+void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
+		      BlockDriverState *bs)
+{
+    VirtIOBlock *s;
+
+    s = (VirtIOBlock *)virtio_init_pci(bus, "virtio-blk", 6900, 0x1001,
+				       0, VIRTIO_ID_BLOCK,
+				       0x01, 0x80, 0x00,
+				       16, sizeof(VirtIOBlock));
+
+    s->vdev.update_config = virtio_blk_update_config;
+    s->vdev.get_features = virtio_blk_get_features;
+    s->bs = bs;
+
+    virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);
+
+    return &s->vdev;
+}
Index: qemu/sysemu.h
===================================================================
--- qemu.orig/sysemu.h	2007-12-04 13:51:49.000000000 -0600
+++ qemu/sysemu.h	2007-12-04 14:18:57.000000000 -0600
@@ -117,7 +117,7 @@
 #endif
 
 typedef enum {
-    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD
+    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO
 } BlockInterfaceType;
 
 typedef struct DriveInfo {
Index: qemu/hw/pc.c
===================================================================
--- qemu.orig/hw/pc.c	2007-12-04 13:51:49.000000000 -0600
+++ qemu/hw/pc.c	2007-12-04 14:18:57.000000000 -0600
@@ -1008,6 +1008,18 @@
 	    }
         }
     }
+
+    /* Add virtio block devices */
+    if (pci_enabled) {
+	int index;
+	int unit_id = 0;
+
+	while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) {
+	    virtio_blk_init(pci_bus, 0x5002, 0x2258,
+			    drives_table[index].bdrv);
+	    unit_id++;
+	}
+    }
 }
 
 static void pc_init_pci(int ram_size, int vga_ram_size,
Index: qemu/hw/pc.h
===================================================================
--- qemu.orig/hw/pc.h	2007-12-04 14:17:37.000000000 -0600
+++ qemu/hw/pc.h	2007-12-04 14:18:57.000000000 -0600
@@ -147,4 +147,8 @@
 void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn);
 
 
+/* virtio-blk.h */
+void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
+		      BlockDriverState *bs);
+
 #endif
Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c	2007-12-04 13:51:49.000000000 -0600
+++ qemu/vl.c	2007-12-04 14:18:57.000000000 -0600
@@ -4918,6 +4918,9 @@
 	} else if (!strcmp(buf, "sd")) {
 	    interface = IF_SD;
             max_devs = 0;
+	} else if (!strcmp(buf, "virtio")) {
+	    interface = IF_VIRTIO;
+	    max_devs = 0;
 	} else {
             fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);
             return -1;
@@ -5088,6 +5091,7 @@
         break;
     case IF_PFLASH:
     case IF_MTD:
+    case IF_VIRTIO:
         break;
     }
     if (!file[0])

             reply	other threads:[~2007-12-04 21:55 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-12-04 21:54 Anthony Liguori [this message]
2007-12-04 23:51 ` [Qemu-devel] Re: [PATCH 3/3] virtio block device Dor Laor
2007-12-05  0:12   ` Anthony Liguori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4755CCAD.7010403@us.ibm.com \
    --to=aliguori@us.ibm.com \
    --cc=avi@qumranet.com \
    --cc=dor.laor@qumranet.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rusty@rustcorp.com.au \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).