* [Qemu-devel] [PATCH 3/3] virtio block device
@ 2007-12-04 21:54 Anthony Liguori
2007-12-04 23:51 ` [Qemu-devel] " Dor Laor
0 siblings, 1 reply; 3+ messages in thread
From: Anthony Liguori @ 2007-12-04 21:54 UTC (permalink / raw)
To: qemu-devel, Avi Kivity, Dor Laor, Rusty Russell
[-- 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])
^ permalink raw reply [flat|nested] 3+ messages in thread
* [Qemu-devel] Re: [PATCH 3/3] virtio block device
2007-12-04 21:54 [Qemu-devel] [PATCH 3/3] virtio block device Anthony Liguori
@ 2007-12-04 23:51 ` Dor Laor
2007-12-05 0:12 ` Anthony Liguori
0 siblings, 1 reply; 3+ messages in thread
From: Dor Laor @ 2007-12-04 23:51 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Rusty Russell, qemu-devel
[-- Attachment #1: Type: text/plain, Size: 2307 bytes --]
Anthony Liguori wrote:
Subject: [PATCH 3/3] virtio block device
+
+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);
+ }
The notify here should also be outside the while loop.
===================================================================
--- 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,
The pci vendor id should be identical to the network (0x6900)
regards,
Dor.
[-- Attachment #2: Type: text/html, Size: 2847 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
* [Qemu-devel] Re: [PATCH 3/3] virtio block device
2007-12-04 23:51 ` [Qemu-devel] " Dor Laor
@ 2007-12-05 0:12 ` Anthony Liguori
0 siblings, 0 replies; 3+ messages in thread
From: Anthony Liguori @ 2007-12-05 0:12 UTC (permalink / raw)
To: dor.laor; +Cc: Rusty Russell, qemu-devel
Dor Laor wrote:
> Anthony Liguori wrote:
>
> Subject: [PATCH 3/3] virtio block device
> +
> +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);
> + }
>
>
>
> The notify here should also be outside the while loop.
>
Yeah, that's in the optimization patch.
> ===================================================================
> --- 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,
>
>
>
>
> The pci vendor id should be identical to the network (0x6900)
>
Indeed! That's for catching that.
Regards,
Anthony Liguori
> regards,
> Dor.
>
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2007-12-05 0:12 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-12-04 21:54 [Qemu-devel] [PATCH 3/3] virtio block device Anthony Liguori
2007-12-04 23:51 ` [Qemu-devel] " Dor Laor
2007-12-05 0:12 ` Anthony Liguori
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).