Markus Groà wrote: > --- > src/libxl/libxl_driver.c | 353 ++++++++++++++++++++++++++++++++++++---------- > 1 files changed, 276 insertions(+), 77 deletions(-) > > diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c > index 61c3494..9bcc3b9 100644 > --- a/src/libxl/libxl_driver.c > +++ b/src/libxl/libxl_driver.c > @@ -66,7 +66,6 @@ static int > libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, > bool start_paused, int restore_fd); > > - > /* Function definitions */ > static void > libxlDriverLock(libxlDriverPrivatePtr driver) > @@ -219,6 +218,87 @@ libxlDoNodeGetInfo(libxlDriverPrivatePtr driver, virNodeInfoPtr info) > return 0; > } > > +static char * > +libxlDomainManagedSavePath(libxlDriverPrivatePtr driver, virDomainObjPtr vm) { > + char *ret; > + > + if (virAsprintf(&ret, "%s/%s.save", driver->saveDir, vm->def->name) < 0) { > + virReportOOMError(); > + return NULL; > + } > + > + return ret; > +} > + > +/* This internal function expects the driver lock to already be held on > + * entry. */ > +static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) > +libxlSaveImageOpen(libxlDriverPrivatePtr driver, const char *from, > + virDomainDefPtr *ret_def, libxlSavefileHeaderPtr ret_hdr) > +{ > + int fd; > + virDomainDefPtr def = NULL; > + libxlSavefileHeader hdr; > + char *xml = NULL; > + > + if ((fd = virFileOpenAs(from, O_RDONLY, 0, getuid(), getgid(), 0)) < 0) { > + libxlError(VIR_ERR_OPERATION_FAILED, > + "%s", _("cannot read domain image")); > + goto error; > + } > + > + if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { > + libxlError(VIR_ERR_OPERATION_FAILED, > + "%s", _("failed to read libxl header")); > + goto error; > + } > + > + if (memcmp(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic))) { > + libxlError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect")); > + goto error; > + } > + > + if (hdr.version > LIBXL_SAVE_VERSION) { > + libxlError(VIR_ERR_OPERATION_FAILED, > + _("image version is not supported (%d > %d)"), > + hdr.version, LIBXL_SAVE_VERSION); > + goto error; > + } > + > + if (hdr.xmlLen <= 0) { > + libxlError(VIR_ERR_OPERATION_FAILED, > + _("invalid XML length: %d"), hdr.xmlLen); > + goto error; > + } > + > + if (VIR_ALLOC_N(xml, hdr.xmlLen) < 0) { > + virReportOOMError(); > + goto error; > + } > + > + if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) { > + libxlError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML")); > + goto error; > + } > + > + if (!(def = virDomainDefParseString(driver->caps, xml, > + VIR_DOMAIN_XML_INACTIVE))) > + goto error; > + > + VIR_FREE(xml); > + > + *ret_def = def; > + *ret_hdr = hdr; > + > + return fd; > + > +error: > + VIR_FREE(xml); > + virDomainDefFree(def); > + VIR_FORCE_CLOSE(fd); > + return -1; > +} > + > /* > * Cleanup function for domain that has reached shutoff state. > * > @@ -546,17 +626,53 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, > bool start_paused, int restore_fd) > { > libxl_domain_config d_config; > - virDomainDefPtr def = vm->def; > + virDomainDefPtr def = NULL; > virDomainEventPtr event = NULL; > + libxlSavefileHeader hdr; > int ret; > uint32_t domid = 0; > char *dom_xml = NULL; > + char *managed_save = NULL; > pid_t child_console_pid = -1; > libxlDomainObjPrivatePtr priv = vm->privateData; > > + /* If there is a managed saved state restore it instead of starting > + * from scratch. The old state is removed once the restoring succeeded. */ > + if (restore_fd < 0) { > + managed_save = libxlDomainManagedSavePath(driver, vm); > + if (managed_save == NULL) > + goto error; > + > + if (virFileExists(managed_save)) { > + > + restore_fd = libxlSaveImageOpen(driver, managed_save, &def, &hdr); > + if (restore_fd < 0) > + goto error; > + > + if (STRNEQ(vm->def->name, def->name) || > + memcmp(vm->def->uuid, def->uuid, VIR_UUID_BUFLEN)) { > + char vm_uuidstr[VIR_UUID_STRING_BUFLEN]; > + char def_uuidstr[VIR_UUID_STRING_BUFLEN]; > + virUUIDFormat(vm->def->uuid, vm_uuidstr); > + virUUIDFormat(def->uuid, def_uuidstr); > + libxlError(VIR_ERR_OPERATION_FAILED, > + _("cannot restore domain '%s' uuid %s from a file" > + " which belongs to domain '%s' uuid %s"), > + vm->def->name, vm_uuidstr, def->name, def_uuidstr); > + goto error; > + } > + > + virDomainObjAssignDef(vm, def, true); > + def = NULL; > + > + if (unlink(managed_save) < 0) > + VIR_WARN("Failed to remove the managed state %s", managed_save); > + } > + } > + > On success of this function, managed_save and restore_fd will leak. > memset(&d_config, 0, sizeof(d_config)); > > - if (libxlBuildDomainConfig(driver, def, &d_config) < 0 ) > + if (libxlBuildDomainConfig(driver, vm->def, &d_config) < 0 ) > return -1; > > if (libxlFreeMem(priv, &d_config) < 0) { > @@ -586,8 +702,8 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, > goto error; > } > > - def->id = domid; > - if ((dom_xml = virDomainDefFormat(def, 0)) == NULL) > + vm->def->id = domid; > + if ((dom_xml = virDomainDefFormat(vm->def, 0)) == NULL) > goto error; > > if (libxl_userdata_store(&priv->ctx, domid, "libvirt-xml", > @@ -627,11 +743,14 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, > error: > if (domid > 0) { > libxl_domain_destroy(&priv->ctx, domid, 0); > - def->id = -1; > + vm->def->id = -1; > virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED); > } > libxl_domain_config_destroy(&d_config); > VIR_FREE(dom_xml); > + VIR_FREE(managed_save); > + virDomainDefFree(def); > + VIR_FORCE_CLOSE(restore_fd); > This would close a caller-provided fd. I think it is better for callers that have opened an fd to also close it. I'll send a patch that addresses these minor issues. Otherwise looks good and no problems noted in my testing. Regards, Jim > return -1; > } > > @@ -1692,12 +1811,13 @@ libxlDomainGetState(virDomainPtr dom, > return ret; > } > > +/* This internal function expects the driver lock to already be held on > + * entry and the vm must be active. */ > static int > -libxlDomainSave(virDomainPtr dom, const char *to) > +libxlDoDomainSave(libxlDriverPrivatePtr driver, virDomainObjPtr vm, > + const char *to) > { > - libxlDriverPrivatePtr driver = dom->conn->privateData; > - virDomainObjPtr vm; > - libxlDomainObjPrivatePtr priv; > + libxlDomainObjPrivatePtr priv = vm->privateData; > libxlSavefileHeader hdr; > virDomainEventPtr event = NULL; > char *xml = NULL; > @@ -1705,28 +1825,10 @@ libxlDomainSave(virDomainPtr dom, const char *to) > int fd; > int ret = -1; > > - libxlDriverLock(driver); > - vm = virDomainFindByUUID(&driver->domains, dom->uuid); > - > - if (!vm) { > - char uuidstr[VIR_UUID_STRING_BUFLEN]; > - virUUIDFormat(dom->uuid, uuidstr); > - libxlError(VIR_ERR_NO_DOMAIN, > - _("No domain with matching uuid '%s'"), uuidstr); > - goto cleanup; > - } > - > - if (!virDomainObjIsActive(vm)) { > - libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running")); > - goto cleanup; > - } > - > - priv = vm->privateData; > - > if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) { > libxlError(VIR_ERR_OPERATION_INVALID, > _("Domain '%d' has to be running because libxenlight will" > - " suspend it"), dom->id); > + " suspend it"), vm->def->id); > goto cleanup; > } > > @@ -1758,10 +1860,10 @@ libxlDomainSave(virDomainPtr dom, const char *to) > goto cleanup; > } > > - if (libxl_domain_suspend(&priv->ctx, NULL, dom->id, fd) != 0) { > + if (libxl_domain_suspend(&priv->ctx, NULL, vm->def->id, fd) != 0) { > libxlError(VIR_ERR_INTERNAL_ERROR, > _("Failed to save domain '%d' with libxenlight"), > - dom->id); > + vm->def->id); > goto cleanup; > } > > @@ -1770,7 +1872,7 @@ libxlDomainSave(virDomainPtr dom, const char *to) > > if (libxlVmReap(driver, vm, 1, VIR_DOMAIN_SHUTOFF_SAVED) != 0) { > libxlError(VIR_ERR_INTERNAL_ERROR, > - _("Failed to destroy domain '%d'"), dom->id); > + _("Failed to destroy domain '%d'"), vm->def->id); > goto cleanup; > } > > @@ -1785,69 +1887,57 @@ cleanup: > VIR_FREE(xml); > if (VIR_CLOSE(fd) < 0) > virReportSystemError(errno, "%s", _("cannot close file")); > - if (vm) > - virDomainObjUnlock(vm); > if (event) > libxlDomainEventQueue(driver, event); > - libxlDriverUnlock(driver); > return ret; > } > > static int > -libxlDomainRestore(virConnectPtr conn, const char *from) > +libxlDomainSave(virDomainPtr dom, const char *to) > { > - libxlDriverPrivatePtr driver = conn->privateData; > - virDomainDefPtr def = NULL; > - virDomainObjPtr vm = NULL; > - libxlSavefileHeader hdr; > - char *xml = NULL; > - int fd; > + libxlDriverPrivatePtr driver = dom->conn->privateData; > + virDomainObjPtr vm; > int ret = -1; > > libxlDriverLock(driver); > + vm = virDomainFindByUUID(&driver->domains, dom->uuid); > > - if ((fd = virFileOpenAs(from, O_RDONLY, 0, getuid(), getgid(), 0)) < 0) { > - libxlError(VIR_ERR_OPERATION_FAILED, > - "%s", _("cannot read domain image")); > - goto cleanup; > - } > - > - if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { > - libxlError(VIR_ERR_OPERATION_FAILED, > - "%s", _("failed to read libxl header")); > + if (!vm) { > + char uuidstr[VIR_UUID_STRING_BUFLEN]; > + virUUIDFormat(dom->uuid, uuidstr); > + libxlError(VIR_ERR_NO_DOMAIN, > + _("No domain with matching uuid '%s'"), uuidstr); > goto cleanup; > } > > - if (memcmp(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic))) { > - libxlError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect")); > + if (!virDomainObjIsActive(vm)) { > + libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running")); > goto cleanup; > } > > - if (hdr.version > LIBXL_SAVE_VERSION) { > - libxlError(VIR_ERR_OPERATION_FAILED, > - _("image version is not supported (%d > %d)"), > - hdr.version, LIBXL_SAVE_VERSION); > - goto cleanup; > - } > + ret = libxlDoDomainSave(driver, vm, to); > > - if (hdr.xmlLen <= 0) { > - libxlError(VIR_ERR_OPERATION_FAILED, > - _("invalid XML length: %d"), hdr.xmlLen); > - goto cleanup; > - } > +cleanup: > + if (vm) > + virDomainObjUnlock(vm); > + libxlDriverUnlock(driver); > + return ret; > +} > > - if (VIR_ALLOC_N(xml, hdr.xmlLen) < 0) { > - virReportOOMError(); > - goto cleanup; > - } > +static int > +libxlDomainRestore(virConnectPtr conn, const char *from) > +{ > + libxlDriverPrivatePtr driver = conn->privateData; > + virDomainObjPtr vm = NULL; > + virDomainDefPtr def = NULL; > + libxlSavefileHeader hdr; > + int fd = -1; > + int ret = -1; > > - if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) { > - libxlError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML")); > - goto cleanup; > - } > + libxlDriverLock(driver); > > - if (!(def = virDomainDefParseString(driver->caps, xml, > - VIR_DOMAIN_XML_INACTIVE))) > + fd = libxlSaveImageOpen(driver, from, &def, &hdr); > + if (fd < 0) > goto cleanup; > > if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0) > @@ -1865,10 +1955,7 @@ libxlDomainRestore(virConnectPtr conn, const char *from) > } > > cleanup: > - VIR_FREE(xml); > virDomainDefFree(def); > - if (VIR_CLOSE(fd) < 0) > - virReportSystemError(errno, "%s", _("cannot close file")); > if (vm) > virDomainObjUnlock(vm); > libxlDriverUnlock(driver); > @@ -1970,6 +2057,115 @@ cleanup: > } > > static int > +libxlDomainManagedSave(virDomainPtr dom, unsigned int flags) > +{ > + libxlDriverPrivatePtr driver = dom->conn->privateData; > + virDomainObjPtr vm = NULL; > + char *name = NULL; > + int ret = -1; > + > + virCheckFlags(0, -1); > + > + libxlDriverLock(driver); > + vm = virDomainFindByUUID(&driver->domains, dom->uuid); > + if (!vm) { > + char uuidstr[VIR_UUID_STRING_BUFLEN]; > + virUUIDFormat(dom->uuid, uuidstr); > + libxlError(VIR_ERR_NO_DOMAIN, > + _("No domain with matching uuid '%s'"), uuidstr); > + goto cleanup; > + } > + > + if (!virDomainObjIsActive(vm)) { > + libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running")); > + goto cleanup; > + } > + > + name = libxlDomainManagedSavePath(driver, vm); > + if (name == NULL) > + goto cleanup; > + > + VIR_INFO("Saving state to %s", name); > + > + ret = libxlDoDomainSave(driver, vm, name); > + > +cleanup: > + if (vm) > + virDomainObjUnlock(vm); > + libxlDriverUnlock(driver); > + VIR_FREE(name); > + return ret; > +} > + > +static int > +libxlDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags) > +{ > + libxlDriverPrivatePtr driver = dom->conn->privateData; > + virDomainObjPtr vm = NULL; > + int ret = -1; > + char *name = NULL; > + > + virCheckFlags(0, -1); > + > + libxlDriverLock(driver); > + vm = virDomainFindByUUID(&driver->domains, dom->uuid); > + if (!vm) { > + char uuidstr[VIR_UUID_STRING_BUFLEN]; > + virUUIDFormat(dom->uuid, uuidstr); > + libxlError(VIR_ERR_NO_DOMAIN, > + _("No domain with matching uuid '%s'"), uuidstr); > + goto cleanup; > + } > + > + name = libxlDomainManagedSavePath(driver, vm); > + if (name == NULL) > + goto cleanup; > + > + ret = virFileExists(name); > + > +cleanup: > + VIR_FREE(name); > + if (vm) > + virDomainObjUnlock(vm); > + libxlDriverUnlock(driver); > + return ret; > +} > + > +static int > +libxlDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags) > +{ > + libxlDriverPrivatePtr driver = dom->conn->privateData; > + virDomainObjPtr vm = NULL; > + int ret = -1; > + char *name = NULL; > + > + virCheckFlags(0, -1); > + > + libxlDriverLock(driver); > + vm = virDomainFindByUUID(&driver->domains, dom->uuid); > + if (!vm) { > + char uuidstr[VIR_UUID_STRING_BUFLEN]; > + virUUIDFormat(dom->uuid, uuidstr); > + libxlError(VIR_ERR_NO_DOMAIN, > + _("No domain with matching uuid '%s'"), uuidstr); > + goto cleanup; > + } > + > + name = libxlDomainManagedSavePath(driver, vm); > + if (name == NULL) > + goto cleanup; > + > + ret = unlink(name); > + > +cleanup: > + VIR_FREE(name); > + if (vm) > + virDomainObjUnlock(vm); > + libxlDriverUnlock(driver); > + return ret; > +} > + > +static int > libxlDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, > unsigned int flags) > { > @@ -3634,6 +3830,9 @@ static virDriver libxlDriver = { > .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */ > .domainEventRegister = libxlDomainEventRegister, /* 0.9.0 */ > .domainEventDeregister = libxlDomainEventDeregister, /* 0.9.0 */ > + .domainManagedSave = libxlDomainManagedSave, /* 0.9.3 */ > + .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.3 */ > + .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.3 */ > .domainIsActive = libxlDomainIsActive, /* 0.9.0 */ > .domainIsPersistent = libxlDomainIsPersistent, /* 0.9.0 */ > .domainIsUpdated = libxlDomainIsUpdated, /* 0.9.0 */ > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list