qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 3/3] virtio block device


From: Anthony Liguori
Subject: [Qemu-devel] [PATCH 3/3] virtio block device
Date: Tue, 04 Dec 2007 15:54:53 -0600
User-agent: Thunderbird 2.0.0.6 (X11/20071022)




Subject: [PATCH 3/3] virtio block device
Cc: Rusty Russell <address@hidden>
Cc: Avi Kivity <address@hidden>
Cc: Dor Laor <address@hidden>

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   <address@hidden>
+ *
+ * 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 via email to

[Prev in Thread] Current Thread [Next in Thread]