From: Soren Hansen <soren@xxxxxxxxxxx> UML supports hot plugging and unplugging of various devices. This patch exposes this functionality for disks. Signed-off-by: Soren Hansen <soren@xxxxxxxxxxx> --- src/uml/uml_driver.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 221 insertions(+), 2 deletions(-) diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 04493ba..a09bc60 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -1686,6 +1686,225 @@ cleanup: } +static inline void umlShrinkDisks(virDomainDefPtr def, size_t i) +{ + if (def->ndisks > 1) { + memmove(def->disks + i, + def->disks + i + 1, + sizeof(*def->disks) * + (def->ndisks - (i + 1))); + def->ndisks--; + if (VIR_REALLOC_N(def->disks, def->ndisks) < 0) { + /* ignore, harmless */ + } + } else { + VIR_FREE(def->disks); + def->ndisks = 0; + } +} + + +static int umlDomainAttachUmlDisk(struct uml_driver *driver, + virDomainObjPtr vm, + virDomainDiskDefPtr disk) +{ + int i, ret; + char *cmd = NULL; + char *reply; + + 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) + return -1; + + if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) { + virReportOOMError(); + goto error; + } + + if (ret < 0) + goto error; + + virDomainDiskInsertPreAlloced(vm->def, disk); + + VIR_FREE(cmd); + + return 0; + +error: + + 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 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; + + umlShrinkDisks(vm->def, i); + + virDomainDiskDefFree(detach); + + ret = 0; + +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 umlDomainGetAutostart(virDomainPtr dom, int *autostart) { @@ -1900,9 +2119,9 @@ static virDriver umlDriver = { umlDomainStartWithFlags, /* domainCreateWithFlags */ umlDomainDefine, /* domainDefineXML */ umlDomainUndefine, /* domainUndefine */ - NULL, /* domainAttachDevice */ + umlDomainAttachDevice, /* domainAttachDevice */ NULL, /* domainAttachDeviceFlags */ - NULL, /* domainDetachDevice */ + umlDomainDetachDevice, /* domainDetachDevice */ NULL, /* domainDetachDeviceFlags */ NULL, /* domainUpdateDeviceFlags */ umlDomainGetAutostart, /* domainGetAutostart */ -- 1.7.0.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list