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/