diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 66e8518..8f98219 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -564,24 +564,28 @@ xenUnifiedListDomains (virConnectPtr conn, int *ids, int maxids) /* Try xenstore. */ if (priv->opened[XEN_UNIFIED_XS_OFFSET]) { ret = xenStoreListDomains (conn, ids, maxids); + DEBUG("xenStoreListDomains: %d", ret); if (ret >= 0) return ret; } /* Try HV. */ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) { ret = xenHypervisorListDomains (conn, ids, maxids); + DEBUG("xenHypervisorListDomains: %d", ret); if (ret >= 0) return ret; } /* Try xend. */ if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) { ret = xenDaemonListDomains (conn, ids, maxids); + DEBUG("xenDaemonListDomains: %d", ret); if (ret >= 0) return ret; } /* Try proxy. */ if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) { ret = xenProxyListDomains (conn, ids, maxids); + DEBUG("xenProxyListDomains: %d", ret); if (ret >= 0) return ret; } return -1; @@ -1979,6 +1983,52 @@ out: return ret; } +static int +xenUnifiedDomainManagedSave(virDomainPtr dom, unsigned int flags) +{ + GET_PRIVATE(dom->conn); + int i; + + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) + if (priv->opened[i] && + drivers[i]->domainManagedSave && + drivers[i]->domainManagedSave(dom, flags) == 0) + return 0; + + return -1; +} + +static int +xenUnifiedDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags) +{ + GET_PRIVATE(dom->conn); + int i; + + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) + if (priv->opened[i] && + drivers[i]->domainHasManagedSaveImage && + drivers[i]->domainHasManagedSaveImage(dom, flags) == 0) + return 0; + + return -1; +} + +static int +xenUnifiedDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags) +{ + GET_PRIVATE(dom->conn); + int i; + + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) + if (priv->opened[i] && + drivers[i]->domainManagedSaveRemove && + drivers[i]->domainManagedSaveRemove(dom, flags) == 0) + return 0; + + return -1; +} + + /*----- Register with libvirt.c, and initialize Xen drivers. -----*/ @@ -2072,9 +2122,9 @@ static virDriver xenUnifiedDriver = { NULL, /* domainMigrateSetMaxDowntime */ xenUnifiedDomainEventRegisterAny, /* domainEventRegisterAny */ xenUnifiedDomainEventDeregisterAny, /* domainEventDeregisterAny */ - NULL, /* domainManagedSave */ - NULL, /* domainHasManagedSaveImage */ - NULL, /* domainManagedSaveRemove */ + xenUnifiedDomainManagedSave, /* domainManagedSave */ + xenUnifiedDomainHasManagedSaveImage, /* domainHasManagedSaveImage */ + xenUnifiedDomainManagedSaveRemove, /* domainManagedSaveRemove */ NULL, /* domainSnapshotCreateXML */ NULL, /* domainSnapshotDumpXML */ NULL, /* domainSnapshotNum */ diff --git a/src/xen/xen_driver.h b/src/xen/xen_driver.h index 53f97d4..59276eb 100644 --- a/src/xen/xen_driver.h +++ b/src/xen/xen_driver.h @@ -99,6 +99,9 @@ struct xenUnifiedDriver { virDrvDomainGetSchedulerType domainGetSchedulerType; virDrvDomainGetSchedulerParameters domainGetSchedulerParameters; virDrvDomainSetSchedulerParameters domainSetSchedulerParameters; + virDrvDomainManagedSave domainManagedSave; + virDrvDomainHasManagedSaveImage domainHasManagedSaveImage; + virDrvDomainManagedSaveRemove domainManagedSaveRemove; }; typedef struct xenXMConfCache *xenXMConfCachePtr; diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index b90c331..245384f 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -952,7 +952,7 @@ xenDaemonListDomainsOld(virConnectPtr xend) * @xend: A xend instance * @sexpr: An S-Expr description of the domain. * - * This method will create a domain based the passed in description. The + * This method will create a domain based on the passed in description. The * domain will be paused after creation and must be unpaused with * xenDaemonResumeDomain() to begin execution. * This method may be deprecated once switching to XML-RPC based communcations @@ -2680,6 +2680,20 @@ error: } #endif /* !PROXY */ +static char * +xenDaemonDomainManagedSavePath(virDomainPtr dom) { + char *ret; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + virUUIDFormat(dom->uuid, uuidstr); + if (virAsprintf(&ret, "%s/%s/checkpoint.chk", XEND_DOMAINS_DIR, uuidstr) < 0) { + virReportOOMError(); + return(NULL); + } + + return(ret); +} + /***************************************************************** ****** ****** @@ -4656,8 +4670,10 @@ virDomainPtr xenDaemonDomainDefineXML(virConnectPtr conn, const char *xmlDesc) { virDomainDefFree(def); return (NULL); } + int xenDaemonDomainCreate(virDomainPtr domain) { + char *managed_save; xenUnifiedPrivatePtr priv; int ret; virDomainPtr tmp; @@ -4672,6 +4688,22 @@ int xenDaemonDomainCreate(virDomainPtr domain) if (priv->xendConfigVersion < 3) return(-1); + /* + * If there is a managed saved state restore it instead of starting + * from scratch. In any case the old state is removed. + */ + managed_save = xenDaemonDomainManagedSavePath(domain); + if ((managed_save) && (virFileExists(managed_save))) { + ret = xend_op(domain->conn, domain->name, "op", "resume", NULL); + + if (unlink(managed_save) < 0) { + VIR_WARN("Failed to remove the managed state %s", managed_save); + } + + if (ret == 0) + goto cleanup; + } + ret = xend_op(domain->conn, domain->name, "op", "start", NULL); if (ret != -1) { @@ -4682,6 +4714,9 @@ int xenDaemonDomainCreate(virDomainPtr domain) virDomainFree(tmp); } } + +cleanup: + VIR_FREE(managed_save); return ret; } @@ -4737,6 +4772,19 @@ xenDaemonNumOfDefinedDomains(virConnectPtr conn) ret++; } + sexpr_free(root); + + root = sexpr_get(conn, "/xend/domain?state=suspended"); + if (root == NULL) + goto error; + + for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS; + _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) { + if (node->kind != SEXPR_VALUE) + continue; + ret++; + } + error: sexpr_free(root); return(ret); @@ -4777,6 +4825,26 @@ xenDaemonListDefinedDomains(virConnectPtr conn, char **const names, int maxnames break; } + sexpr_free(root); + + root = sexpr_get(conn, "/xend/domain?state=suspended"); + if (root == NULL) + goto error; + + for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS; + _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) { + if (node->kind != SEXPR_VALUE) + continue; + + if ((names[ret++] = strdup(node->u.value)) == NULL) { + virReportOOMError(); + goto error; + } + + if (ret >= maxnames) + break; + } + cleanup: sexpr_free(root); return(ret); @@ -5071,7 +5139,7 @@ error: /** * xenDaemonDomainBlockPeek: - * @dom: domain object + * @domain: domain object * @path: path to the file or device * @offset: offset * @size: size @@ -5159,6 +5227,124 @@ xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path, return ret; } +/** + * xenDaemonDomainManagedSave: + * @domain: pointer to the domain + * @flags: optional flags currently unused + * + * This method will suspend a domain and save its memory contents to + * a file on disk. After the call, if successful, the domain is not + * listed as running anymore. + * The difference from virDomainSave() is that libvirt is keeping track of + * the saved state itself, and will reuse it once the domain is being + * restarted (automatically or via an explicit libvirt call). + * As a result any running domain is sure to not have a managed saved image. + * + * Returns 0 in case of success or -1 in case of failure + */ +int +xenDaemonDomainManagedSave(virDomainPtr domain, unsigned int flags) +{ + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) { + virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + + if (domain->id < 0) { + virXendError(VIR_ERR_OPERATION_INVALID, + _("Domain %s isn't running."), domain->name); + return(-1); + } + + /* We can't save the state of Domain-0, that would mean stopping it too */ + if (domain->id == 0) { + return(-1); + } + + virCheckFlags(0, -1); + + return xend_op(domain->conn, domain->name, "op", "suspend", NULL); +} + +/** + * xenDaemonDomainHasManagedSaveImage: + * @domain: pointer to the domain + * @flags: optional flags currently unused + * + * Check if a domain has a managed save image as created by + * virDomainManagedSave(). Note that any running domain should not have + * such an image, as it should have been removed on restart. + * + * Returns 0 if no image is present, 1 if an image is present, and + * -1 in case of error + */ +int +xenDaemonDomainHasManagedSaveImage(virDomainPtr domain, unsigned int flags) +{ + char *name = NULL; + int ret = -1; + + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) { + virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + + /* We can't save the state of Domain-0, that would mean stopping it too */ + if (domain->id == 0) { + return(-1); + } + + virCheckFlags(0, -1); + + name = xenDaemonDomainManagedSavePath(domain); + if (name == NULL) + goto cleanup; + + ret = virFileExists(name); + +cleanup: + VIR_FREE(name); + return ret; +} + +/** + * xenDaemonDomainManagedSaveRemove: + * @domain: pointer to the domain + * @flags: optional flags currently unused + * + * Remove any managed save image for this domain. + * + * Returns 0 in case of success, and -1 in case of error + */ +int +xenDaemonDomainManagedSaveRemove(virDomainPtr domain, unsigned int flags) +{ + char *name = NULL; + int ret = -1; + + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) { + virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + + /* We can't save the state of Domain-0, that would mean stopping it too */ + if (domain->id == 0) { + return(-1); + } + + virCheckFlags(0, -1); + + name = xenDaemonDomainManagedSavePath(domain); + if (name == NULL) + goto cleanup; + + ret = unlink(name); + +cleanup: + VIR_FREE(name); + return ret; +} + struct xenUnifiedDriver xenDaemonDriver = { xenDaemonOpen, /* open */ xenDaemonClose, /* close */ @@ -5197,6 +5383,9 @@ struct xenUnifiedDriver xenDaemonDriver = { xenDaemonGetSchedulerType, /* domainGetSchedulerType */ xenDaemonGetSchedulerParameters, /* domainGetSchedulerParameters */ xenDaemonSetSchedulerParameters, /* domainSetSchedulerParameters */ + xenDaemonDomainManagedSave, /* domainManagedSave */ + xenDaemonDomainHasManagedSaveImage, /* domainHasManagedSaveImage */ + xenDaemonDomainManagedSaveRemove, /* domainManagedSaveRemove */ }; /************************************************************************ diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h index 53f5d2c..af97b88 100644 --- a/src/xen/xend_internal.h +++ b/src/xen/xend_internal.h @@ -144,6 +144,9 @@ int xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info); char *xenDaemonDomainDumpXML(virDomainPtr domain, int flags, const char *cpus); unsigned long xenDaemonDomainGetMaxMemory(virDomainPtr domain); char **xenDaemonListDomainsOld(virConnectPtr xend); +int xenDaemonDomainManagedSave(virDomainPtr dom, unsigned int flags); +int xenDaemonDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags); +int xenDaemonDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags); virDomainPtr xenDaemonDomainDefineXML(virConnectPtr xend, const char *sexpr); int xenDaemonDomainCreate(virDomainPtr domain); diff --git a/tools/Makefile.am b/tools/Makefile.am index bfe4455..9ee9363 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -38,6 +38,7 @@ virt-pki-validate.1: virt-pki-validate virsh_SOURCES = \ console.c console.h \ + @top_srcdir@/daemon/event.c \ virsh.c virsh_LDFLAGS = $(WARN_LDFLAGS) $(COVERAGE_LDFLAGS) @@ -52,6 +53,7 @@ virsh_CFLAGS = \ -I../include -I$(top_srcdir)/include \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/util \ + -I$(top_srcdir) \ -DGETTEXT_PACKAGE=\"$(PACKAGE)\" \ -DLOCALEBASEDIR=\""$(datadir)/locale"\" \ $(WARN_CFLAGS) \ diff --git a/tools/virsh.c b/tools/virsh.c index 3e37b06..9cea612 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -50,6 +50,7 @@ #include "util.h" #include "memory.h" #include "xml.h" +#include "daemon/event.h" static char *progname; @@ -11068,6 +11069,13 @@ vshInit(vshControl *ctl) /* set up the signals handlers to catch disconnections */ vshSetupSignals(); + virEventRegisterImpl(virEventAddHandleImpl, + virEventUpdateHandleImpl, + virEventRemoveHandleImpl, + virEventAddTimeoutImpl, + virEventUpdateTimeoutImpl, + virEventRemoveTimeoutImpl); + ctl->conn = virConnectOpenAuth(ctl->name, virConnectAuthPtrDefault, ctl->readonly ? VIR_CONNECT_RO : 0);