Markus Groà wrote: > --- > src/libxl/libxl_conf.h | 10 +++ > src/libxl/libxl_driver.c | 184 +++++++++++++++++++++++++++++++++++++++++++++- > 2 files changed, 191 insertions(+), 3 deletions(-) > > diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h > index f2f0d8a..e28615b 100644 > --- a/src/libxl/libxl_conf.h > +++ b/src/libxl/libxl_conf.h > @@ -1,5 +1,6 @@ > /*---------------------------------------------------------------------------*/ > /* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany. > + * Copyright (C) 2011 Univention GmbH. > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Lesser General Public > @@ -17,6 +18,7 @@ > * > * Authors: > * Jim Fehlig <jfehlig@xxxxxxxxxx> > + * Markus Groà <gross@xxxxxxxxxxxxx> > */ > /*---------------------------------------------------------------------------*/ > > @@ -85,6 +87,14 @@ struct _libxlDomainObjPrivate { > int eventHdl; > }; > > +static const char libxlSavefileMagic[16]= "libvirt-xml\n \0 \r"; > +typedef struct _libxlSavefileHeader libxlSavefileHeader; > +typedef libxlSavefileHeader *libxlSavefileHeaderPtr; > +struct _libxlSavefileHeader { > + char magic[16]; /* magic id */ > + uint32_t xmlLen; /* length of saved xml */ > +}; > I think we should pad the header, similar to qemu driver, and provide a version field. > + > > # define libxlError(code, ...) \ > virReportErrorHelper(NULL, VIR_FROM_LIBXL, code, __FILE__, \ > diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c > index 1539385..b02d4b7 100644 > --- a/src/libxl/libxl_driver.c > +++ b/src/libxl/libxl_driver.c > @@ -29,6 +29,7 @@ > #include <sys/utsname.h> > #include <math.h> > #include <libxl.h> > +#include <fcntl.h> > > #include "internal.h" > #include "logging.h" > @@ -60,7 +61,6 @@ > > static libxlDriverPrivatePtr libxl_driver = NULL; > > - > /* Function declarations */ > static int > libxlVmStart(libxlDriverPrivatePtr driver, > @@ -1555,6 +1555,184 @@ libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) > } > > static int > +libxlDomainSave(virDomainPtr dom, const char * to) > +{ > + libxlDriverPrivatePtr driver = dom->conn->privateData; > + virDomainObjPtr vm; > + libxlDomainObjPrivatePtr priv; > + virDomainEventPtr event = NULL; > + libxlSavefileHeader hdr; > + libxl_domain_suspend_info s_info; > + char * xml; > + uint32_t xml_len; > + 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 (vm->state != VIR_DOMAIN_PAUSED) { > + memset(&s_info, 0, sizeof(s_info)); > + > + if ((fd = virFileOpenAs(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR, > + getuid(), getgid(), 0)) < 0) { > + virReportSystemError(-fd, > + _("Failed to create domain save file '%s'"), > + to); > + goto cleanup; > + } > + > + if ((xml = virDomainDefFormat(vm->def, 0)) == NULL) > + goto cleanup; > + xml_len = strlen(xml) + 1; > + > + memset(&hdr, 0, sizeof(hdr)); > + memcpy(hdr.magic, libxlSavefileMagic, sizeof(hdr.magic)); > + hdr.xmlLen = xml_len; > + > + if (safewrite(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { > + libxlError(VIR_ERR_OPERATION_FAILED, > + _("Failed to write save file header")); > + goto cleanup; > + } > + > + if (safewrite(fd, xml, xml_len) != xml_len) { > + libxlError(VIR_ERR_OPERATION_FAILED, > + _("Failed to write xml description")); > + goto cleanup; > + } > + > + if (libxl_domain_suspend(&priv->ctx, &s_info, dom->id, fd) != 0) { > + libxlError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to save domain '%d' with libxenlight"), > + dom->id); > + goto cleanup; > + } > + > + event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, > + VIR_DOMAIN_EVENT_STOPPED_SAVED); > + > + if (libxlVmReap(driver, vm, 1) != 0) { > + libxlError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to destroy domain '%d'"), dom->id); > + goto cleanup; > + } > + > + if (!vm->persistent) { > + virDomainRemoveInactive(&driver->domains, vm); > + vm = NULL; > + } > + ret = 0; > + } > +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) > +{ > + libxlDriverPrivatePtr driver = conn->privateData; > + virDomainDefPtr def = NULL; > + virDomainObjPtr vm = NULL; > + virDomainEventPtr event = NULL; > + libxlSavefileHeader hdr; > + char * xml = NULL; > + int fd; > + int ret = -1; > + > + libxlDriverLock(driver); > + > + 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")); > + goto cleanup; > + } > + > + if (memcmp(hdr.magic, libxlSavefileMagic, sizeof(hdr.magic))) { > + libxlError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect")); > + goto cleanup; > + } > + > + if (hdr.xmlLen <= 0) { > + libxlError(VIR_ERR_OPERATION_FAILED, > + _("invalid XML length: %d"), hdr.xmlLen); > + goto cleanup; > + } > + > + if (VIR_ALLOC_N(xml, hdr.xmlLen) < 0) { > + virReportOOMError(); > + goto cleanup; > + } > + > + if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) { > + libxlError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML")); > + goto cleanup; > + } > + > + if (!(def = virDomainDefParseString(driver->caps, xml, 0))) > + goto cleanup; > + > + if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0) > + goto cleanup; > + > + if (!(vm = virDomainAssignDef(driver->caps, &driver->domains, def, false))) > + goto cleanup; > + > + def = NULL; > + > + ret = libxlVmStart(driver, vm, false); > This starts a new domain. To restore a domain, you need to use libxl_domain_create_restore(). Regards, Jim > + > + if (ret == 0) { > + event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED, > + VIR_DOMAIN_EVENT_STARTED_RESTORED); > + } else if (ret < 0 && !vm->persistent) { > + virDomainRemoveInactive(&driver->domains, vm); > + vm = NULL; > + } > + > +cleanup: > + VIR_FREE(xml); > + virDomainDefFree(def); > + 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 > libxlDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, > unsigned int flags) > { > @@ -2658,8 +2836,8 @@ static virDriver libxlDriver = { > NULL, /* domainSetBlkioParameters */ > NULL, /* domainGetBlkioParameters */ > libxlDomainGetInfo, /* domainGetInfo */ > - NULL, /* domainSave */ > - NULL, /* domainRestore */ > + libxlDomainSave, /* domainSave */ > + libxlDomainRestore, /* domainRestore */ > NULL, /* domainCoreDump */ > libxlDomainSetVcpus, /* domainSetVcpus */ > libxlDomainSetVcpusFlags, /* domainSetVcpusFlags */ > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list