Skip to contentSkip to conversation

Teach xm save to checkpoint a running domain

PATCH New Brendan Cully 3 participants 13 messages Jan 12, 2007 Arm/actions semi architecture

lore
Share & tools
lore
#0 lore raw

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.

#1 lore raw

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
diff -r a84fc0de350d -r 4514d8e0843c xen/common/domctl.c
@@ -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
diff -r a84fc0de350d -r 4514d8e0843c xen/include/public/domctl.h
@@ -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      5
 struct xen_domctl_getdomaininfo {
#2 lore raw

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 ID 4514d8e0843ca4e46128dd43e3f0d2b04b24ff92 # Parent a84fc0de350d276cb2b3359102f6fda32bc18922 Add resumedomain domctl to resume a domain after checkpoint.

diff -r a84fc0de350d -r 4514d8e0843c xen/common/domctl.c

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;

diff -r a84fc0de350d -r 4514d8e0843c xen/include/public/domctl.h

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      5
 struct xen_domctl_getdomaininfo {

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

#3 lore raw

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_area 26
struct xen_domctl_real_mode_area {
uint32_t log; /* 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
diff -r 8fdd24d1dfbf -r 74431b023b3c xen/common/domctl.c
@@ -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
diff -r 8fdd24d1dfbf -r 74431b023b3c xen/include/public/domctl.h
@@ -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      5
 struct xen_domctl_getdomaininfo {

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

#4 lore raw

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
diff -r 4514d8e0843c -r 30e07c0e462b tools/libxc/xc_domain.c
@@ -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
diff -r 4514d8e0843c -r 30e07c0e462b tools/libxc/xenctrl.h
@@ -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
#5 lore raw

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
diff -r 30e07c0e462b -r 2cdbd7c62a0e tools/python/xen/lowlevel/xc/xc.c
@@ -160,6 +160,10 @@ static PyObject *pyxc_domain_destroy(XcO
     return 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
diff -r 30e07c0e462b -r 2cdbd7c62a0e tools/python/xen/xend/XendDomainInfo.py
@@ -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
     # 
#6 lore raw

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
diff -r 2cdbd7c62a0e -r c6154e7b94ab tools/xenstore/xenstored_core.c
@@ -164,6 +164,7 @@ static char *sockmsg_string(enum xsd_soc
 	case 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 conne
 
 	case 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
diff -r 2cdbd7c62a0e -r c6154e7b94ab tools/xenstore/xenstored_domain.c
@@ -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
diff -r 2cdbd7c62a0e -r c6154e7b94ab tools/xenstore/xenstored_domain.h
@@ -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
diff -r 2cdbd7c62a0e -r c6154e7b94ab tools/xenstore/xs.c
@@ -719,6 +719,12 @@ bool xs_release_domain(struct xs_handle 
 	return 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
diff -r 2cdbd7c62a0e -r c6154e7b94ab tools/xenstore/xs.h
@@ -133,6 +133,11 @@ bool xs_introduce_domain(struct xs_handl
 			 unsigned 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
diff -r 2cdbd7c62a0e -r c6154e7b94ab xen/include/public/io/xs_wire.h
@@ -45,7 +45,8 @@ enum xsd_sockmsg_type
     XS_SET_PERMS,
     XS_WATCH_EVENT,
     XS_ERROR,
-    XS_IS_DOMAIN_INTRODUCED
+    XS_IS_DOMAIN_INTRODUCED,
+    XS_RESUME
 };
 
 #define XS_WRITE_NONE "NONE"
#7 lore raw

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
diff -r c6154e7b94ab -r 5ae12d620c6d tools/python/xen/lowlevel/xs/xs.c
@@ -618,6 +618,33 @@ static PyObject *xspy_introduce_domain(X
     return 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
diff -r c6154e7b94ab -r 5ae12d620c6d tools/python/xen/xend/XendDomainInfo.py
@@ -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
diff -r c6154e7b94ab -r 5ae12d620c6d tools/python/xen/xend/xenstore/xsutil.py
@@ -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)
#8 lore raw

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
diff -r 5ae12d620c6d -r b5414e713c97 tools/libxc/xc_linux_restore.c
@@ -690,6 +690,8 @@ int xc_linux_restore(int xc_handle, int 
         ERROR("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);
#9 lore raw

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

#10 lore raw

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.

#11 lore raw

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
diff -r b5414e713c97 -r b10287396924 linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c
@@ -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
diff -r b5414e713c97 -r b10287396924 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
@@ -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
diff -r b5414e713c97 -r b10287396924 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c
@@ -668,31 +668,23 @@ EXPORT_SYMBOL_GPL(unregister_xenbus_watc
 
 void 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
diff -r b5414e713c97 -r b10287396924 linux-2.6-xen-sparse/include/xen/xenbus.h
@@ -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) {		\
#12 lore raw

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
diff -r b10287396924 -r 086b3085b3ef tools/python/xen/xend/XendCheckpoint.py
@@ -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
diff -r b10287396924 -r 086b3085b3ef tools/python/xen/xend/XendDomain.py
@@ -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
diff -r b10287396924 -r 086b3085b3ef tools/python/xen/xm/main.py
@@ -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)