On Fri, Jul 25, 2008 at 04:17:30PM -0400, Guido Günther wrote: > attached is some basic support for host device passthrough. It enables > you to passthrough usb devices in qemu/kvm via: On top of the hostdev passthrough (but it's actually totally independent) I added usb massstorage backed by a file. Very handy for installer testing where the preseed data is on the USB stick and the CD/DVD is the installation medium. At the moment I'm using a dummy target "usbdisk" so we don't have to check for target == NULL in that many places. Once qemu handles it we can fill in bus and device address for unplugging. To add a file as usb massstorage to the guest you can use: <disk type='file' device='disk'> <source file='/foo/bar/usbmass.img'/> <target bus='usb'/> </disk> Does this make sense? -- Guido
--- src/domain_conf.c | 40 ++++++++++++++++++++++++++++------------ src/domain_conf.h | 1 + src/qemu_conf.c | 23 +++++++++++++++++++++-- src/qemu_driver.c | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 14 deletions(-) diff --git a/src/domain_conf.c b/src/domain_conf.c index d36caeb..74ceecc 100644 --- a/src/domain_conf.c +++ b/src/domain_conf.c @@ -84,7 +84,8 @@ VIR_ENUM_IMPL(virDomainDiskBus, VIR_DOMAIN_DISK_BUS_LAST, "fdc", "scsi", "virtio", - "xen") + "xen", + "usb") VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST, "user", @@ -540,6 +541,14 @@ virDomainDiskDefParseXML(virConnectPtr conn, def->device = VIR_DOMAIN_DISK_DEVICE_DISK; } + if (bus) { + if ((def->bus = virDomainDiskBusTypeFromString(bus)) < 0) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unknown disk bus type '%s'"), bus); + goto error; + } + } + /* Only CDROM and Floppy devices are allowed missing source path * to indicate no media present */ if (source == NULL && @@ -550,10 +559,16 @@ virDomainDiskDefParseXML(virConnectPtr conn, goto error; } + /* only USB devices are allowed missing target path since the hypervisor + * can assign bus and device number */ if (target == NULL) { - virDomainReportError(conn, VIR_ERR_NO_TARGET, - source ? "%s" : NULL, source); - goto error; + if (def->bus == VIR_DOMAIN_DISK_BUS_USB) { + target = strdup("usbdisk"); + } else { + virDomainReportError(conn, VIR_ERR_NO_TARGET, + source ? "%s" : NULL, source); + goto error; + } } if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY && @@ -571,19 +586,14 @@ virDomainDiskDefParseXML(virConnectPtr conn, !STRPREFIX((const char *)target, "hd") && !STRPREFIX((const char *)target, "sd") && !STRPREFIX((const char *)target, "vd") && - !STRPREFIX((const char *)target, "xvd")) { + !STRPREFIX((const char *)target, "xvd") && + !STREQ((const char*)target, "usbdisk")) { virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, _("Invalid harddisk device name: %s"), target); goto error; } - if (bus) { - if ((def->bus = virDomainDiskBusTypeFromString(bus)) < 0) { - virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, - _("unknown disk bus type '%s'"), bus); - goto error; - } - } else { + if (!bus) { if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) { def->bus = VIR_DOMAIN_DISK_BUS_FDC; } else { @@ -612,6 +622,12 @@ virDomainDiskDefParseXML(virConnectPtr conn, _("Invalid bus type '%s' for disk"), bus); goto error; } + if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK && + def->bus == VIR_DOMAIN_DISK_BUS_USB) { + virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("Invalid bus type '%s' for usb disk"), bus); + goto error; + } def->src = source; source = NULL; diff --git a/src/domain_conf.h b/src/domain_conf.h index 1aa5c39..a9c237e 100644 --- a/src/domain_conf.h +++ b/src/domain_conf.h @@ -72,6 +72,7 @@ enum virDomainDiskBus { VIR_DOMAIN_DISK_BUS_SCSI, VIR_DOMAIN_DISK_BUS_VIRTIO, VIR_DOMAIN_DISK_BUS_XEN, + VIR_DOMAIN_DISK_BUS_USB, VIR_DOMAIN_DISK_BUS_LAST }; diff --git a/src/qemu_conf.c b/src/qemu_conf.c index 7678ac5..868b3dc 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -55,7 +55,8 @@ VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST, "floppy", "scsi", "virtio", - "xen") + "xen", + "usb") #define qemudLog(level, msg...) fprintf(stderr, msg) @@ -772,6 +773,13 @@ int qemudBuildCommandLine(virConnectPtr conn, goto no_memory; \ } while (0) +#define ADD_USBDISK(thisarg) \ + do { \ + ADD_ARG_LIT("-usbdevice"); \ + if ((asprintf(&qargv[qargc++], "disk:%s", thisarg)) == -1) \ + goto no_memory; \ + } while (0) + snprintf(memory, sizeof(memory), "%lu", vm->def->memory/1024); snprintf(vcpus, sizeof(vcpus), "%lu", vm->def->vcpus); @@ -883,6 +891,12 @@ int qemudBuildCommandLine(virConnectPtr conn, int idx = virDiskNameToIndex(disk->dst); const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus); + if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) { + ADD_USBDISK(disk->src); + disk = disk->next; + continue; + } + if (idx < 0) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, _("unsupported disk type '%s'"), disk->dst); @@ -924,6 +938,12 @@ int qemudBuildCommandLine(virConnectPtr conn, char dev[NAME_MAX]; char file[PATH_MAX]; + if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) { + ADD_USBDISK(disk->src); + disk = disk->next; + continue; + } + if (STREQ(disk->dst, "hdc") && disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) { if (disk->src) { @@ -947,7 +967,6 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG_LIT(dev); ADD_ARG_LIT(file); - disk = disk->next; } } diff --git a/src/qemu_driver.c b/src/qemu_driver.c index 3381d10..73b6da4 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -2979,6 +2979,44 @@ static int qemudDomainAttachCdromDevice(virDomainPtr dom, return 0; } +static int qemudDomainAttachUsbMassstorageDevice(virDomainPtr dom, virDomainDeviceDefPtr dev) +{ + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + virDomainObjPtr vm = virDomainFindByUUID(driver->domains, dom->uuid); + int ret; + char *cmd, *reply; + + ret = asprintf(&cmd, "usb_add disk:%s", dev->data.disk->src); + + if (ret == -1) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("out of memory")); + return ret; + } + + if (qemudMonitorCommand(driver, vm, cmd, &reply) < 0) { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("cannot attach usb device")); + VIR_FREE(cmd); + return -1; + } + + DEBUG ("attach_usb reply: %s", reply); + /* If the command failed qemu prints: + * Could not add ... */ + if (strstr(reply, "Could not add ")) { + qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, + "%s", + _("adding usb device failed")); + VIR_FREE(reply); + VIR_FREE(cmd); + return -1; + } + VIR_FREE(reply); + VIR_FREE(cmd); + return 0; +} + static int qemudDomainAttachHostDevice(virDomainPtr dom, virDomainDeviceDefPtr dev) { struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; @@ -3051,6 +3089,9 @@ static int qemudDomainAttachDevice(virDomainPtr dom, if (dev->type == VIR_DOMAIN_DEVICE_DISK && dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) { ret = qemudDomainAttachCdromDevice(dom, dev); + } else if (dev->data.disk->device == VIR_DOMAIN_DEVICE_DISK && + dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) { + ret = qemudDomainAttachUsbMassstorageDevice(dom, dev); } else if (dev->type == VIR_DOMAIN_DEVICE_HOST && dev->data.hostdev->type == VIR_DOMAIN_HOSTDEV_TYPE_USB) { ret = qemudDomainAttachHostDevice(dom, dev); -- 1.5.6.3
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list