[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 3/3] libxenlight: check for early failures of qemu-dm (v3)
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 v2 of this patch: * Various other changes split out into earlier patches in this series * xl.c's create_domain checking for errors in its libxl calls deferred for a future patch to avoid rebase churn. * New libxl_spawn_... abstraction. Signed-off-by: Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx> --- tools/libxl/libxl.c | 94 +++++++++++++++++---- tools/libxl/libxl.h | 20 ++++- tools/libxl/libxl_device.c | 11 ++- tools/libxl/libxl_exec.c | 189 ++++++++++++++++++++++++++++++++++++++---- tools/libxl/libxl_internal.h | 49 ++++++++++- tools/libxl/osdeps.c | 2 + tools/libxl/xl.c | 19 ++++- 7 files changed, 344 insertions(+), 40 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 421628c..29143cf 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,16 +524,41 @@ 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; + 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]; + + clone = *ctx; + clone.xsh = xs_daemon_open(); + /* we mustn't use the parent's handle in the child */ + + kvs[0] = libxl_sprintf(ctx, "image/device-model-pid"); + kvs[1] = libxl_sprintf(ctx, "%d", innerchild); + kvs[2] = NULL; + libxl_xs_writev(ctx, XBT_NULL, 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]; 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) @@ -559,18 +588,50 @@ 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; + 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 +978,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 +1257,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 +1271,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 +1345,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 +1355,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); } -- 1.5.6.5 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |