[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
[libvirt] [PATCH/RFC]: file backed usb massstorage
- From: Guido Günther <agx sigxcpu org>
- To: libvir-list redhat com
- Subject: [libvirt] [PATCH/RFC]: file backed usb massstorage
- Date: Mon, 28 Jul 2008 11:02:45 -0400
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
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]