[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] Re: [PATCH] libxenlight: check for early failures of qemu-dm (v4) [and 1 more messages]



I wrote:
> commit 6704f959a0ea543f6bbf07e0a58e8b84cdef2236
> Author: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
> Date:   Wed Nov 18 15:24:17 2009 +0000

But apparently I was having a bad day yesterday.  I generated that
patch without first committing all of my changes :-(.

Here is the real version.


commit eb5d75cb1157ccdedf0c292e647b0a26790a164c
Author: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Date:   Wed Nov 18 15:24:17 2009 +0000

libxenlight: check for early failures of qemu-dm (v4)

This patch makes xl create check whether qemu-dm has started
correctly, and causes it to fail immediately with appropriate errors
if not.  There are other bugfixes too.

More specifically:

 * libxl_create_device_model forks twice rather than once so that the
   process which calls libxl does not end up being the actual parent
   of qemu.  That avoids the need for the qemu-dm process to be reaped
   at some indefinite time in the future.

 * The first fork generates an intermediate process which is
   responsible for writing the qemu-dm pid to xenstore and then merely
   waits to collect and report on qemu-dm's exit status during
   startup.  New arguments to libxl_create_device_model allow the
   preservation of its pid so that a later call can check whether the
   startup is successful.

 * The core of this functionality (the double fork, waitpid, signal
   handling and so forth) is abstracted away into a new facility
   libxl_spawn_... in libxl_exec.c.

Consequential changes:

 * libxl_wait_for_device_model now takes a callback function parameter
   which is called repeatedly in the loop iteration and allows the
   caller to abort the wait.

 * libxl_exec no longer calls fork; there is a new libxl_fork.

 * There is a hook to override waitpid, which will be necessary for
   some callers.

Remaining problems and other issues I noticed or we found:

 * The error handling is rather inconsistent still and lacking in
   places.
 * destroy_device_model can kill random dom0 processes (!)

Changes since v3 of this patch:
 * Fixed bug which prevented qemu-dm from being properly killed on domain
   shutdown.  (Failure to set dom_path in dm starting state.)
 * Slightly tidy some memory allocation and error handling in
   dm_xenstore_record_pid.

Signed-off-by: Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx>


diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 421628c..107a8ee 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -23,10 +23,12 @@
 #include <sys/types.h>
 #include <fcntl.h>
 #include <sys/select.h>
+#include <sys/wait.h>
 #include <signal.h>
 #include <unistd.h> /* for write, unlink and close */
 #include <stdint.h>
 #include <inttypes.h>
+#include <assert.h>
 
 #include "libxl.h"
 #include "libxl_utils.h"
@@ -43,6 +45,8 @@ int libxl_ctx_init(struct libxl_ctx *ctx)
 
     ctx->xch = xc_interface_open();
     ctx->xsh = xs_daemon_open();
+
+    ctx->waitpid_instead= libxl_waitpid_instead_default;
     return 0;
 }
 
@@ -520,25 +524,50 @@ static char ** libxl_build_device_model_args(struct 
libxl_ctx *ctx,
     return (char **) flexarray_contents(dm_args);
 }
 
+struct libxl_device_model_starting {
+    struct libxl_spawn_starting for_spawn; /* first! */
+    char *dom_path; /* from libxl_malloc, only for dm_xenstore_record_pid */
+    int domid;
+};
+
+void dm_xenstore_record_pid(struct libxl_ctx *ctx, void *for_spawn,
+                            pid_t innerchild) {
+    struct libxl_device_model_starting *starting = for_spawn;
+    struct libxl_ctx clone;
+    char *kvs[3];
+    int rc;
+    
+    clone = *ctx;
+    clone.xsh = xs_daemon_open();
+    /* we mustn't use the parent's handle in the child */
+
+    kvs[0] = "image/device-model-pid";
+    kvs[1] = libxl_sprintf(ctx, "%d", innerchild);
+    kvs[2] = NULL;
+    rc = libxl_xs_writev(ctx, XBT_NULL, starting->dom_path, kvs);
+    if (rc) XL_LOG_ERRNO(ctx, XL_LOG_ERROR,
+                         "Couldn't record device model pid %ld at %s/%s",
+                         (unsigned long)innerchild, starting->dom_path, kvs);
+}
+
 int libxl_create_device_model(struct libxl_ctx *ctx,
                               libxl_device_model_info *info,
-                              libxl_device_nic *vifs, int num_vifs)
+                              libxl_device_nic *vifs, int num_vifs,
+                              libxl_device_model_starting **starting_r)
 {
-    char *dom_path, *path, *logfile, *logfile_new;
-    char *kvs[3];
+    char *path, *logfile, *logfile_new;
     struct stat stat_buf;
-    int logfile_w, null, pid;
-    int i;
+    int logfile_w, null;
+    int i, rc;
     char **args;
+    struct libxl_spawn_starting buf_spawn, *for_spawn;
+
+    *starting_r= 0;
 
     args = libxl_build_device_model_args(ctx, info, vifs, num_vifs);
     if (!args)
         return ERROR_FAIL;
 
-    dom_path = libxl_xs_get_dompath(ctx, info->domid);
-    if (!dom_path)
-        return ERROR_FAIL;
-
     path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid);
     xs_mkdir(ctx->xsh, XBT_NULL, path);
 
@@ -559,18 +588,54 @@ int libxl_create_device_model(struct libxl_ctx *ctx,
     logfile = libxl_sprintf(ctx, "/var/log/xen/qemu-dm-%s.log", 
info->dom_name);
     logfile_w = open(logfile, O_WRONLY|O_CREAT, 0644);
     null = open("/dev/null", O_RDONLY);
-    pid = libxl_exec(ctx, null, logfile_w, logfile_w, info->device_model, 
args);
+
+    if (starting_r) {
+        *starting_r= libxl_calloc(ctx, sizeof(**starting_r), 1);
+        if (!*starting_r) return ERROR_NOMEM;
+        (*starting_r)->domid= info->domid;
+
+        (*starting_r)->dom_path = libxl_xs_get_dompath(ctx, info->domid);
+        if (!(*starting_r)->dom_path) { free(*starting_r); return ERROR_FAIL; }
+
+        for_spawn= &(*starting_r)->for_spawn;
+    } else {
+        for_spawn= &buf_spawn;
+    }
+    rc = libxl_spawn_spawn(ctx, for_spawn, "device model",
+                           dm_xenstore_record_pid);
+    if (rc < 0) goto xit;
+    if (!rc) { /* inner child */
+        libxl_exec(ctx, null, logfile_w, logfile_w,
+                   info->device_model, args);
+    }
+
+    rc = 0;
+ xit:
     close(null);
     close(logfile_w);
 
-    kvs[0] = libxl_sprintf(ctx, "image/device-model-pid");
-    kvs[1] = libxl_sprintf(ctx, "%d", pid);
-    kvs[2] = NULL;
-    libxl_xs_writev(ctx, XBT_NULL, dom_path, kvs);
+    return rc;
+}
 
-    return 0;
+int libxl_detach_device_model(struct libxl_ctx *ctx,
+                              libxl_device_model_starting *starting) {
+    int rc;
+    rc = libxl_spawn_detach(ctx, &starting->for_spawn);
+    libxl_free(ctx, starting);
+    return rc;
 }
 
+
+int libxl_confirm_device_model_startup(struct libxl_ctx *ctx,
+                                       libxl_device_model_starting *starting) {
+    int problem = libxl_wait_for_device_model(ctx, starting->domid, "running",
+                                              libxl_spawn_check,
+                                              &starting->for_spawn);
+    int detach = libxl_detach_device_model(ctx, starting);
+    return problem ? problem : detach;
+}
+
+
 
/******************************************************************************/
 int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_disk *disk)
 {
@@ -917,12 +982,13 @@ static int libxl_build_xenpv_qemu_args(struct libxl_ctx 
*ctx,
 }
 
 int libxl_create_xenpv_qemu(struct libxl_ctx *ctx, libxl_device_vfb *vfb,
-                            int num_console, libxl_device_console *console)
+                            int num_console, libxl_device_console *console,
+                            struct libxl_device_model_starting **starting_r)
 {
     libxl_device_model_info info;
 
     libxl_build_xenpv_qemu_args(ctx, vfb, num_console, console, &info);
-    libxl_create_device_model(ctx, &info, NULL, 0);
+    libxl_create_device_model(ctx, &info, NULL, 0, starting_r);
     return 0;
 }
 
@@ -1195,7 +1261,7 @@ int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t 
domid, libxl_device_pci
 
     hvm = is_hvm(ctx, domid);
     if (hvm) {
-        if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
+        if (libxl_wait_for_device_model(ctx, domid, "running", 0,0) < 0) {
             return -1;
         }
         snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", 
domid);
@@ -1209,7 +1275,7 @@ int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t 
domid, libxl_device_pci
                            pcidev->bus, pcidev->dev, pcidev->func);
         snprintf(path, sizeof(path), 
"/local/domain/0/device-model/%d/command", domid);
         xs_write(ctx->xsh, XBT_NULL, path, "pci-ins", strlen("pci-ins"));
-        if (libxl_wait_for_device_model(ctx, domid, "pci-inserted") < 0)
+        if (libxl_wait_for_device_model(ctx, domid, "pci-inserted", 0,0) < 0)
             XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time");
         snprintf(path, sizeof(path), 
"/local/domain/0/device-model/%d/parameter", domid);
         vdevfn = libxl_xs_read(ctx, XBT_NULL, path);
@@ -1283,7 +1349,7 @@ int libxl_device_pci_remove(struct libxl_ctx *ctx, 
uint32_t domid, libxl_device_
 
     hvm = is_hvm(ctx, domid);
     if (hvm) {
-        if (libxl_wait_for_device_model(ctx, domid, "running") < 0) {
+        if (libxl_wait_for_device_model(ctx, domid, "running", 0,0) < 0) {
             return -1;
         }
         snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", 
domid);
@@ -1293,7 +1359,7 @@ int libxl_device_pci_remove(struct libxl_ctx *ctx, 
uint32_t domid, libxl_device_
                        pcidev->bus, pcidev->dev, pcidev->func);
         snprintf(path, sizeof(path), 
"/local/domain/0/device-model/%d/command", domid);
         xs_write(ctx->xsh, XBT_NULL, path, "pci-rem", strlen("pci-rem"));
-        if (libxl_wait_for_device_model(ctx, domid, "pci-removed") < 0) {
+        if (libxl_wait_for_device_model(ctx, domid, "pci-removed", 0,0) < 0) {
             XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time");
             return -1;
         }
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index ac4c79e..29ffde2 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -41,6 +41,11 @@ struct libxl_ctx {
     /* mini-GC */
     int alloc_maxsize;
     void **alloc_ptrs;
+
+    /* for callers who reap children willy-nilly; caller must only
+     * set this after libxl_init and before any other call - or
+     * may leave them untouched */
+    int (*waitpid_instead)(pid_t pid, int *status, int flags);
 };
 
 typedef struct {
@@ -235,11 +240,22 @@ int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t 
domid);
 struct libxl_dominfo * libxl_domain_list(struct libxl_ctx *ctx, int 
*nb_domain);
 xc_dominfo_t * libxl_domain_infolist(struct libxl_ctx *ctx, int *nb_domain);
 
+typedef struct libxl_device_model_starting libxl_device_model_starting;
 int libxl_create_device_model(struct libxl_ctx *ctx,
                               libxl_device_model_info *info,
-                              libxl_device_nic *vifs, int num_vifs);
+                              libxl_device_nic *vifs, int num_vifs,
+                              libxl_device_model_starting **starting_r);
 int libxl_create_xenpv_qemu(struct libxl_ctx *ctx, libxl_device_vfb *vfb,
-                            int num_console, libxl_device_console *console);
+                            int num_console, libxl_device_console *console,
+                            libxl_device_model_starting **starting_r);
+  /* Caller must either: pass starting_r==0, or on successful
+   * return pass *starting_r (which will be non-0) to
+   * libxl_confirm_device_model or libxl_detach_device_model. */
+int libxl_confirm_device_model_startup(struct libxl_ctx *ctx,
+                              libxl_device_model_starting *starting);
+int libxl_detach_device_model(struct libxl_ctx *ctx,
+                              libxl_device_model_starting *starting);
+  /* DM is detached even if error is returned */
 
 int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, 
libxl_device_disk *disk);
 int libxl_device_disk_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid);
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 451233f..39932a6 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -287,12 +287,17 @@ int libxl_device_pci_flr(struct libxl_ctx *ctx, unsigned 
int domain, unsigned in
     return -1;
 }
 
-int libxl_wait_for_device_model(struct libxl_ctx *ctx, uint32_t domid, char 
*state)
+int libxl_wait_for_device_model(struct libxl_ctx *ctx,
+                                uint32_t domid, char *state,
+                                int (*check_callback)(struct libxl_ctx *ctx,
+                                                      void *userdata),
+                                void *check_callback_userdata)
 {
     char path[50];
     char *p;
     int watchdog = 100;
     unsigned int len;
+    int rc;
 
     snprintf(path, sizeof(path), "/local/domain/0/device-model/%d/state", 
domid);
     while (watchdog > 0) {
@@ -310,6 +315,10 @@ int libxl_wait_for_device_model(struct libxl_ctx *ctx, 
uint32_t domid, char *sta
                 watchdog--;
             }
         }
+        if (check_callback) {
+            rc = check_callback(ctx, check_callback_userdata);
+            if (rc) return rc;
+        }
     }
     XL_LOG(ctx, XL_LOG_ERROR, "Device Model not ready");
     return -1;
diff --git a/tools/libxl/libxl_exec.c b/tools/libxl/libxl_exec.c
index 5186ac8..6a3373e 100644
--- a/tools/libxl/libxl_exec.c
+++ b/tools/libxl/libxl_exec.c
@@ -18,34 +18,191 @@
 #include "libxl_osdeps.h"
 
 #include <stdio.h>
+#include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 
 #include "libxl.h"
 #include "libxl_internal.h"
 
-int libxl_exec(struct libxl_ctx *ctx, int stdinfd, int stdoutfd, int stderrfd,
-               char *arg0, char **args)
+pid_t libxl_fork(struct libxl_ctx *ctx)
 {
-    int pid, i;
+    pid_t pid;
 
     pid = fork();
     if (pid == -1) {
         XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "fork failed");
         return -1;
     }
-    if (pid == 0) {
-        /* child */
-        if (stdinfd != -1)
-            dup2(stdinfd, STDIN_FILENO);
-        if (stdoutfd != -1)
-            dup2(stdoutfd, STDOUT_FILENO);
-        if (stderrfd != -1)
-            dup2(stderrfd, STDERR_FILENO);
-        for (i = 4; i < 256; i++)
-            close(i);
-        execv(arg0, args);
-        exit(256);
-    }
+    
     return pid;
 }
+
+void libxl_exec(struct libxl_ctx *ctx, int stdinfd, int stdoutfd, int stderrfd,
+                char *arg0, char **args)
+     /* call this in the child */
+{
+    int i;
+
+    if (stdinfd != -1)
+        dup2(stdinfd, STDIN_FILENO);
+    if (stdoutfd != -1)
+        dup2(stdoutfd, STDOUT_FILENO);
+    if (stderrfd != -1)
+        dup2(stderrfd, STDERR_FILENO);
+    for (i = 4; i < 256; i++)
+        close(i);
+    execv(arg0, args);
+    XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "exec %s failed", arg0);
+    _exit(-1);
+}
+
+void libxl_report_child_exitstatus(struct libxl_ctx *ctx,
+                                   const char *what, pid_t pid, int status) {
+    /* treats all exit statuses as errors; if that's not what you want,
+     * check status yourself first */
+    
+    if (WIFEXITED(status)) {
+        int st= WEXITSTATUS(status);
+        if (st)
+            XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] exited"
+                   " with error status %d", what, (unsigned long)pid, st);
+        else
+            XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] unexpectedly"
+                   " exited status zero", what, (unsigned long)pid);
+    } else if (WIFSIGNALED(status)) {
+        int sig= WTERMSIG(status);
+        const char *str= strsignal(sig);
+        const char *coredump= WCOREDUMP(status) ? " (core dumped)" : "";
+        if (str)
+            XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] died due to"
+                   " fatal signal %s%s", what, (unsigned long)pid,
+                   str, coredump);
+        else 
+            XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] died due to unknown"
+                   " fatal signal number %d%s", what, (unsigned long)pid,
+                   sig, coredump);
+    } else {
+        XL_LOG(ctx, XL_LOG_ERROR, "%s [%ld] gave unknown"
+               " wait status 0x%x", what, (unsigned long)pid, status);
+    }
+}
+
+pid_t libxl_waitpid_instead_default(pid_t pid, int *status, int flags) {
+    return waitpid(pid,status,flags);
+}
+
+
+
+int libxl_spawn_spawn(struct libxl_ctx *ctx,
+                      struct libxl_spawn_starting *for_spawn,
+                      const char *what,
+                      void (*intermediate_hook)(struct libxl_ctx *ctx,
+                                                void *for_spawn,
+                                                pid_t innerchild)) {
+    pid_t child, got;
+    int status;
+    pid_t intermediate;
+
+    if (for_spawn) {
+        for_spawn->what= strdup(what);
+        if (!for_spawn->what) return ERROR_NOMEM;
+    }
+
+    intermediate = libxl_fork(ctx);
+    if (intermediate==-1) {
+        if (for_spawn) free(for_spawn->what);
+        return ERROR_FAIL;
+    }
+    if (intermediate) {
+        /* parent */
+        if (for_spawn) for_spawn->intermediate= intermediate;
+        return 1;
+    }
+    
+    /* we are now the intermediate process */
+
+    child = libxl_fork(ctx);
+    if (!child) return 0; /* caller runs child code */
+    if (child<0) exit(255);
+
+    intermediate_hook(ctx, for_spawn, child);
+
+    if (!for_spawn) _exit(0); /* just detach then */
+
+    got = ctx->waitpid_instead(child, &status, 0);
+    assert(got == child);
+
+    libxl_report_child_exitstatus(ctx, what, child, status);
+    _exit(WIFEXITED(status) ? WEXITSTATUS(status) :
+          WIFSIGNALED(status) && WTERMSIG(status)<127
+          ? WTERMSIG(status)+128 : -1);
+}
+
+static void report_spawn_intermediate_status(struct libxl_ctx *ctx,
+                                 struct libxl_spawn_starting *for_spawn,
+                                 int status) {
+    if (!WIFEXITED(status)) {
+        /* intermediate process did the logging itself if it exited */
+        char *intermediate_what=
+            libxl_sprintf(ctx,
+                          "%s intermediate process (startup monitor)",
+                          for_spawn->what);
+        libxl_report_child_exitstatus(ctx, intermediate_what,
+                                      for_spawn->intermediate, status);
+    }
+}
+
+int libxl_spawn_detach(struct libxl_ctx *ctx,
+                       struct libxl_spawn_starting *for_spawn) {
+    int r, status;
+    pid_t got;
+    int rc = 0;
+
+    if (!for_spawn) return 0;
+    
+    if (for_spawn->intermediate) {
+        r = kill(for_spawn->intermediate, SIGKILL);
+        if (r) {
+            XL_LOG_ERRNO(ctx, XL_LOG_ERROR,
+                         "could not kill %s intermediate process [%ld]",
+                         for_spawn->what,
+                         (unsigned long)for_spawn->intermediate);
+            abort(); /* things are very wrong */
+        }
+        got = ctx->waitpid_instead(for_spawn->intermediate, &status, 0);
+        assert(got == for_spawn->intermediate);
+        if (!(WIFSIGNALED(status) && WTERMSIG(status)==SIGKILL)) {
+            report_spawn_intermediate_status(ctx, for_spawn, status);
+            rc = ERROR_FAIL;
+        }
+        for_spawn->intermediate = 0;
+    }
+
+    free(for_spawn->what);
+    for_spawn->what = 0;
+    
+    return rc;
+}
+
+int libxl_spawn_check(struct libxl_ctx *ctx, void *for_spawn_void) {
+    struct libxl_spawn_starting *for_spawn = for_spawn_void;
+    pid_t got;
+    int status;
+
+    if (!for_spawn) return 0;
+    
+    assert(for_spawn->intermediate);
+    got = ctx->waitpid_instead(for_spawn->intermediate, &status, WNOHANG);
+    if (!got) return 0;
+
+    assert(got == for_spawn->intermediate);
+    report_spawn_intermediate_status(ctx, for_spawn, status);
+    
+    for_spawn->intermediate= 0;
+    return ERROR_FAIL;
+}
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 046e51d..957bd9e 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -135,7 +135,11 @@ int libxl_device_generic_add(struct libxl_ctx *ctx, 
libxl_device *device,
                              char **bents, char **fents);
 int libxl_device_destroy(struct libxl_ctx *ctx, char *be_path, int force);
 int libxl_devices_destroy(struct libxl_ctx *ctx, uint32_t domid, int force);
-int libxl_wait_for_device_model(struct libxl_ctx *ctx, uint32_t domid, char 
*state);
+int libxl_wait_for_device_model(struct libxl_ctx *ctx,
+                                uint32_t domid, char *state,
+                                int (*check_callback)(struct libxl_ctx *ctx,
+                                                      void *userdata),
+                                void *check_callback_userdata);
 int libxl_wait_for_backend(struct libxl_ctx *ctx, char *be_path, char *state);
 int libxl_device_pci_flr(struct libxl_ctx *ctx, unsigned int domain, unsigned 
int bus,
                          unsigned int dev, unsigned int func);
@@ -146,8 +150,47 @@ int hvm_build_set_params(int handle, uint32_t domid,
                          int vcpus, int store_evtchn, unsigned long 
*store_mfn);
 
 /* xl_exec */
-int libxl_exec(struct libxl_ctx *ctx, int stdinfd, int stdoutfd, int stderrfd,
-               char *arg0, char **args);
+
+ /* higher-level double-fork and separate detach eg as for device models */
+
+struct libxl_spawn_starting {
+    /* put this in your own stateu structure as returned to application */
+    /* all fields are private to libxl_spawn_... */
+    pid_t intermediate;
+    char *what; /* malloc'd in spawn_spawn */
+};
+
+int libxl_spawn_spawn(struct libxl_ctx *ctx,
+                      struct libxl_spawn_starting *for_spawn,
+                      const char *what,
+                      void (*intermediate_hook)(struct libxl_ctx *ctx,
+                                                void *for_spawn,
+                                                pid_t innerchild));
+  /* Logs errors.  A copy of "what" is taken.  Return values:
+   *  < 0   error, for_spawn need not be detached
+   *   +1   caller is now the inner child, should probably call libxl_exec
+   *    0   caller is the parent, must call detach on *for_spawn eventually
+   * Caller, may pass 0 for for_spawn, in which case no need to detach.
+   */
+int libxl_spawn_detach(struct libxl_ctx *ctx,
+                       struct libxl_spawn_starting *for_spawn);
+  /* Logs errors.  Idempotent, but only permitted after successful
+   * call to libxl_spawn_spawn, and no point calling it again if it fails. */
+int libxl_spawn_check(struct libxl_ctx *ctx,
+                      void *for_spawn);
+  /* Logs errors but also returns them.
+   * for_spawn must actually be a  struct libxl_spawn_starting*  but
+   * we take void* so you can pass this function directly to
+   * libxl_wait_for_device_model.  Caller must still call detach. */
+
+ /* low-level stuff, for synchronous subprocesses etc. */
+
+pid_t libxl_fork(struct libxl_ctx *ctx); // logs errors
+void libxl_exec(struct libxl_ctx *ctx, int stdinfd, int stdoutfd, int stderrfd,
+                char *arg0, char **args); // logs errors, never returns
+void libxl_log_child_exitstatus(struct libxl_ctx *ctx,
+                                const char *what, pid_t pid, int status);
+pid_t libxl_waitpid_instead_default(pid_t pid, int *status, int flags);
 
 #endif
 
diff --git a/tools/libxl/osdeps.c b/tools/libxl/osdeps.c
index ad96480..b146a9d 100644
--- a/tools/libxl/osdeps.c
+++ b/tools/libxl/osdeps.c
@@ -13,6 +13,8 @@
  * GNU Lesser General Public License for more details.
  */
 
+#include "libxl_osdeps.h"
+
 #include <unistd.h>
 #include <stdarg.h>
 #include <stdio.h>
diff --git a/tools/libxl/xl.c b/tools/libxl/xl.c
index 727fe4a..6d43f8b 100644
--- a/tools/libxl/xl.c
+++ b/tools/libxl/xl.c
@@ -699,6 +699,15 @@ skip_pci:
     config_destroy(&config);
 }
 
+#define MUST( call ) ({                                                 \
+        int must_rc = (call);                                           \
+        if (must_rc) {                                                  \
+            fprintf(stderr,"xl: fatal error: %s:%d, rc=%d: %s\n",       \
+                    __FILE__,__LINE__, must_rc, #call);                 \
+            exit(-must_rc);                                             \
+        }                                                               \
+    })
+
 static void create_domain(int debug, const char *filename)
 {
     struct libxl_ctx ctx;
@@ -715,6 +724,7 @@ static void create_domain(int debug, const char *filename)
     libxl_device_console console;
     int num_disks = 0, num_vifs = 0, num_pcidevs = 0, num_vfbs = 0, num_vkbs = 
0;
     int i;
+    libxl_device_model_starting *dm_starting = 0;
 
     printf("Parsing config file %s\n", filename);
     parse_config_file(filename, &info1, &info2, &disks, &num_disks, &vifs, 
&num_vifs, &pcidevs, &num_pcidevs, &vfbs, &num_vfbs, &vkbs, &num_vkbs, 
&dm_info);
@@ -736,7 +746,8 @@ static void create_domain(int debug, const char *filename)
     }
     if (info1.hvm) {
         device_model_info_domid_fixup(&dm_info, domid);
-        libxl_create_device_model(&ctx, &dm_info, vifs, num_vifs);
+        MUST( libxl_create_device_model(&ctx, &dm_info, vifs, num_vifs,
+                                        &dm_starting) );
     } else {
         for (i = 0; i < num_vfbs; i++) {
             vfb_info_domid_fixup(vfbs + i, domid);
@@ -750,10 +761,14 @@ static void create_domain(int debug, const char *filename)
             console.constype = CONSTYPE_IOEMU;
         libxl_device_console_add(&ctx, domid, &console);
         if (num_vfbs)
-            libxl_create_xenpv_qemu(&ctx, vfbs, 1, &console);
+            libxl_create_xenpv_qemu(&ctx, vfbs, 1, &console, &dm_starting);
     }
+
     for (i = 0; i < num_pcidevs; i++)
         libxl_device_pci_add(&ctx, domid, &pcidevs[i]);
+    if (dm_starting)
+        MUST( libxl_confirm_device_model_startup(&ctx, dm_starting) );
+    
     libxl_domain_unpause(&ctx, domid);
 
 }

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.