Teach xm save to checkpoint a running domain
PATCH 1/1 Teach xm save to checkpoint a running domain
Here's version 2 of the checkpointing code, incorporating some of Keir's feedback on version 1.
It adds a -c flag to xm save that indicates that the parent domain should continue running after the checkpoint has been taken. The checkpoint path is much more like the regular suspend path in this version of the patch series.
PATCH 1/1 Add resumedomain domctl to resume a domain after checkpoint
# HG changeset patch
# User Brendan Cully <[email protected]>
# Date 1168565202 28800
# Node ID 4514d8e0843ca4e46128dd43e3f0d2b04b24ff92 # Parent a84fc0de350d276cb2b3359102f6fda32bc18922 Add resumedomain domctl to resume a domain after checkpoint.
xen/common/domctl.c +25 -0
@@ -250,6 +250,31 @@ ret_t do_domctl(XEN_GUEST_HANDLE(xen_dom }break ; +case XEN_DOMCTL_resumedomain: + { +struct domain *d =find_domain_by_id (op->domain); +struct vcpu *v; + + ret = -ESRCH ; +if ( d !=NULL ) + { + ret = -EINVAL ; +printk ("Resuming domain %d\n" , op->domain); +if ( (d != current->domain) && (d->vcpu[0 ] !=NULL ) && +test_bit (_DOMF_shutdown, &d->domain_flags) ) + { +clear_bit (_DOMF_shutdown, &d->domain_flags); + +for_each_vcpu (d, v) + vcpu_wake (v); + + ret =0 ; + } +put_domain (d); + } + } +break ; +case XEN_DOMCTL_createdomain: {struct domain *d;
xen/include/public/domctl.h +1 -0
@@ -63,6 +63,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_creat#define XEN_DOMCTL_destroydomain 2#define XEN_DOMCTL_pausedomain 3#define XEN_DOMCTL_unpausedomain 4 +#define XEN_DOMCTL_resumedomain 26#define XEN_DOMCTL_getdomaininfo 5struct xen_domctl_getdomaininfo {
Re: [PATCH 1 of 8] Add resumedomain domctl to resume adomain after checkpoint
Hi Brendan,
The 26th is already defined at line 390 in domctl.h.
#define XEN_DOMCTL_real_mode_area 26
struct xen_domctl_real_mode_area {
uint32_t log; /* log2 of Real Mode Area size */
};
Best regards,
Kan
Quoted 60 lines
# HG changeset patch
# User Brendan Cully <[email protected]>
# Date 1168565202 28800
# Node ID4514d8e0843ca4e46128dd43e3f0d2b04b24ff92# Parenta84fc0de350d276cb2b3359102f6fda32bc18922Add resumedomain domctl to resume a domain after checkpoint.Signed-off-by Brendan Cully <[email protected]>diff -r
a84fc0de350d-r4514d8e0843cxen/common/domctl.cxen/common/domctl.c +25
-0@@ -250,6 +250,31 @@ ret_t do_domctl(XEN_GUEST_HANDLE(xen_dom }break ; +case XEN_DOMCTL_resumedomain: + { +struct domain *d =find_domain_by_id (op->domain); +struct vcpu *v; + + ret = -ESRCH ; +if ( d !=NULL ) + { + ret = -EINVAL ; +printk ("Resuming domain %d\n" , op->domain); +if ( (d != current->domain) && (d->vcpu[0 ] !=NULL ) && +test_bit (_DOMF_shutdown, &d->domain_flags) ) + { +clear_bit (_DOMF_shutdown, &d->domain_flags); + +for_each_vcpu (d, v) + vcpu_wake (v); + + ret =0 ; + } +put_domain (d); + } + } +break ; +case XEN_DOMCTL_createdomain: {struct domain *d;diff -r
a84fc0de350d-r4514d8e0843cxen/include/public/domctl.hxen/include/public/domctl.h +1
-0@@ -63,6 +63,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_creat#define XEN_DOMCTL_destroydomain 2#define XEN_DOMCTL_pausedomain 3#define XEN_DOMCTL_unpausedomain 4 +#define XEN_DOMCTL_resumedomain 26#define XEN_DOMCTL_getdomaininfo 5struct xen_domctl_getdomaininfo {_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Re: [PATCH 1 of 8] Add resumedomain domctl to resume adomain after checkpoint
Quoted 1 line · Masaki Kanno
Hi Brendan,
That was fast!
Quoted 6 lines
The 26th is already defined at line 390 in
domctl.h.#define
XEN_DOMCTL_real_mode_area26
structxen_domctl_real_mode_area{
uint32_tlog; /* log2 of Real Mode Area size */
};
Whoops, thanks. That snuck in after I wrote the first patch series, I think. Here's a replacement.
# HG changeset patch
# User Brendan Cully <[email protected]>
# Date 1168566620 28800
# Node ID 74431b023b3cfb12968717d025d48aa27a651e72 # Parent 8fdd24d1dfbfb6134313c83832d9fefa77d6ec3f Add resumedomain domctl to resume a domain after checkpoint.
xen/common/domctl.c +25 -0
@@ -250,6 +250,31 @@ ret_t do_domctl(XEN_GUEST_HANDLE(xen_dom }break ; +case XEN_DOMCTL_resumedomain: + { +struct domain *d =find_domain_by_id (op->domain); +struct vcpu *v; + + ret = -ESRCH ; +if ( d !=NULL ) + { + ret = -EINVAL ; +printk ("Resuming domain %d\n" , op->domain); +if ( (d != current->domain) && (d->vcpu[0 ] !=NULL ) && +test_bit (_DOMF_shutdown, &d->domain_flags) ) + { +clear_bit (_DOMF_shutdown, &d->domain_flags); + +for_each_vcpu (d, v) + vcpu_wake (v); + + ret =0 ; + } +put_domain (d); + } + } +break ; +case XEN_DOMCTL_createdomain: {struct domain *d;
xen/include/public/domctl.h +1 -0
@@ -63,6 +63,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_creat#define XEN_DOMCTL_destroydomain 2#define XEN_DOMCTL_pausedomain 3#define XEN_DOMCTL_unpausedomain 4 +#define XEN_DOMCTL_resumedomain 27#define XEN_DOMCTL_getdomaininfo 5struct xen_domctl_getdomaininfo {
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
PATCH 1/1 Export resumedomain domctl to libxc
In reply to Brendan Cully# HG changeset patch
# User Brendan Cully <[email protected]>
# Date 1168565202 28800
# Node ID 30e07c0e462be0d6237ac461b1fd1ba046dbe7c1 # Parent 4514d8e0843ca4e46128dd43e3f0d2b04b24ff92 Export resumedomain domctl to libxc.
tools/libxc/xc_domain.c +10 -0
@@ -86,6 +86,16 @@ int xc_domain_shutdown(int xc_handle, out1:return ret; +} + + +int xc_domain_resume (int xc_handle, +uint32_t domid) +{ +DECLARE_DOMCTL ; + domctl.cmd = XEN_DOMCTL_resumedomain; + domctl.domain = (domid_t )domid; +return do_domctl (xc_handle, &domctl); }
tools/libxc/xenctrl.h +12 -0
@@ -236,6 +236,18 @@ int xc_domain_destroy(int xc_handle,int xc_domain_destroy (int xc_handle,uint32_t domid); + +/** +* This function resumes a suspended domain. The domain should have +* been previously suspended. +* +* @parm xc_handle a handle to an open hypervisor interface +* @parm domid the domain id to resume +* return 0 on success, -1 on failure +*/ +int xc_domain_resume (int xc_handle, +uint32_t domid); +/** * This function will shutdown a domain. This is intended for use in * fully-virtualized domains where this operation is analogous to the
PATCH 1/1 Export xc_domain_resume to xend
In reply to Brendan Cully# HG changeset patch
# User Brendan Cully <[email protected]>
# Date 1168565202 28800
# Node ID 2cdbd7c62a0efe182082317a7f4bd3fde73e925b # Parent 30e07c0e462be0d6237ac461b1fd1ba046dbe7c1 Export xc_domain_resume to xend.
tools/python/xen/lowlevel/xc/xc.c +11 -0
@@ -160,6 +160,10 @@ static PyObject *pyxc_domain_destroy(XcOreturn dom_op (self, args, xc_domain_destroy); } +static PyObject *pyxc_domain_resume (XcObject *self,PyObject *args) +{ +return dom_op (self, args, xc_domain_resume); +} static PyObject *pyxc_vcpu_setaffinity(XcObject *self, PyObject *args,
@@ -1027,6 +1031,13 @@ static PyMethodDef pyxc_methods[] = {METH_VARARGS ,"\n" "Destroy a domain.\n" " dom [int]: Identifier of domain to be destroyed.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "domain_resume", + (PyCFunction )pyxc_domain_resume, +METH_VARARGS ,"\n" +"Resume execution of a suspended domain.\n" +" dom [int]: Identifier of domain to be resumed.\n\n" "Returns: [int] 0 on success; -1 on error.\n" }, { "vcpu_setaffinity",
tools/python/xen/xend/XendDomainInfo.py +9 -0
@@ -1528,6 +1528,15 @@ class XendDomainInfo: self.cleanupDomain() + def resumeDomain(self): + log.debug("XendDomainInfo.resumeDomain(%s)", str(self.domid)) + + try: + if self.domid is not None: + xc.domain_resume(self.domid) + except: + log.exception("XendDomainInfo.resume: xc.domain_resume failed on domain %s." % (str(self.domid))) + # # Channels for xenstore and console #
PATCH 1/1 Add XS_RESUME command
In reply to Brendan Cully# HG changeset patch
# User Brendan Cully <[email protected]>
# Date 1168565202 28800
# Node ID c6154e7b94abb94793b43ddc8e1f550fdb8f1a58 # Parent 2cdbd7c62a0efe182082317a7f4bd3fde73e925b Add XS_RESUME command.
This clears the shutdown flag for a domain in xenstore, allowing subsequent shutdowns of the same domain to fire the appropriate watches.
tools/xenstore/xenstored_core.c +5 -0
@@ -164,6 +164,7 @@ static char *sockmsg_string(enum xsd_soccase XS_WATCH_EVENT :return "WATCH_EVENT" ;case XS_ERROR :return "ERROR" ;case XS_IS_DOMAIN_INTRODUCED :return "XS_IS_DOMAIN_INTRODUCED" ; +case XS_RESUME :return "RESUME" ;default :return "**UNKNOWN**" ; }
@@ -1265,6 +1266,10 @@ static void process_message(struct connecase XS_GET_DOMAIN_PATH :do_get_domain_path (conn,onearg (in)); +break ; + +case XS_RESUME : +do_resume (conn,onearg (in));break ;default :
tools/xenstore/xenstored_domain.c +37 -0
@@ -395,6 +395,43 @@ void do_release(struct connection *conn,send_ack (conn,XS_RELEASE ); } +void do_resume (struct connection *conn,const char *domid_str) +{ +struct domain *domain; +unsigned int domid; + +if (!domid_str) { +send_error (conn,EINVAL ); +return ; + } + + domid =atoi (domid_str); +if (!domid) { +send_error (conn,EINVAL ); +return ; + } + +if (conn->id !=0 ) { +send_error (conn,EACCES ); +return ; + } + + domain =find_domain_by_domid (domid); +if (!domain) { +send_error (conn,ENOENT ); +return ; + } + +if (!domain->conn) { +send_error (conn,EINVAL ); +return ; + } + + domain->shutdown =0 ; + +send_ack (conn,XS_RESUME ); +} +void do_get_domain_path (struct connection *conn,const char *domid_str) {char *path;
tools/xenstore/xenstored_domain.h +3 -0
@@ -32,6 +32,9 @@ void do_release(struct connection *conn,void do_release (struct connection *conn,const char *domid_str);/* domid */ +void do_resume (struct connection *conn,const char *domid_str); + +/* domid */ void do_get_domain_path (struct connection *conn,const char *domid_str);/* Returns the event channel handle */
tools/xenstore/xs.c +6 -0
@@ -719,6 +719,12 @@ bool xs_release_domain(struct xs_handlereturn xs_bool (single_with_domid (h,XS_RELEASE , domid)); } +/* clear the shutdown bit for the given domain */ +bool xs_resume_domain (struct xs_handle *h,unsigned int domid) +{ +return xs_bool (single_with_domid (h,XS_RESUME , domid)); +} +char *xs_get_domain_path (struct xs_handle *h,unsigned int domid) {char domid_str[MAX_STRLEN (domid)];
tools/xenstore/xs.h +5 -0
@@ -133,6 +133,11 @@ bool xs_introduce_domain(struct xs_handlunsigned int domid, unsigned long mfn, unsigned int eventchn); +/* Resume a domain. +* Clear the shutdown flag for this domain in the store. +*/ +bool xs_resume_domain (struct xs_handle *h,unsigned int domid); +/* Release a domain. * Tells the store domain to release the memory page to the domain. */
xen/include/public/io/xs_wire.h +2 -1
@@ -45,7 +45,8 @@ enum xsd_sockmsg_typeXS_SET_PERMS ,XS_WATCH_EVENT ,XS_ERROR , - XS_IS_DOMAIN_INTRODUCED +XS_IS_DOMAIN_INTRODUCED , + XS_RESUME };#define XS_WRITE_NONE "NONE"
PATCH 1/1 Export XS_RESUME to xend
In reply to Brendan Cully# HG changeset patch
# User Brendan Cully <[email protected]>
# Date 1168565202 28800
# Node ID 5ae12d620c6d8af00eed66ed37c988150984b1f0 # Parent c6154e7b94abb94793b43ddc8e1f550fdb8f1a58 Export XS_RESUME to xend.
tools/python/xen/lowlevel/xs/xs.c +28 -0
@@ -618,6 +618,33 @@ static PyObject *xspy_introduce_domain(Xreturn none (result); } +#define xspy_resume_domain_doc "\n" \ + "Tell xenstore to clear its shutdown flag for a domain.\n" \ + "This ensures that a subsequent shutdown will fire the\n" \ + "appropriate watches.\n" \ + " dom [int]: domain id\n" \ + "\n" \ + "Returns None on success.\n" \ + "Raises xen.lowlevel.xs.Error on error.\n" + +static PyObject *xspy_resume_domain (XsHandle *self,PyObject *args) +{ +uint32_t dom; + +struct xs_handle *xh =xshandle (self); +bool result =0 ; + +if (!xh) +return NULL ; +if (!PyArg_ParseTuple (args,"i" , &dom)) +return NULL ; + +Py_BEGIN_ALLOW_THREADS + result =xs_resume_domain (xh, dom); +Py_END_ALLOW_THREADS + + return none(result); +}#define xspy_release_domain_doc "\n" \ "Tell xenstore to release its channel to a domain.\n" \
@@ -789,6 +816,7 @@ static PyMethodDef xshandle_methods[] =XSPY_METH (transaction_start,METH_NOARGS ),XSPY_METH (transaction_end,METH_VARARGS |METH_KEYWORDS ),XSPY_METH (introduce_domain,METH_VARARGS ), +XSPY_METH (resume_domain,METH_VARARGS ),XSPY_METH (release_domain,METH_VARARGS ),XSPY_METH (close,METH_NOARGS ), XSPY_METH(get_domain_path, METH_VARARGS),
tools/python/xen/xend/XendDomainInfo.py +2 -1
@@ -45,7 +45,7 @@ from xen.xend.XendError import XendError from xen.xend.XendError import XendError, VmError from xen.xend.XendDevices import XendDevices from xen.xend.xenstore.xstransact import xstransact, complete -from xen.xend.xenstore.xsutil import GetDomainPath, IntroduceDomain +from xen.xend.xenstore.xsutil import GetDomainPath, IntroduceDomain, ResumeDomain from xen.xend.xenstore.xswatch import xswatch from xen.xend.XendConstants import * from xen.xend.XendAPIConstants import *
@@ -1534,6 +1534,7 @@ class XendDomainInfo: try: if self.domid is not None: xc.domain_resume(self.domid) + ResumeDomain(self.domid) except: log.exception("XendDomainInfo.resume: xc.domain_resume failed on domain %s." % (str(self.domid)))
tools/python/xen/xend/xenstore/xsutil.py +3 -0
@@ -24,3 +24,6 @@ def IntroduceDomain(domid, page, port): def GetDomainPath(domid): return xshandle().get_domain_path(domid) + +def ResumeDomain(domid): + return xshandle().resume_domain(domid)
PATCH 1/1 Make suspend hypercall return 1 when the domain has been resumed
In reply to Brendan Cully# HG changeset patch
# User Brendan Cully <[email protected]>
# Date 1168565202 28800
# Node ID b5414e713c97fff9b13c290f3a80d42183665e0e
# Parent 5ae12d620c6d8af00eed66ed37c988150984b1f0
Make suspend hypercall return 1 when the domain has been resumed.
This patch writes 1 into EAX when the domain has been resumed, alerting the guest domain that it needs to reconnect to its back ends.
tools/libxc/xc_linux_restore.c +2 -0
@@ -690,6 +690,8 @@ int xc_linux_restore(int xc_handle, intERROR ("Suspend record frame number is bad" ); goto out; } +/* HYPERVISOR_suspend returns 1 to let guest know it should reconnect */ + ctxt.user_regs.eax =1 ; ctxt.user_regs.edx = mfn = p2m[pfn]; start_info =xc_map_foreign_range ( xc_handle, dom,PAGE_SIZE ,PROT_READ |PROT_WRITE , mfn);
Re: [PATCH 6 of 8] Make suspend hypercall return 1 when the domain has been resumed
Quoted 1 line · Brendan Cully
Make suspend hypercall return 1 when the domain has been resumed.
How does a domain identify itself as being able to handle this? Shouldn't you be checking for an elfnote?
regards
john
Re: [PATCH 6 of 8] Make suspend hypercall return 1 when the domain has been resumed
Quoted 6 lines · John Levon
Quoted 1 line · Brendan Cully
Make suspend hypercall return 1 when the domain has been resumed.
How does a domain identify itself as being able to handle this? Shouldn't you be checking for an elfnote?
I've just posted a small set of patches on top of this series to address backward compatibility.
PATCH 1/1 Make xen_suspend handle resume
In reply to Brendan Cully# HG changeset patch
# User Brendan Cully <[email protected]>
# Date 1168565202 28800
# Node ID b10287396924bf9973987cc3bfeb442847189e21 # Parent b5414e713c97fff9b13c290f3a80d42183665e0e Make xen_suspend handle resume.
Don't destroy xenstore watches on suspend, and only recreate them when resuming in a new domain. Likewise, only invoke frontend device resume code when in a new domain (the resume functions all tear down the existing function and wait for the backend to negotiate a new one, which does not happen in the source domain).
linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c +19 -9
@@ -85,13 +85,20 @@ static void pre_suspend(void)mfn_to_pfn (xen_start_info->console.domU.mfn); } -static void post_suspend (void ) +static void post_suspend (int reconnect) {int i, j, k, fpp;extern unsigned long max_pfn;extern unsigned long *pfn_to_mfn_frame_list_list;extern unsigned long *pfn_to_mfn_frame_list[]; +if (!reconnect) { + xen_start_info->store_mfn = +pfn_to_mfn (xen_start_info->store_mfn); + xen_start_info->console.domU.mfn = +pfn_to_mfn (xen_start_info->console.domU.mfn); + } +set_fixmap (FIX_SHARED_INFO , xen_start_info->shared_info); HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt (FIX_SHARED_INFO );
@@ -120,7 +127,7 @@ static void post_suspend(void)#define switch_idle_mm () ((void)0)#define mm_pin_all () ((void)0)#define pre_suspend () ((void)0) -#define post_suspend () ((void)0) +#define post_suspend (x) ((void)0)#endif
@@ -158,16 +165,18 @@ int __xen_suspend(void)pre_suspend ();/* -* We'll stop somewhere inside this hypercall. When it returns, -* we'll start resuming after the restore. +* This hypercall returns 0 if suspend was cancelled or +* the domain was merely checkpointed, and 1 if it is +* resuming in a new domain. */ -HYPERVISOR_suspend (virt_to_mfn (xen_start_info)); + err =HYPERVISOR_suspend (virt_to_mfn (xen_start_info)); -post_suspend (); +post_suspend (err);gnttab_resume (); -irq_resume (); +if (err) +irq_resume ();time_resume ();
@@ -175,9 +184,10 @@ int __xen_suspend(void)local_irq_enable (); -xencons_resume (); +if (err) +xencons_resume (); -xenbus_resume (); +xenbus_resume (err);smp_resume ();
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +9 -5
@@ -727,11 +727,15 @@ void xenbus_suspend(void) }EXPORT_SYMBOL_GPL (xenbus_suspend); -void xenbus_resume (void ) -{ -xb_init_comms (); -xs_resume (); -bus_for_each_dev (&xenbus_frontend.bus,NULL ,NULL , resume_dev); +void xenbus_resume (int reconnect) +{ +if (reconnect) +xb_init_comms (); +xs_resume (reconnect); + +if (reconnect) { +bus_for_each_dev (&xenbus_frontend.bus,NULL ,NULL , resume_dev); + }xenbus_backend_resume (resume_dev); }EXPORT_SYMBOL_GPL (xenbus_resume);
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c +12 -20
@@ -668,31 +668,23 @@ EXPORT_SYMBOL_GPL(unregister_xenbus_watcvoid xs_suspend (void ) { +down_write (&xs_state.suspend_mutex); +mutex_lock (&xs_state.request_mutex); +} + +void xs_resume (int reconnect) +{struct xenbus_watch *watch;char token[sizeof (watch) *2 +1 ]; -down_write (&xs_state.suspend_mutex); - -/* No need for watches_lock: the suspend_mutex is sufficient. */ -list_for_each_entry (watch, &watches, list) { -sprintf (token,"%lX" , (long )watch); -xs_unwatch (watch->node, token); - } - -mutex_lock (&xs_state.request_mutex); -} - -void xs_resume (void ) -{ -struct xenbus_watch *watch; -char token[sizeof (watch) *2 +1 ]; -mutex_unlock (&xs_state.request_mutex); -/* No need for watches_lock: the suspend_mutex is sufficient. */ -list_for_each_entry (watch, &watches, list) { -sprintf (token,"%lX" , (long )watch); -xs_watch (watch->node, token); +if (reconnect) { +/* No need for watches_lock: the suspend_mutex is sufficient. */ +list_for_each_entry (watch, &watches, list) { +sprintf (token,"%lX" , (long )watch); +xs_watch (watch->node, token); + } }up_write (&xs_state.suspend_mutex);
linux-2.6-xen-sparse/include/xen/xenbus.h +2 -2
@@ -159,14 +159,14 @@ int register_xenbus_watch(struct xenbus_int register_xenbus_watch (struct xenbus_watch *watch);void unregister_xenbus_watch (struct xenbus_watch *watch);void xs_suspend (void ); -void xs_resume (void ); +void xs_resume (int reconnect);/* Used by xenbus_dev to borrow kernel's store connection. */ void *xenbus_dev_request_and_reply (struct xsd_sockmsg *msg);/* Called from xen core code. */ void xenbus_suspend (void ); -void xenbus_resume (void ); +void xenbus_resume (int reconnect);#define XENBUS_IS_ERR_READ (str) ({ \ if (!IS_ERR(str) && strlen(str) == 0) { \
PATCH 1/1 Add xm save -c/--checkpoint option
In reply to Brendan Cully# HG changeset patch
# User Brendan Cully <[email protected]>
# Date 1168565202 28800
# Node ID 086b3085b3ef106de92c86d7fbcd2d5c63291603 # Parent b10287396924bf9973987cc3bfeb442847189e21 Add xm save -c/--checkpoint option
xm save --checkpoint leaves the domain running after creating the snapshot.
tools/python/xen/xend/XendCheckpoint.py +5 -2
@@ -51,7 +51,7 @@ def read_exact(fd, size, errmsg): return buf -def save(fd, dominfo, network, live, dst): +def save(fd, dominfo, network, live, dst, checkpoint=False): write_exact(fd, SIGNATURE, "could not write guest state file: signature") config = sxp.to_string(dominfo.sxpr())
@@ -96,7 +96,8 @@ def save(fd, dominfo, network, live, dst forkHelper(cmd, fd, saveInputHandler, False) - dominfo.destroyDomain() + if not checkpoint: + dominfo.destroyDomain() try: dominfo.setName(domain_name) except VmError:
@@ -105,6 +106,8 @@ def save(fd, dominfo, network, live, dst # persistent VM, we need the rename, and don't expect the # conflict. This needs more thought. pass + if checkpoint: + dominfo.resumeDomain() except Exception, exn: log.exception("Save failed on domain %s (%s).", domain_name,
tools/python/xen/xend/XendDomain.py +3 -3
@@ -1177,7 +1177,7 @@ class XendDomain: dominfo.testDeviceComplete() sock.close() - def domain_save(self, domid, dst): + def domain_save(self, domid, dst, checkpoint): """Start saving a domain to file. @param domid: Domain ID or Name
@@ -1198,8 +1198,8 @@ class XendDomain: fd = os.open(dst, os.O_WRONLY | os.O_CREAT | os.O_TRUNC) try: - # For now we don't support 'live checkpoint' - XendCheckpoint.save(fd, dominfo, False, False, dst) + XendCheckpoint.save(fd, dominfo, False, False, dst, + checkpoint=checkpoint) finally: os.close(fd) except OSError, ex:
tools/python/xen/xm/main.py +26 -7
@@ -102,7 +102,7 @@ SUBCOMMAND_HELP = { 'reboot' : ('<Domain> [-wa]', 'Reboot a domain.'), 'restore' : ('<CheckpointFile> [-p]', 'Restore a domain from a saved state.'), - 'save' : ('<Domain> <CheckpointFile>', + 'save' : ('[-c] <Domain> <CheckpointFile>', 'Save a domain state to restore later.'), 'shutdown' : ('<Domain> [-waRH]', 'Shutdown a domain.'), 'top' : ('', 'Monitor a host and the domains in real time.'),
@@ -230,6 +230,9 @@ SUBCOMMAND_OPTIONS = { 'resume': ( ('-p', '--paused', 'Do not unpause domain after resuming it'), ), + 'save': ( + ('-c', '--checkpoint', 'Leave domain running after creating snapshot'), + ), 'restore': ( ('-p', '--paused', 'Do not unpause domain after restoring it'), ),
@@ -586,21 +589,37 @@ def xm_shell(args): ######################################################################### def xm_save(args): - arg_check(args, "save", 2) - - try: - dominfo = parse_doms_info(server.xend.domain(args[0])) + arg_check(args, "save", 2, 3) + + try: + (options, params) = getopt.gnu_getopt(args, 'c', ['checkpoint']) + except getopt.GetoptError, opterr: + err(opterr) + sys.exit(1) + + checkpoint = False + for (k, v) in options: + if k in ['-c', '--checkpoint']: + checkpoint = True + + if len(params) != 2: + err("Wrong number of parameters") + usage('save') + sys.exit(1) + + try: + dominfo = parse_doms_info(server.xend.domain(params[0])) except xmlrpclib.Fault, ex: raise ex domid = dominfo['domid'] - savefile = os.path.abspath(args[1]) + savefile = os.path.abspath(params[1]) if not os.access(os.path.dirname(savefile), os.W_OK): err("xm save: Unable to create file %s" % savefile) sys.exit(1) - server.xend.domain.save(domid, savefile) + server.xend.domain.save(domid, savefile, checkpoint) def xm_restore(args): arg_check(args, "restore", 1, 2)