]> xenbits.xensource.com Git - mini-os.git/commitdiff
Save/Restore Support: Add suspend/restore support for xenbus
authorBruno Alvisio <bruno.alvisio@gmail.com>
Mon, 11 Dec 2017 16:21:48 +0000 (08:21 -0800)
committerWei Liu <wei.liu2@citrix.com>
Wed, 21 Mar 2018 09:16:49 +0000 (09:16 +0000)
Currently the watch path is not saved in the watch struct when it is registered.
During xenbus resume the path is needed so that the watches can be registered again.
Thus, 'path' field is added to struct watch so that watches can be re-registered
during xenbus resume.

Signed-off-by: Bruno Alvisio <bruno.alvisio@gmail.com>
Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
include/xenbus.h
kernel.c
xenbus/xenbus.c

index b2d5072b53bc238086b898407a4c11a452f995db..3871f358f4721b4f568ab7e621fda0882cd9f56f 100644 (file)
@@ -120,6 +120,8 @@ domid_t xenbus_get_self_id(void);
 #ifdef CONFIG_XENBUS
 /* Reset the XenBus system. */
 void fini_xenbus(void);
+void suspend_xenbus(void);
+void resume_xenbus(int canceled);
 #else
 static inline void fini_xenbus(void)
 {
index 933cbcd7f346b26918b5dd86e706a60166d2c6cf..1393d15cc24159243760dcc5b3317984939cf5a0 100644 (file)
--- a/kernel.c
+++ b/kernel.c
@@ -119,6 +119,10 @@ void start_kernel(void* par)
 
 void pre_suspend(void)
 {
+#ifdef CONFIG_XENBUS
+    suspend_xenbus();
+#endif
+
     local_irq_disable();
 
     suspend_gnttab();
@@ -139,6 +143,10 @@ void post_suspend(int canceled)
     resume_gnttab();
 
     local_irq_enable();
+
+#ifdef CONFIG_XENBUS
+    resume_xenbus(canceled);
+#endif
 }
 
 void stop_kernel(void)
index c2d2bd1758575d5dbd20679d8e7484438877c7d1..d72dc3a0f5d942bc2664c12588d707a791a34b7e 100644 (file)
@@ -50,6 +50,7 @@ DECLARE_WAIT_QUEUE_HEAD(xenbus_watch_queue);
 xenbus_event_queue xenbus_events;
 static struct watch {
     char *token;
+    char *path;
     xenbus_event_queue *events;
     struct watch *next;
 } *watches;
@@ -63,6 +64,8 @@ struct xenbus_req_info
 #define NR_REQS 32
 static struct xenbus_req_info req_info[NR_REQS];
 
+static char *errmsg(struct xsd_sockmsg *rep);
+
 uint32_t xenbus_evtchn;
 
 #ifdef CONFIG_PARAVIRT
@@ -231,45 +234,39 @@ static void xenbus_thread_func(void *ign)
     struct xsd_sockmsg msg;
     unsigned prod = xenstore_buf->rsp_prod;
 
-    for (;;) 
-    {
+    for (;;) {
         wait_event(xb_waitq, prod != xenstore_buf->rsp_prod);
-        while (1) 
-        {
+        while (1) {
             prod = xenstore_buf->rsp_prod;
             DEBUG("Rsp_cons %d, rsp_prod %d.\n", xenstore_buf->rsp_cons,
-                    xenstore_buf->rsp_prod);
+                  xenstore_buf->rsp_prod);
             if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons < sizeof(msg))
                 break;
             rmb();
-            memcpy_from_ring(xenstore_buf->rsp,
-                    &msg,
-                    MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
-                    sizeof(msg));
-            DEBUG("Msg len %d, %d avail, id %d.\n",
-                    msg.len + sizeof(msg),
-                    xenstore_buf->rsp_prod - xenstore_buf->rsp_cons,
-                    msg.req_id);
+            memcpy_from_ring(xenstore_buf->rsp, &msg,
+                             MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
+                             sizeof(msg));
+            DEBUG("Msg len %d, %d avail, id %d.\n", msg.len + sizeof(msg),
+                  xenstore_buf->rsp_prod - xenstore_buf->rsp_cons, msg.req_id);
+
             if (xenstore_buf->rsp_prod - xenstore_buf->rsp_cons <
-                    sizeof(msg) + msg.len)
+                sizeof(msg) + msg.len)
                 break;
 
             DEBUG("Message is good.\n");
 
-            if(msg.type == XS_WATCH_EVENT)
-            {
-               struct xenbus_event *event = malloc(sizeof(*event) + msg.len);
+            if (msg.type == XS_WATCH_EVENT) {
+                struct xenbus_event *event = malloc(sizeof(*event) + msg.len);
                 xenbus_event_queue *events = NULL;
-               char *data = (char*)event + sizeof(*event);
+                char *data = (char*)event + sizeof(*event);
                 struct watch *watch;
 
-                memcpy_from_ring(xenstore_buf->rsp,
-                   data,
+                memcpy_from_ring(xenstore_buf->rsp, data,
                     MASK_XENSTORE_IDX(xenstore_buf->rsp_cons + sizeof(msg)),
                     msg.len);
 
-               event->path = data;
-               event->token = event->path + strlen(event->path) + 1;
+                event->path = data;
+                event->token = event->path + strlen(event->path) + 1;
 
                 mb();
                 xenstore_buf->rsp_cons += msg.len + sizeof(msg);
@@ -288,15 +285,11 @@ static void xenbus_thread_func(void *ign)
                     printk("unexpected watch token %s\n", event->token);
                     free(event);
                 }
-            }
-
-            else
-            {
+            } else {
                 req_info[msg.req_id].reply = malloc(sizeof(msg) + msg.len);
-                memcpy_from_ring(xenstore_buf->rsp,
-                    req_info[msg.req_id].reply,
-                    MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
-                    msg.len + sizeof(msg));
+                memcpy_from_ring(xenstore_buf->rsp, req_info[msg.req_id].reply,
+                                 MASK_XENSTORE_IDX(xenstore_buf->rsp_cons),
+                                 msg.len + sizeof(msg));
                 mb();
                 xenstore_buf->rsp_cons += msg.len + sizeof(msg);
                 wake_up(&req_info[msg.req_id].waitq);
@@ -380,6 +373,55 @@ void fini_xenbus(void)
 {
 }
 
+void suspend_xenbus(void)
+{
+    /* Check for live requests and wait until they finish */
+    while (1)
+    {
+        spin_lock(&req_lock);
+        if (nr_live_reqs == 0)
+            break;
+        spin_unlock(&req_lock);
+        wait_event(req_wq, (nr_live_reqs == 0));
+    }
+
+    mask_evtchn(xenbus_evtchn);
+    xenstore_buf = NULL;
+    spin_unlock(&req_lock);
+}
+
+void resume_xenbus(int canceled)
+{
+    char *msg;
+    struct watch *watch;
+    struct write_req req[2];
+    struct xsd_sockmsg *rep;
+
+#ifdef CONFIG_PARAVIRT
+    get_xenbus(&start_info);
+#else
+    get_xenbus(0);
+#endif
+    unmask_evtchn(xenbus_evtchn);
+
+    if (!canceled) {
+        for (watch = watches; watch; watch = watch->next) {
+            req[0].data = watch->path;
+            req[0].len = strlen(watch->path) + 1;
+            req[1].data = watch->token;
+            req[1].len = strlen(watch->token) + 1;
+
+            rep = xenbus_msg_reply(XS_WATCH, XBT_NIL, req, ARRAY_SIZE(req));
+            msg = errmsg(rep);
+            if (msg)
+                xprintk("error on XS_WATCH: %s\n", msg);
+            free(rep);
+        }
+    }
+
+    notify_remote_via_evtchn(xenbus_evtchn);
+}
+
 /* Send data to xenbus.  This can block.  All of the requests are seen
    by xenbus as if sent atomically.  The header is added
    automatically, using type %type, req_id %req_id, and trans_id
@@ -501,7 +543,7 @@ static char *errmsg(struct xsd_sockmsg *rep)
     res[rep->len] = 0;
     free(rep);
     return res;
-}      
+}
 
 /* Send a debug message to xenbus.  Can block. */
 static void xenbus_debug_msg(const char *msg)
@@ -601,6 +643,7 @@ char* xenbus_watch_path_token( xenbus_transaction_t xbt, const char *path, const
         events = &xenbus_events;
 
     watch->token = strdup(token);
+    watch->path = strdup(path);
     watch->events = events;
     watch->next = watches;
     watches = watch;
@@ -636,6 +679,7 @@ char* xenbus_unwatch_path_token( xenbus_transaction_t xbt, const char *path, con
     for (prev = &watches, watch = *prev; watch; prev = &watch->next, watch = *prev)
         if (!strcmp(watch->token, token)) {
             free(watch->token);
+            free(watch->path);
             *prev = watch->next;
             free(watch);
             break;