From 5c3eec9ffbe962d2f517cd642ed27c36760e3ce8 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 23 Aug 2010 11:31:27 +0200 Subject: [PATCH] Support virDomainAttachDevice and virDomainDetachDevice for disks in UML UML supports hot plugging and unplugging of various devices. This patch exposes this functionality for disks. Signed-off-by: Soren Hansen --- src/uml/uml_driver.c | 236 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 232 insertions(+), 4 deletions(-) diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 6582d95569..8b129b7cc4 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1691,6 +1691,234 @@ cleanup: } +static int umlDomainAttachUmlDisk(struct uml_driver *driver, + virDomainObjPtr vm, + virDomainDiskDefPtr disk) +{ + int i; + char *cmd = NULL; + char *reply = NULL; + + for (i = 0 ; i < vm->def->ndisks ; i++) { + if (STREQ(vm->def->disks[i]->dst, disk->dst)) { + umlReportError(VIR_ERR_OPERATION_FAILED, + _("target %s already exists"), disk->dst); + return -1; + } + } + + if (!disk->src) { + umlReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("disk source path is missing")); + goto error; + } + + if (virAsprintf(&cmd, "config %s=%s", disk->dst, disk->src) < 0) { + virReportOOMError(); + return -1; + } + + if (umlMonitorCommand(driver, vm, cmd, &reply) < 0) + goto error; + + if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) { + virReportOOMError(); + goto error; + } + + virDomainDiskInsertPreAlloced(vm->def, disk); + + VIR_FREE(reply); + VIR_FREE(cmd); + + return 0; + +error: + + VIR_FREE(reply); + VIR_FREE(cmd); + + return -1; +} + + +static int umlDomainAttachDevice(virDomainPtr dom, const char *xml) +{ + struct uml_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + virDomainDeviceDefPtr dev = NULL; + int ret = -1; + + umlDriverLock(driver); + + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + umlReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + umlReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cannot attach device on inactive domain")); + goto cleanup; + } + + dev = virDomainDeviceDefParse(driver->caps, vm->def, xml, + VIR_DOMAIN_XML_INACTIVE); + + if (dev == NULL) + goto cleanup; + + if (dev->type == VIR_DOMAIN_DEVICE_DISK) { + if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML) { + ret = umlDomainAttachUmlDisk(driver, vm, dev->data.disk); + if (ret == 0) + dev->data.disk = NULL; + } else { + umlReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("disk bus '%s' cannot be hotplugged."), + virDomainDiskBusTypeToString(dev->data.disk->bus)); + } + } else { + umlReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("device type '%s' cannot be attached"), + virDomainDeviceTypeToString(dev->type)); + goto cleanup; + } + +cleanup: + + virDomainDeviceDefFree(dev); + if (vm) + virDomainObjUnlock(vm); + umlDriverUnlock(driver); + return ret; +} + + +static int umlDomainAttachDeviceFlags(virDomainPtr dom, + const char *xml, + unsigned int flags) { + if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) { + umlReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cannot modify the persistent configuration of a domain")); + return -1; + } + + return umlDomainAttachDevice(dom, xml); +} + + +static int umlDomainDetachUmlDisk(struct uml_driver *driver, + virDomainObjPtr vm, + virDomainDeviceDefPtr dev) +{ + int i, ret = -1; + virDomainDiskDefPtr detach = NULL; + char *cmd; + char *reply; + + for (i = 0 ; i < vm->def->ndisks ; i++) { + if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) { + break; + } + } + + if (i == vm->def->ndisks) { + umlReportError(VIR_ERR_OPERATION_FAILED, + _("disk %s not found"), dev->data.disk->dst); + return -1; + } + + detach = vm->def->disks[i]; + + if (virAsprintf(&cmd, "remove %s", detach->dst) < 0) { + virReportOOMError(); + return -1; + } + + if (umlMonitorCommand(driver, vm, cmd, &reply) < 0) + goto cleanup; + + virDomainDiskRemove(vm->def, i); + + virDomainDiskDefFree(detach); + + ret = 0; + + VIR_FREE(reply); + +cleanup: + VIR_FREE(cmd); + + return ret; +} + + +static int umlDomainDetachDevice(virDomainPtr dom, const char *xml) { + struct uml_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + virDomainDeviceDefPtr dev = NULL; + int ret = -1; + + umlDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + umlReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + umlReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cannot detach device on inactive domain")); + goto cleanup; + } + + dev = virDomainDeviceDefParse(driver->caps, vm->def, xml, + VIR_DOMAIN_XML_INACTIVE); + if (dev == NULL) + goto cleanup; + + if (dev->type == VIR_DOMAIN_DEVICE_DISK && + dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) { + if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_UML) + ret = umlDomainDetachUmlDisk(driver, vm, dev); + else { + umlReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("This type of disk cannot be hot unplugged")); + } + } else { + umlReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("This type of device cannot be hot unplugged")); + } + +cleanup: + virDomainDeviceDefFree(dev); + if (vm) + virDomainObjUnlock(vm); + umlDriverUnlock(driver); + return ret; +} + + +static int umlDomainDetachDeviceFlags(virDomainPtr dom, + const char *xml, + unsigned int flags) { + if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) { + umlReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cannot modify the persistent configuration of a domain")); + return -1; + } + + return umlDomainDetachDevice(dom, xml); +} + static int umlDomainGetAutostart(virDomainPtr dom, int *autostart) { @@ -1905,10 +2133,10 @@ static virDriver umlDriver = { umlDomainStartWithFlags, /* domainCreateWithFlags */ umlDomainDefine, /* domainDefineXML */ umlDomainUndefine, /* domainUndefine */ - NULL, /* domainAttachDevice */ - NULL, /* domainAttachDeviceFlags */ - NULL, /* domainDetachDevice */ - NULL, /* domainDetachDeviceFlags */ + umlDomainAttachDevice, /* domainAttachDevice */ + umlDomainAttachDeviceFlags, /* domainAttachDeviceFlags */ + umlDomainDetachDevice, /* domainDetachDevice */ + umlDomainDetachDeviceFlags, /* domainDetachDeviceFlags */ NULL, /* domainUpdateDeviceFlags */ umlDomainGetAutostart, /* domainGetAutostart */ umlDomainSetAutostart, /* domainSetAutostart */