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

Re: [Libvir] [PATCH] Add bus attribute to disk target definition



Hi,

sorry for the delay. Here's the newest version of the patch which should
address all the issues that have been raised so far.


=== modified file 'src/qemu_conf.c'
--- old/src/qemu_conf.c	2008-04-30 12:30:55 +0000
+++ new/src/qemu_conf.c	2008-05-06 17:58:44 +0000
@@ -491,6 +491,8 @@
             *flags |= QEMUD_CMD_FLAG_KQEMU;
         if (strstr(help, "-no-reboot"))
             *flags |= QEMUD_CMD_FLAG_NO_REBOOT;
+        if (strstr(help, "\n-drive"))
+            *flags |= QEMUD_CMD_FLAG_DRIVE_OPT;
         if (*version >= 9000)
             *flags |= QEMUD_CMD_FLAG_VNC_COLON;
         ret = 0;
@@ -568,6 +570,7 @@
     xmlChar *source = NULL;
     xmlChar *target = NULL;
     xmlChar *type = NULL;
+    xmlChar *bus = NULL;
     int typ = 0;
 
     type = xmlGetProp(node, BAD_CAST "type");
@@ -598,6 +601,7 @@
             } else if ((target == NULL) &&
                        (xmlStrEqual(cur->name, BAD_CAST "target"))) {
                 target = xmlGetProp(cur, BAD_CAST "dev");
+                bus = xmlGetProp(cur, BAD_CAST "bus");
             } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
                 disk->readonly = 1;
             }
@@ -643,10 +647,9 @@
         disk->readonly = 1;
 
     if ((!device || !strcmp((const char *)device, "disk")) &&
-        strcmp((const char *)target, "hda") &&
-        strcmp((const char *)target, "hdb") &&
-        strcmp((const char *)target, "hdc") &&
-        strcmp((const char *)target, "hdd")) {
+        strncmp((const char *)target, "hd", 2) &&
+        strncmp((const char *)target, "sd", 2) &&
+        strncmp((const char *)target, "vd", 2)) {
         qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                          _("Invalid harddisk device name: %s"), target);
         goto error;
@@ -673,13 +676,28 @@
         goto error;
     }
 
+    if (!bus)
+        disk->bus = QEMUD_DISK_BUS_IDE;
+    else if (STREQ((const char *)bus, "ide"))
+        disk->bus = QEMUD_DISK_BUS_IDE;
+    else if (STREQ((const char *)bus, "scsi"))
+        disk->bus = QEMUD_DISK_BUS_SCSI;
+    else if (STREQ((const char *)bus, "virtio"))
+        disk->bus = QEMUD_DISK_BUS_VIRTIO;
+    else {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("Invalid bus type: %s"), bus);
+        goto error;
+    }
+
     xmlFree(device);
     xmlFree(target);
     xmlFree(source);
+    xmlFree(bus);
 
     return 0;
 
  error:
+    xmlFree(bus);
     xmlFree(type);
     xmlFree(target);
     xmlFree(source);
@@ -1373,6 +1391,68 @@
     return -1;
 }
 
+static int qemudDiskCompare(const void *aptr, const void *bptr) {
+    struct qemud_vm_disk_def *a = (struct qemud_vm_disk_def *) aptr;
+    struct qemud_vm_disk_def *b = (struct qemud_vm_disk_def *) bptr;
+    if (a->device == b->device)
+        return virDiskNameToIndex(a->dst) - virDiskNameToIndex(b->dst);
+    else
+        return a->device - b->device;
+}
+
+static const char *qemudBusIdToName(int busId) {
+    const char *busnames[] = { "ide",
+                                "scsi",
+                                "virtio" };
+
+	if (busId >= 0 && busId < 3)
+	    return busnames[busId];
+	else
+		return 0;
+}
+
+static char *qemudDriveOpt(struct qemud_vm_disk_def *disk, int boot)
+{
+    char opt[PATH_MAX];
+
+    switch (disk->device) {
+        case QEMUD_DISK_CDROM:
+            snprintf(opt, PATH_MAX, "file=%s,if=ide,media=cdrom%s",
+                          disk->src, boot ? ",boot=on" : "");
+        break;
+        case QEMUD_DISK_FLOPPY:
+            snprintf(opt, PATH_MAX, "file=%s,if=floppy%s",
+                          disk->src, boot ? ",boot=on" : "");
+        break;
+        case QEMUD_DISK_DISK:
+            snprintf(opt, PATH_MAX, "file=%s,if=%s%s",
+                          disk->src, qemudBusIdToName(disk->bus), boot ? ",boot=on" : "");
+        break;
+        default:
+            return 0;
+    }
+    return strdup(opt);
+}
+
+static char *qemudAddBootDrive(virConnectPtr conn,
+                                struct qemud_vm_def *def,
+                            	char *handledDisks,
+                            	int type) {
+    int j = 0;
+    struct qemud_vm_disk_def *disk = def->disks;
+
+    while (disk) {
+        if (!handledDisks[j] && disk->device == type) {
+            handledDisks[j] = 1;
+            return qemudDriveOpt(disk, 1);
+        }
+        j++;
+        disk = disk->next;
+    }
+    qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         "Requested boot device type %d, but no such device defined.", type);
+    return 0;
+}
 
 /*
  * Parses a libvirt XML definition of a guest, and populates the
@@ -1762,7 +1842,6 @@
     obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
     if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
         (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
-        struct qemud_vm_disk_def *prev = NULL;
         for (i = 0; i < obj->nodesetval->nodeNr; i++) {
             struct qemud_vm_disk_def *disk = calloc(1, sizeof(*disk));
             if (!disk) {
@@ -1775,13 +1854,20 @@
                 goto error;
             }
             def->ndisks++;
-            disk->next = NULL;
             if (i == 0) {
+                disk->next = NULL;
                 def->disks = disk;
             } else {
-                prev->next = disk;
+                struct qemud_vm_disk_def *ptr = def->disks;
+                while (ptr) {
+                    if (!ptr->next || qemudDiskCompare(ptr->next, disk) < 0) {
+                        disk->next = ptr->next;
+                        ptr->next = disk;
+                        break;
+                    }
+                    ptr = ptr->next;
+                }
             }
-            prev = disk;
         }
     }
     xmlXPathFreeObject(obj);
@@ -2110,6 +2196,7 @@
     struct qemud_vm_chr_def *parallel = vm->def->parallels;
     struct utsname ut;
     int disableKQEMU = 0;
+    int use_extboot = 0;
 
     /* Make sure the binary we are about to try exec'ing exists.
      * Technically we could catch the exec() failure, but that's
@@ -2230,30 +2317,47 @@
             goto no_memory;
     }
 
-    for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
-        switch (vm->def->os.bootDevs[i]) {
-        case QEMUD_BOOT_CDROM:
-            boot[i] = 'd';
-            break;
-        case QEMUD_BOOT_FLOPPY:
-            boot[i] = 'a';
-            break;
-        case QEMUD_BOOT_DISK:
-            boot[i] = 'c';
-            break;
-        case QEMUD_BOOT_NET:
-            boot[i] = 'n';
-            break;
-        default:
-            boot[i] = 'c';
-            break;
-        }
-    }
-    boot[vm->def->os.nBootDevs] = '\0';
-    if (!((*argv)[++n] = strdup("-boot")))
-        goto no_memory;
-    if (!((*argv)[++n] = strdup(boot)))
-        goto no_memory;
+    /* Use extboot if available and required */
+    if ((vm->qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_OPT) &&
+	       (vm->def->os.nBootDevs == 1) && 
+           (vm->def->os.bootDevs[0] == QEMUD_BOOT_DISK)) {
+        struct qemud_vm_disk_def *tmp = disk;
+
+        while (tmp) {
+            if (tmp->bus == QEMUD_DISK_BUS_VIRTIO) {
+                use_extboot = 1;
+                break;
+            }
+            tmp = tmp->next;
+        }
+    }
+
+    if (!use_extboot) {
+        for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
+            switch (vm->def->os.bootDevs[i]) {
+            case QEMUD_BOOT_CDROM:
+                boot[i] = 'd';
+                break;
+            case QEMUD_BOOT_FLOPPY:
+                boot[i] = 'a';
+                break;
+            case QEMUD_BOOT_DISK:
+                boot[i] = 'c';
+                break;
+            case QEMUD_BOOT_NET:
+                boot[i] = 'n';
+                break;
+            default:
+                boot[i] = 'c';
+                break;
+            }
+        }
+        boot[vm->def->os.nBootDevs] = '\0';
+        if (!((*argv)[++n] = strdup("-boot")))
+            goto no_memory;
+        if (!((*argv)[++n] = strdup(boot)))
+            goto no_memory;
+    }
 
     if (vm->def->os.kernel[0]) {
         if (!((*argv)[++n] = strdup("-kernel")))
@@ -2274,28 +2378,74 @@
             goto no_memory;
     }
 
-    while (disk) {
-        char dev[NAME_MAX];
-        char file[PATH_MAX];
-        if (!strcmp(disk->dst, "hdc") &&
-            disk->device == QEMUD_DISK_CDROM) {
-            if (disk->src[0])
-                snprintf(dev, NAME_MAX, "-%s", "cdrom");
-            else {
-                /* Don't put anything on the cmdline for an empty cdrom*/
-                disk = disk->next;
-                continue;
-            }
-        } else
-            snprintf(dev, NAME_MAX, "-%s", disk->dst);
-        snprintf(file, PATH_MAX, "%s", disk->src);
-
-        if (!((*argv)[++n] = strdup(dev)))
-            goto no_memory;
-        if (!((*argv)[++n] = strdup(file)))
-            goto no_memory;
-
-        disk = disk->next;
+    if (use_extboot) {
+        char *handledDisks = NULL;
+        int j;
+
+        handledDisks = calloc(sizeof(*handledDisks), vm->def->ndisks);
+
+        if (!handledDisks)
+            goto no_memory;
+
+        /* When using -drive notation, we need to provide the devices in boot
+         * preference order. */
+        for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
+            if (!((*argv)[++n] = strdup("-drive")))
+                goto no_memory;
+
+            switch (vm->def->os.bootDevs[i]) {
+                case QEMUD_BOOT_CDROM:
+                    if (!((*argv)[++n] = qemudAddBootDrive(conn, vm->def, handledDisks, QEMUD_DISK_CDROM)))
+                        goto error;
+                    break;
+                 case QEMUD_BOOT_FLOPPY:
+                    if (!((*argv)[++n] = qemudAddBootDrive(conn, vm->def, handledDisks, QEMUD_DISK_FLOPPY)))
+                        goto error;
+                break;
+                case QEMUD_BOOT_DISK:
+                    if (!((*argv)[++n] = qemudAddBootDrive(conn, vm->def, handledDisks, QEMUD_DISK_DISK)))
+                        goto error;
+                break;
+            }
+        }
+
+        /* Pick up the rest of the devices */
+        j=0;
+        while (disk) {
+            if (!handledDisks[j]) {
+                handledDisks[j] = 1;
+                if (!((*argv)[++n] = strdup("-drive")))
+                    goto no_memory;
+                if (!((*argv)[++n] = qemudDriveOpt(disk, 0)))
+                    goto no_memory;
+            }
+            disk = disk->next;
+            j++;
+        }
+    } else {
+        while (disk) {
+            char dev[NAME_MAX];
+            char file[PATH_MAX];
+
+            if (!strcmp(disk->dst, "hdc") &&
+                disk->device == QEMUD_DISK_CDROM)
+				if (disk->src[0])
+	                snprintf(dev, NAME_MAX, "-%s", "cdrom");
+				else {
+					disk = disk->next;
+					continue;
+				}
+            else
+                snprintf(dev, NAME_MAX, "-%s", disk->dst);
+            snprintf(file, PATH_MAX, "%s", disk->src);
+
+            if (!((*argv)[++n] = strdup(dev)))
+                goto no_memory;
+            if (!((*argv)[++n] = strdup(file)))
+                goto no_memory;
+
+            disk = disk->next;
+        }
     }
 
     if (!net) {
@@ -3587,6 +3737,7 @@
             virBufferVSprintf(&buf, "      <source %s='%s'/>\n",
                               typeAttrs[disk->type], disk->src);
 
+        virBufferVSprintf(&buf, "      <target dev='%s' bus='%s'/>\n", disk->dst, qemudBusIdToName(disk->bus));
         virBufferVSprintf(&buf, "      <target dev='%s'/>\n", disk->dst);
 
         if (disk->readonly)

=== modified file 'src/qemu_conf.h'
--- old/src/qemu_conf.h	2008-04-30 12:30:55 +0000
+++ new/src/qemu_conf.h	2008-05-06 17:52:17 +0000
@@ -56,10 +56,17 @@
     QEMUD_DISK_FLOPPY,
 };
 
+enum qemud_vm_disk_bus {
+    QEMUD_DISK_BUS_IDE,
+    QEMUD_DISK_BUS_SCSI,
+    QEMUD_DISK_BUS_VIRTIO
+};
+
 /* Stores the virtual disk configuration */
 struct qemud_vm_disk_def {
     int type;
     int device;
+    int bus;
     char src[PATH_MAX];
     char dst[NAME_MAX];
     int readonly;
@@ -223,6 +230,7 @@
     QEMUD_CMD_FLAG_KQEMU = 1,
     QEMUD_CMD_FLAG_VNC_COLON = 2,
     QEMUD_CMD_FLAG_NO_REBOOT = 4,
+    QEMUD_CMD_FLAG_DRIVE_OPT = 8,
 };
 
 

=== modified file 'src/util.c'
--- old/src/util.c	2008-04-25 14:53:05 +0000
+++ new/src/util.c	2008-05-06 17:52:17 +0000
@@ -771,3 +771,44 @@
 
     return -1;
 }
+
+/* Translates a device name of the form (regex) "[fhv]d[a-z]+" into
+ * the corresponding index (e.g. sda => 1, hdz => 26, vdaa => 27)
+ * @param name The name of the device
+ * @return name's index, or 0 on failure
+ */
+int virDiskNameToIndex(const char *name) {
+    const char *ptr = NULL;
+    int idx = 0;
+
+    if (strlen(name) < 3)
+        return 0;
+
+    switch (*name) {
+        case 'f':
+        case 'h':
+        case 'v':
+        case 's':
+            break;
+        default:
+            return 0;
+    }
+
+    if (*(name + 1) != 'd')
+        return 0;
+
+    ptr = name+2;
+
+    while (*ptr) {
+        idx = idx * 26;
+
+        if ('a' > *ptr || 'z' < *ptr)
+            return 0;
+
+        idx += *ptr - 'a' + 1;
+        ptr++;
+    }
+
+    return idx;
+}
+

=== modified file 'src/util.h'
--- old/src/util.h	2008-04-25 14:53:05 +0000
+++ new/src/util.h	2008-05-06 17:52:18 +0000
@@ -92,4 +92,6 @@
 
 int virParseMacAddr(const char* str, unsigned char *addr);
 
+int virDiskNameToIndex(const char* str);
+
 #endif /* __VIR_UTIL_H__ */


-- 
Soren Hansen               | 
Virtualisation specialist  | Ubuntu Server Team
Canonical Ltd.             | http://www.ubuntu.com/

Attachment: signature.asc
Description: Digital signature


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