Skip to contentSkip to conversation

virtio block device

PATCH In review Anthony Liguori 2 participants 3 messages Dec 4, 2007 – Dec 5, 2007 Kbuild

lore
Share & tools
lore
#0 lore raw

PATCH 3/3 virtio block device

Subject: [PATCH 3/3] virtio block device
Cc: Rusty Russell <[email protected]>
Cc: Avi Kivity <[email protected]>
Cc: Dor Laor <[email protected]>

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).

Makefile.target +1 -1
Index: qemu/Makefile.target
===================================================================
@@ -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
hw/virtio-blk.c new file +163 -0

163 lines not on this page · raw message

sysemu.h +1 -1
Index: qemu/sysemu.h
===================================================================
@@ -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 {
hw/pc.c +12 -0
Index: qemu/hw/pc.c
===================================================================
@@ -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,
hw/pc.h +4 -0
Index: qemu/hw/pc.h
===================================================================
@@ -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
vl.c +4 -0
Index: qemu/vl.c
===================================================================
@@ -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])
#1 lore raw

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.

===================================================================

sysemu.h +0 -0
@@ -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 {

hw/pc.c +0 -0
Index: qemu/hw/pc.c
===================================================================
@@ -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.

#2 lore raw
Quoted 55 lines · Dor Laor

Anthony Liguori wrote:

Subject: [PATCH 3/3] virtio block device

(quoted diff) +49 -0
+
+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);
+    }
Quoted 2 lines

The notify here should also be outside the while loop.

Yeah, that's in the optimization patch.

Quoted 32 lines

===================================================================

sysemu.h +1 -1
@@ -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
===================================================================

hw/pc.c +8 -0
@@ -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,
 
 
 
Quoted 2 lines

The pci vendor id should be identical to the network (0x6900)

Indeed! That's for catching that.

Regards,

Anthony Liguori

Quoted 4 lines

regards,
Dor.