Ian Campbell
2010-Jul-12 14:01 UTC
[Xen-devel] [PATCH 0 of 9] libxl/xl: support for domain 0 bootloader (e.g. pygrub)
This series adds support to libxl/xl for running a domain 0 bootloader (such as pygrub). _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2010-Jul-12 14:01 UTC
[Xen-devel] [PATCH 1 of 9] pygrub: introduce easier to parse output format
libxl would rather like to parse the output of pygrub. Rather than implement an SXP parser in libxl add a --output-format option to pygrub which can select an alternative, simpler to parse, format. Available formats are: sxp: current SXP output format; simple: simple key+value output with \n separating item ( for debugging). key and value are separated by a single space (and key therefore cannot contain a space); simple0: as simple but with \0 as a separator; Also add --output-directory to allow temporary files to be placed somewhere other than /var/run/xend/boot. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> diff -r 4f194a196734 -r 988cf8dff1c0 tools/pygrub/src/pygrub --- a/tools/pygrub/src/pygrub Mon Jul 12 11:40:17 2010 +0100 +++ b/tools/pygrub/src/pygrub Mon Jul 12 14:56:37 2010 +0100 @@ -630,16 +630,34 @@ return cfg +def format_sxp(kernel, ramdisk, args): + s = "linux (kernel %s)" % kernel + if ramdisk: + s += "(ramdisk %s)" % ramdisk + if args: + s += "(args \"%s\")" % args + return s + +def format_simple(kernel, ramdisk, args, sep): + s = ("kernel %s" % kernel) + sep + if ramdisk: + s += ("ramdisk %s" % ramdisk) + sep + if args: + s += ("args %s" % args) + sep + s += sep + return s + if __name__ == "__main__": sel = None def usage(): - print >> sys.stderr, "Usage: %s [-q|--quiet] [-i|--interactive] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] <image>" %(sys.argv[0],) + print >> sys.stderr, "Usage: %s [-q|--quiet] [-i|--interactive] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] <image>" %(sys.argv[0],) try: opts, args = getopt.gnu_getopt(sys.argv[1:], ''qinh::'', - ["quiet", "interactive", "not-really", - "help", "output=", "entry=", "kernel=", + ["quiet", "interactive", "not-really", "help", + "output=", "output-format=", "output-directory=", + "entry=", "kernel=", "ramdisk=", "args=", "isconfig"]) except getopt.GetoptError: usage() @@ -655,6 +673,8 @@ interactive = True isconfig = False not_really = False + output_format = "sxp" + output_directory = "/var/run/xend/boot" # what was passed in incfg = { "kernel": None, "ramdisk": None, "args": "" } @@ -687,6 +707,14 @@ interactive = False elif o in ("--isconfig",): isconfig = True + elif o in ("--output-format",): + if a not in ["sxp", "simple", "simple0"]: + print "unkonwn output format %s" % a + usage() + sys.exit(1) + output_format = a + elif o in ("--output-directory",): + output_directory = a if output is None or output == "-": fd = sys.stdout.fileno() @@ -723,7 +751,7 @@ else: data = fs.open_file(chosencfg["kernel"]).read() (tfd, bootcfg["kernel"]) = tempfile.mkstemp(prefix="boot_kernel.", - dir="/var/run/xend/boot") + dir=output_directory) os.write(tfd, data) os.close(tfd) @@ -733,26 +761,29 @@ else: data = fs.open_file(chosencfg["ramdisk"],).read() (tfd, bootcfg["ramdisk"]) = tempfile.mkstemp( - prefix="boot_ramdisk.", dir="/var/run/xend/boot") + prefix="boot_ramdisk.", dir=output_directory) os.write(tfd, data) os.close(tfd) else: initrd = None - sxp = "linux (kernel %s)" % bootcfg["kernel"] - if bootcfg["ramdisk"]: - sxp += "(ramdisk %s)" % bootcfg["ramdisk"] + args = None if chosencfg["args"]: zfsinfo = fsimage.getbootstring(fs) - if zfsinfo is None: - sxp += "(args \"%s\")" % chosencfg["args"] - else: + if zfsinfo is not None: e = re.compile("zfs-bootfs=[\w\-\.\:@/]+" ) (chosencfg["args"],count) = e.subn(zfsinfo, chosencfg["args"]) if count == 0: chosencfg["args"] += " -B %s" % zfsinfo - sxp += "(args \"%s\")" % (chosencfg["args"]) + args = chosencfg["args"] + + if output_format == "sxp": + ostring = format_sxp(bootcfg["kernel"], bootcfg["ramdisk"], args) + elif output_format == "simple": + ostring = format_simple(bootcfg["kernel"], bootcfg["ramdisk"], args, "\n") + elif output_format == "simple0": + ostring = format_simple(bootcfg["kernel"], bootcfg["ramdisk"], args, "\0") sys.stdout.flush() - os.write(fd, sxp) + os.write(fd, ostring) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2010-Jul-12 14:01 UTC
[Xen-devel] [PATCH 2 of 9] xenconsole: do not exit if a pty device is missing
this can just mean we have raced with the bootloader exiting and if we continue we will likely see the real domain console show up. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> diff -r 988cf8dff1c0 -r 24a1b866b2d1 tools/console/client/main.c --- a/tools/console/client/main.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/console/client/main.c Mon Jul 12 14:56:37 2010 +0100 @@ -115,6 +115,8 @@ * disambiguate: just read the pty path */ pty_path = xs_read(xs, XBT_NULL, path, &len); if (pty_path != NULL) { + if (access(pty_path, R_OK|W_OK) != 0) + continue; pty_fd = open(pty_path, O_RDWR | O_NOCTTY); if (pty_fd == -1) err(errno, "Could not open tty `%s''", _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2010-Jul-12 14:01 UTC
[Xen-devel] [PATCH 3 of 9] libxl: add printf attribute to libxl_xs_write and fixup resulting warnings
There is an unfortunate warning for the empty format string by default which I workaround by adding -Wno-format-zero-length. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> diff -r 24a1b866b2d1 -r 8545cbf7f513 tools/libxl/Makefile --- a/tools/libxl/Makefile Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/Makefile Mon Jul 12 14:56:37 2010 +0100 @@ -11,7 +11,7 @@ XLUMAJOR = 1.0 XLUMINOR = 0 -CFLAGS += -Werror +CFLAGS += -Werror -Wno-format-zero-length CFLAGS += -I. -fPIC CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl) diff -r 24a1b866b2d1 -r 8545cbf7f513 tools/libxl/libxl.c --- a/tools/libxl/libxl.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl.c Mon Jul 12 14:56:37 2010 +0100 @@ -523,7 +523,7 @@ path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid); state = libxl_xs_read(ctx, XBT_NULL, path); if (state != NULL && !strcmp(state, "paused")) { - libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid), "continue", strlen("continue")); + libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid), "continue"); libxl_wait_for_device_model(ctx, domid, "running", NULL, NULL); } } @@ -2663,7 +2663,7 @@ } if (domid != 0) - libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/memory/static-max", dompath), "%lu", max_memkb); + libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/memory/static-max", dompath), "%"PRIu32, max_memkb); return 0; } @@ -2702,14 +2702,14 @@ videoram_s = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/memory/videoram", dompath)); videoram = videoram_s ? atoi(videoram_s) : 0; - libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/memory/target", dompath), "%lu", target_memkb); + libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/memory/target", dompath), "%"PRIu32, target_memkb); rc = xc_domain_getinfolist(ctx->xch, domid, 1, &info); if (rc != 1 || info.domain != domid) return rc; xcinfo2xlinfo(&info, &ptr); uuid = libxl_uuid2string(ctx, ptr.uuid); - libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "/vm/%s/memory", uuid), "%lu", target_memkb / 1024); + libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "/vm/%s/memory", uuid), "%"PRIu32, target_memkb / 1024); if (enforce || !domid) memorykb = target_memkb; diff -r 24a1b866b2d1 -r 8545cbf7f513 tools/libxl/libxl_dom.c --- a/tools/libxl/libxl_dom.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl_dom.c Mon Jul 12 14:56:37 2010 +0100 @@ -247,7 +247,7 @@ return 1; } path = libxl_sprintf(si->ctx, "%s/control/shutdown", libxl_xs_get_dompath(si->ctx, si->domid)); - libxl_xs_write(si->ctx, XBT_NULL, path, "suspend", strlen("suspend")); + libxl_xs_write(si->ctx, XBT_NULL, path, "suspend"); if (si->hvm) { unsigned long hvm_pvdrv, hvm_s_state; xc_get_hvm_param(si->ctx->xch, si->domid, HVM_PARAM_CALLBACK_IRQ, &hvm_pvdrv); @@ -275,7 +275,7 @@ } if (!strcmp(state, "suspend")) { XL_LOG(si->ctx, XL_LOG_ERROR, "guest didn''t suspend in time"); - libxl_xs_write(si->ctx, XBT_NULL, path, "", 1); + libxl_xs_write(si->ctx, XBT_NULL, path, ""); } return 1; } @@ -338,7 +338,7 @@ char *filename = libxl_sprintf(ctx, "/var/lib/xen/qemu-save.%d", domid); XL_LOG(ctx, XL_LOG_DEBUG, "Saving device model state to %s", filename); - libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid), "save", strlen("save")); + libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid), "save"); libxl_wait_for_device_model(ctx, domid, "paused", NULL, NULL); c = libxl_write_exactly(ctx, fd, QEMU_SIGNATURE, strlen(QEMU_SIGNATURE), diff -r 24a1b866b2d1 -r 8545cbf7f513 tools/libxl/libxl_internal.h --- a/tools/libxl/libxl_internal.h Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl_internal.h Mon Jul 12 14:56:37 2010 +0100 @@ -117,7 +117,7 @@ int libxl_xs_writev(struct libxl_ctx *ctx, xs_transaction_t t, char *dir, char **kvs); int libxl_xs_write(struct libxl_ctx *ctx, xs_transaction_t t, - char *path, char *fmt, ...); + char *path, char *fmt, ...) PRINTF_ATTRIBUTE(4, 5); char *libxl_xs_get_dompath(struct libxl_ctx *ctx, uint32_t domid); // logs errs char *libxl_xs_read(struct libxl_ctx *ctx, xs_transaction_t t, char *path); char **libxl_xs_directory(struct libxl_ctx *ctx, xs_transaction_t t, char *path, unsigned int *nb); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2010-Jul-12 14:01 UTC
[Xen-devel] [PATCH 4 of 9] libxl: add libxl_strdup convenience function
Use in preference to libxl_sprintf(..., "%s", "...") Signed-off-by: Ian Campbell <ian.campbell@citrix.com> diff -r 8545cbf7f513 -r 6c6961e09c50 tools/libxl/libxl.c --- a/tools/libxl/libxl.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl.c Mon Jul 12 14:56:37 2010 +0100 @@ -1339,7 +1339,7 @@ flexarray_set(back, boffset++, "tapdisk-params"); flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s:%s", device_disk_string_of_phystype(disk->phystype), disk->physpath)); flexarray_set(back, boffset++, "params"); - flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", dev)); + flexarray_set(back, boffset++, libxl_strdup(ctx, dev)); backend_type = "phy"; device_physdisk_major_minor(dev, &major, &minor); flexarray_set(back, boffset++, "physical-device"); @@ -1467,7 +1467,7 @@ nic->mac[0], nic->mac[1], nic->mac[2], nic->mac[3], nic->mac[4], nic->mac[5])); flexarray_set(back, boffset++, "bridge"); - flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", nic->bridge)); + flexarray_set(back, boffset++, libxl_strdup(ctx, nic->bridge)); flexarray_set(back, boffset++, "handle"); flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->devid)); @@ -2020,13 +2020,13 @@ info->vnc = vfb->vnc; if (vfb->vnclisten) - info->vnclisten = libxl_sprintf(ctx, "%s", vfb->vnclisten); + info->vnclisten = libxl_strdup(ctx, vfb->vnclisten); info->vncdisplay = vfb->vncdisplay; info->vncunused = vfb->vncunused; if (vfb->vncpasswd) info->vncpasswd = vfb->vncpasswd; if (vfb->keymap) - info->keymap = libxl_sprintf(ctx, "%s", vfb->keymap); + info->keymap = libxl_strdup(ctx, vfb->keymap); info->sdl = vfb->sdl; info->opengl = vfb->opengl; for (i = 0; i < num_console; i++) { @@ -2782,19 +2782,19 @@ info->xen_version_major = xen_version >> 16; info->xen_version_minor = xen_version & 0xFF; xc_version(ctx->xch, XENVER_extraversion, &u.xen_extra); - info->xen_version_extra = libxl_sprintf(ctx, "%s", u.xen_extra); + info->xen_version_extra = libxl_strdup(ctx, u.xen_extra); xc_version(ctx->xch, XENVER_compile_info, &u.xen_cc); - info->compiler = libxl_sprintf(ctx, "%s", u.xen_cc.compiler); - info->compile_by = libxl_sprintf(ctx, "%s", u.xen_cc.compile_by); - info->compile_domain = libxl_sprintf(ctx, "%s", u.xen_cc.compile_domain); - info->compile_date = libxl_sprintf(ctx, "%s", u.xen_cc.compile_date); + info->compiler = libxl_strdup(ctx, u.xen_cc.compiler); + info->compile_by = libxl_strdup(ctx, u.xen_cc.compile_by); + info->compile_domain = libxl_strdup(ctx, u.xen_cc.compile_domain); + info->compile_date = libxl_strdup(ctx, u.xen_cc.compile_date); xc_version(ctx->xch, XENVER_capabilities, &u.xen_caps); - info->capabilities = libxl_sprintf(ctx, "%s", u.xen_caps); + info->capabilities = libxl_strdup(ctx, u.xen_caps); xc_version(ctx->xch, XENVER_changeset, &u.xen_chgset); - info->changeset = libxl_sprintf(ctx, "%s", u.xen_chgset); + info->changeset = libxl_strdup(ctx, u.xen_chgset); xc_version(ctx->xch, XENVER_platform_parameters, &u.p_parms); info->virt_start = u.p_parms.virt_start; @@ -2802,7 +2802,7 @@ info->pagesize = xc_version(ctx->xch, XENVER_pagesize, NULL); xc_version(ctx->xch, XENVER_commandline, &u.xen_commandline); - info->commandline = libxl_sprintf(ctx, "%s", u.xen_commandline); + info->commandline = libxl_strdup(ctx, u.xen_commandline); return info; } diff -r 8545cbf7f513 -r 6c6961e09c50 tools/libxl/libxl_exec.c --- a/tools/libxl/libxl_exec.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl_exec.c Mon Jul 12 14:56:37 2010 +0100 @@ -100,7 +100,7 @@ struct libxl_spawn_starting *for_spawn = starting->for_spawn; if (for_spawn) { - for_spawn->what = libxl_sprintf(ctx, "%s", what); + for_spawn->what = libxl_strdup(ctx, what); if (!for_spawn->what) return ERROR_NOMEM; } diff -r 8545cbf7f513 -r 6c6961e09c50 tools/libxl/libxl_internal.c --- a/tools/libxl/libxl_internal.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl_internal.c Mon Jul 12 14:56:37 2010 +0100 @@ -138,10 +138,20 @@ return s; } +char *libxl_strdup(struct libxl_ctx *ctx, const char *c) +{ + char *s = strdup(c); + + if (s) + libxl_ptr_add(ctx, s); + + return s; +} + char *libxl_dirname(struct libxl_ctx *ctx, const char *s) { char *c; - char *ptr = libxl_sprintf(ctx, "%s", s); + char *ptr = libxl_strdup(ctx, s); c = strrchr(ptr, ''/''); if (!c) diff -r 8545cbf7f513 -r 6c6961e09c50 tools/libxl/libxl_internal.h --- a/tools/libxl/libxl_internal.h Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl_internal.h Mon Jul 12 14:56:37 2010 +0100 @@ -111,6 +111,7 @@ void *libxl_zalloc(struct libxl_ctx *ctx, int bytes); void *libxl_calloc(struct libxl_ctx *ctx, size_t nmemb, size_t size); char *libxl_sprintf(struct libxl_ctx *ctx, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3); +char *libxl_strdup(struct libxl_ctx *ctx, const char *c); char *libxl_dirname(struct libxl_ctx *ctx, const char *s); char **libxl_xs_kvs_of_flexarray(struct libxl_ctx *ctx, flexarray_t *array, int length); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Signed-off-by: Ian Campbell <ian.campbell@citrix.com> diff -r 6c6961e09c50 -r 4b41b5e7532c tools/libxl/libxl_internal.h --- a/tools/libxl/libxl_internal.h Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl_internal.h Mon Jul 12 14:56:37 2010 +0100 @@ -176,7 +176,7 @@ /* 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 */ + /* put this in your own status structure as returned to application */ /* all fields are private to libxl_spawn_... */ pid_t intermediate; char *what; /* malloc''d in spawn_spawn */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2010-Jul-12 14:01 UTC
[Xen-devel] [PATCH 6 of 9] libxl/xl: exec xenconsole in current process, defer decision to fork to caller
Use this to run xenconsole as the foreground process and move the connection to the console in the "create -c" case early enough to be able to view output from the bootloader. This behaviour is consistent with how both "xm console" and "xm create -c" operate. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> diff -r 4b41b5e7532c -r bcea013ddd5a tools/libxl/libxl.c --- a/tools/libxl/libxl.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl.c Mon Jul 12 14:56:37 2010 +0100 @@ -786,12 +786,12 @@ return 0; } -int libxl_console_attach(struct libxl_ctx *ctx, uint32_t domid, int cons_num) +int libxl_console_exec(struct libxl_ctx *ctx, uint32_t domid, int cons_num) { - char *cmd = libxl_sprintf( - ctx, "%s/xenconsole %d --num %d", - libxl_private_bindir_path(), domid, cons_num); - return (system(cmd) != 0) ? ERROR_FAIL : 0; + char *p = libxl_sprintf(ctx, "%s/xenconsole", libxl_private_bindir_path()); + char *domid_s = libxl_sprintf(ctx, "%d", domid); + char *cons_num_s = libxl_sprintf(ctx, "%d", cons_num); + return execl(p, p, domid_s, "--num", cons_num_s, (void *)NULL) == 0 ? 0 : ERROR_FAIL; } static char ** libxl_build_device_model_args(struct libxl_ctx *ctx, diff -r 4b41b5e7532c -r bcea013ddd5a tools/libxl/libxl.h --- a/tools/libxl/libxl.h Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl.h Mon Jul 12 14:56:37 2010 +0100 @@ -358,7 +358,7 @@ int libxl_domain_setmaxmem(struct libxl_ctx *ctx, uint32_t domid, uint32_t target_memkb); int libxl_set_memory_target(struct libxl_ctx *ctx, uint32_t domid, uint32_t target_memkb, int enforce); -int libxl_console_attach(struct libxl_ctx *ctx, uint32_t domid, int cons_num); +int libxl_console_exec(struct libxl_ctx *ctx, uint32_t domid, int cons_num); int libxl_domain_info(struct libxl_ctx*, struct libxl_dominfo *info_r, uint32_t domid); diff -r 4b41b5e7532c -r bcea013ddd5a tools/libxl/xl_cmdimpl.c --- a/tools/libxl/xl_cmdimpl.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/xl_cmdimpl.c Mon Jul 12 14:56:37 2010 +0100 @@ -931,12 +931,45 @@ return r; } +int autoconnect_console(int cons_num) +{ + int status; + pid_t pid, r; + + /* + * Fork for xenconsole. We exec xenconsole in the foreground + * process allowing it to retain the tty. xl continues in the + * child. The xenconsole client uses a xenstore watch to wait for + * the console to be setup so there is no race. + */ + pid = fork(); + if (pid < 0) { + perror("unable to fork xenconsole"); + return ERROR_FAIL; + } else if (pid == 0) + return 0; + + /* + * Catch failure of the create process. + */ + sleep(1); + r = waitpid(pid, &status, WNOHANG); + if (r > 0 && WIFEXITED(status) && WEXITSTATUS(status) != 0) + _exit(WEXITSTATUS(status)); + + libxl_console_exec(&ctx, domid, cons_num); + /* Do not return. xl continued in child process */ + fprintf(stderr, "Unable to attach console\n"); + _exit(1); +} + struct domain_create { int debug; int daemonize; int paused; int dryrun; int quiet; + int console_autoconnect; const char *config_file; const char *extra_config; /* extra config string */ const char *restore_file; @@ -1118,6 +1151,12 @@ perror("cannot save config file"); ret = ERROR_FAIL; goto error_out; + } + + if (dom_info->console_autoconnect) { + ret = autoconnect_console(0); + if (ret) + goto error_out; } if (!restore_file || !need_daemon) { @@ -1467,12 +1506,6 @@ exit(0); } -void console(char *p, int cons_num) -{ - find_domain(p); - libxl_console_attach(&ctx, domid, cons_num); -} - void cd_insert(char *dom, char *virtdev, char *phys) { libxl_device_disk disk; @@ -1570,7 +1603,6 @@ int main_console(int argc, char **argv) { int opt = 0, cons_num = 0; - char *p = NULL; while ((opt = getopt(argc, argv, "hn:")) != -1) { switch (opt) { @@ -1592,10 +1624,10 @@ exit(2); } - p = argv[optind]; - - console(p, cons_num); - exit(0); + find_domain(argv[optind]); + libxl_console_exec(&ctx, domid, 0); + fprintf(stderr, "Unable to attach console\n"); + return 1; } void pcilist(char *dom) @@ -2672,7 +2704,6 @@ char *filename = NULL; char *p, extra_config[1024]; struct domain_create dom_info; - char dom[10]; /* long enough */ int paused = 0, debug = 0, daemonize = 1, console_autoconnect = 0, dryrun = 0, quite = 0; int opt, rc; @@ -2747,15 +2778,11 @@ dom_info.config_file = filename; dom_info.extra_config = extra_config; dom_info.migrate_fd = -1; + dom_info.console_autoconnect = console_autoconnect; rc = create_domain(&dom_info); if (rc < 0) exit(-rc); - - if (console_autoconnect) { - snprintf(dom, sizeof(dom), "%d", rc); - console(dom, 0); - } exit(0); } _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2010-Jul-12 14:01 UTC
[Xen-devel] [PATCH 7 of 9] libxl: support mapping files rather than carrying paths around
This will allow us to map and then unlink the file and therefore delete the process on process exit or explicit unmap. Using the mmaped versions of these files required rewriting build_pv to use the xc_dom builder functionality directly rather than through the xc_linux_build "compatibility layer". (The status of the xc_linux_build interface as a compatibility layer seems a bit dubious since all existing callers use it but if anything is going to replace it then libxl seems like the likely candidate). I''m not thrilled with the definition of the maps lifecycle. This could be solved by adding a helper function to explicitly free the toplevel structure. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> diff -r bcea013ddd5a -r 2d4475143f70 tools/libxl/libxl.c --- a/tools/libxl/libxl.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl.c Mon Jul 12 14:56:37 2010 +0100 @@ -22,6 +22,7 @@ #include <sys/types.h> #include <fcntl.h> #include <sys/select.h> +#include <sys/mman.h> #include <sys/wait.h> #include <signal.h> #include <unistd.h> /* for write, unlink and close */ @@ -291,12 +292,12 @@ vments[i++] = "image/ostype"; vments[i++] = "linux"; vments[i++] = "image/kernel"; - vments[i++] = (char*) info->kernel; + vments[i++] = (char*) info->kernel.path; vments[i++] = "start_time"; vments[i++] = libxl_sprintf(ctx, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000); - if (info->u.pv.ramdisk) { + if (info->u.pv.ramdisk.path) { vments[i++] = "image/ramdisk"; - vments[i++] = (char*) info->u.pv.ramdisk; + vments[i++] = (char*) info->u.pv.ramdisk.path; } if (info->u.pv.cmdline) { vments[i++] = "image/cmdline"; @@ -305,6 +306,10 @@ } ret = build_post(ctx, domid, info, state, vments, localents); out: + libxl_file_reference_unmap(ctx, &info->kernel); + if (!info->hvm) + libxl_file_reference_unmap(ctx, &info->u.pv.ramdisk); + return ret; } @@ -338,12 +343,12 @@ vments[i++] = "image/ostype"; vments[i++] = "linux"; vments[i++] = "image/kernel"; - vments[i++] = (char*) info->kernel; + vments[i++] = (char*) info->kernel.path; vments[i++] = "start_time"; vments[i++] = libxl_sprintf(ctx, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000); - if (info->u.pv.ramdisk) { + if (info->u.pv.ramdisk.path) { vments[i++] = "image/ramdisk"; - vments[i++] = (char*) info->u.pv.ramdisk; + vments[i++] = (char*) info->u.pv.ramdisk.path; } if (info->u.pv.cmdline) { vments[i++] = "image/cmdline"; @@ -361,6 +366,10 @@ } out: + libxl_file_reference_unmap(ctx, &info->kernel); + if (!info->hvm) + libxl_file_reference_unmap(ctx, &info->u.pv.ramdisk); + esave = errno; flags = fcntl(fd, F_GETFL); @@ -1057,9 +1066,9 @@ b_info.max_vcpus = 1; b_info.max_memkb = 32 * 1024; b_info.target_memkb = b_info.max_memkb; - b_info.kernel = libxl_abs_path(ctx, "ioemu-stubdom.gz", libxl_xenfirmwaredir_path()); + b_info.kernel.path = libxl_abs_path(ctx, "ioemu-stubdom.gz", libxl_xenfirmwaredir_path()); b_info.u.pv.cmdline = libxl_sprintf(ctx, " -d %d", info->domid); - b_info.u.pv.ramdisk = ""; + b_info.u.pv.ramdisk.path = ""; b_info.u.pv.features = ""; b_info.hvm = 0; @@ -3181,3 +3190,47 @@ return rc; } +int libxl_file_reference_map(struct libxl_ctx *ctx, libxl_file_reference *f) +{ + struct stat st_buf; + int ret, fd; + void *data; + + if (f->mapped) + return 0; + + fd = open(f->path, O_RDONLY); + if (f < 0) + return ERROR_FAIL; + + ret = fstat(fd, &st_buf); + if (ret < 0) + goto out; + + ret = -1; + data = mmap(NULL, st_buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data == NULL) + goto out; + + f->mapped = 1; + f->data = data; + f->size = st_buf.st_size; + + ret = 0; +out: + close(fd); + + return ret == 0 ? 0 : ERROR_FAIL; +} + +int libxl_file_reference_unmap(struct libxl_ctx *ctx, libxl_file_reference *f) +{ + int ret; + + if (!f->mapped) + return 0; + + ret = munmap(f->data, f->size); + + return ret == 0 ? 0 : ERROR_FAIL; +} diff -r bcea013ddd5a -r 2d4475143f70 tools/libxl/libxl.h --- a/tools/libxl/libxl.h Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl.h Mon Jul 12 14:56:37 2010 +0100 @@ -90,6 +90,24 @@ } libxl_domain_create_info; typedef struct { + /* + * Path is always set if the file refernece is valid. However if + * mapped is true then the actual file may already be unlinked. + */ + char *path; + int mapped; + void *data; + size_t size; +} libxl_file_reference; + +/* + * Instances of libxl_file_reference contained in this struct which + * have been mapped (with libxl_file_reference_map) will be unmapped + * by libxl_domain_build/restore. If either of these are never called + * then the user is responsible for calling + * libxl_file_reference_unmap. + */ +typedef struct { int max_vcpus; int cur_vcpus; int tsc_mode; @@ -98,7 +116,7 @@ uint32_t video_memkb; uint32_t shadow_memkb; bool disable_migrate; - const char *kernel; + libxl_file_reference kernel; int hvm; union { struct { @@ -115,7 +133,7 @@ struct { uint32_t slack_memkb; const char *cmdline; - const char *ramdisk; + libxl_file_reference ramdisk; const char *features; } pv; } u; @@ -308,6 +326,9 @@ int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req); int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force); +int libxl_file_reference_map(struct libxl_ctx *ctx, libxl_file_reference *f); +int libxl_file_reference_unmap(struct libxl_ctx *ctx, libxl_file_reference *f); + char *libxl_uuid2string(struct libxl_ctx *ctx, uint8_t uuid[16]); /* 0 means ERROR_ENOMEM, which we have logged */ diff -r bcea013ddd5a -r 2d4475143f70 tools/libxl/libxl_dom.c --- a/tools/libxl/libxl_dom.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl_dom.c Mon Jul 12 14:56:37 2010 +0100 @@ -143,22 +143,76 @@ int ret; int flags = 0; + xc_dom_loginit(ctx->xch); + dom = xc_dom_allocate(ctx->xch, info->u.pv.cmdline, info->u.pv.features); if (!dom) { XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_allocate failed"); - return -1; + return ERROR_FAIL; } - ret = xc_dom_linux_build(ctx->xch, dom, domid, info->target_memkb / 1024, - info->kernel, info->u.pv.ramdisk, flags, - state->store_port, &state->store_mfn, - state->console_port, &state->console_mfn); - if (ret != 0) { - xc_dom_release(dom); - XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "xc_dom_linux_build failed"); - return -2; + + if (info->kernel.mapped) { + if ( (ret = xc_dom_kernel_mem(dom, info->kernel.data, info->kernel.size)) != 0) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_kernel_mem failed"); + goto out; + } + } else { + if ( (ret = xc_dom_kernel_file(dom, info->kernel.path)) != 0) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_kernel_file failed"); + goto out; + } } + + if ( info->u.pv.ramdisk.path && strlen(info->u.pv.ramdisk.path) ) { + if (info->u.pv.ramdisk.mapped) { + if ( (ret = xc_dom_ramdisk_mem(dom, info->u.pv.ramdisk.data, info->u.pv.ramdisk.size)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_ramdisk_mem failed"); + goto out; + } + } else { + if ( (ret = xc_dom_ramdisk_file(dom, info->u.pv.ramdisk.path)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_ramdisk_file failed"); + goto out; + } + } + } + + dom->flags = flags; + dom->console_evtchn = state->console_port; + dom->xenstore_evtchn = state->store_port; + + if ( (ret = xc_dom_boot_xen_init(dom, ctx->xch, domid)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_boot_xen_init failed"); + goto out; + } + if ( (ret = xc_dom_parse_image(dom)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_parse_image failed"); + goto out; + } + if ( (ret = xc_dom_mem_init(dom, info->target_memkb / 1024)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_mem_init failed"); + goto out; + } + if ( (ret = xc_dom_boot_mem_init(dom)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_boot_mem_init failed"); + goto out; + } + if ( (ret = xc_dom_build_image(dom)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_build_image failed"); + goto out; + } + if ( (ret = xc_dom_boot_image(dom)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_boot_image failed"); + goto out; + } + + state->console_mfn = xc_dom_p2m_host(dom, dom->console_pfn); + state->store_mfn = xc_dom_p2m_host(dom, dom->xenstore_pfn); + + ret = 0; +out: xc_dom_release(dom); - return 0; + return ret == 0 ? 0 : ERROR_FAIL; } int build_hvm(struct libxl_ctx *ctx, uint32_t domid, @@ -166,12 +220,17 @@ { int ret; + if (info->kernel.mapped) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "build_hvm kernel cannot be mmapped"); + return ERROR_INVAL; + } + ret = xc_hvm_build_target_mem( ctx->xch, domid, (info->max_memkb - info->video_memkb) / 1024, (info->target_memkb - info->video_memkb) / 1024, - libxl_abs_path(ctx, (char *)info->kernel, + libxl_abs_path(ctx, (char *)info->kernel.path, libxl_xenfirmwaredir_path())); if (ret) { XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "hvm building failed"); diff -r bcea013ddd5a -r 2d4475143f70 tools/libxl/xl_cmdimpl.c --- a/tools/libxl/xl_cmdimpl.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/xl_cmdimpl.c Mon Jul 12 14:56:37 2010 +0100 @@ -196,7 +196,7 @@ if (c_info->hvm) { b_info->shadow_memkb = 0; /* Set later */ b_info->video_memkb = 8 * 1024; - b_info->kernel = "hvmloader"; + b_info->kernel.path = "hvmloader"; b_info->hvm = 1; b_info->u.hvm.pae = 1; b_info->u.hvm.apic = 1; @@ -366,7 +366,7 @@ printf("\t(image\n"); if (c_info->hvm) { printf("\t\t(hvm\n"); - printf("\t\t\t(loader %s)\n", b_info->kernel); + printf("\t\t\t(loader %s)\n", b_info->kernel.path); printf("\t\t\t(video_memkb %d)\n", b_info->video_memkb); printf("\t\t\t(shadow_memkb %d)\n", b_info->shadow_memkb); printf("\t\t\t(pae %d)\n", b_info->u.hvm.pae); @@ -397,9 +397,9 @@ printf("\t\t)\n"); } else { printf("\t\t(linux %d)\n", b_info->hvm); - printf("\t\t\t(kernel %s)\n", b_info->kernel); + printf("\t\t\t(kernel %s)\n", b_info->kernel.path); printf("\t\t\t(cmdline %s)\n", b_info->u.pv.cmdline); - printf("\t\t\t(ramdisk %s)\n", b_info->u.pv.ramdisk); + printf("\t\t\t(ramdisk %s)\n", b_info->u.pv.ramdisk.path); printf("\t\t)\n"); } printf("\t)\n"); @@ -563,7 +563,7 @@ b_info->video_memkb = l * 1024; if (!xlu_cfg_get_string (config, "kernel", &buf)) - b_info->kernel = strdup(buf); + b_info->kernel.path = strdup(buf); if (c_info->hvm == 1) { if (!xlu_cfg_get_long (config, "pae", &l)) @@ -603,7 +603,7 @@ b_info->u.pv.cmdline = cmdline; if (!xlu_cfg_get_string (config, "ramdisk", &buf)) - b_info->u.pv.ramdisk = strdup(buf); + b_info->u.pv.ramdisk.path = strdup(buf); } if (!xlu_cfg_get_list (config, "disk", &vbds, 0)) { diff -r bcea013ddd5a -r 2d4475143f70 tools/ocaml/libs/xl/xl_stubs.c --- a/tools/ocaml/libs/xl/xl_stubs.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/ocaml/libs/xl/xl_stubs.c Mon Jul 12 14:56:37 2010 +0100 @@ -103,7 +103,7 @@ c_val->target_memkb = Int64_val(Field(v, 6)); c_val->video_memkb = Int64_val(Field(v, 7)); c_val->shadow_memkb = Int64_val(Field(v, 8)); - c_val->kernel = String_val(Field(v, 9)); + c_val->kernel.path = String_val(Field(v, 9)); c_val->hvm = Tag_val(Field(v, 10)) == 0; infopriv = Field(Field(v, 10), 0); if (c_val->hvm) { @@ -119,7 +119,7 @@ } else { c_val->u.pv.slack_memkb = Int64_val(Field(infopriv, 0)); c_val->u.pv.cmdline = String_val(Field(infopriv, 1)); - c_val->u.pv.ramdisk = String_val(Field(infopriv, 2)); + c_val->u.pv.ramdisk.path = String_val(Field(infopriv, 2)); c_val->u.pv.features = String_val(Field(infopriv, 3)); } _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2010-Jul-12 14:01 UTC
[Xen-devel] [PATCH 8 of 9] libxl: add function to attach/detach a disk to/from the local VM
Useful if you need to read a guest filesystem (e.g. pygrub). I''m not overly thrilled with the implementation WRT tap interfaces, particularly WRT to detach. I was unable to find a way to get at the paramters necessary to call tap_ctl_destroy so I assumed for now it that is OK to assume that the tap device is going to be wanted for the actual domain at some point in the immediate future and hence there is no pressing need to destroy it. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> diff -r 2d4475143f70 -r 769e3bc13a6b tools/libxl/libxl.c --- a/tools/libxl/libxl.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl.c Mon Jul 12 14:56:37 2010 +0100 @@ -1425,6 +1425,48 @@ return libxl_device_del(ctx, &device, wait); } +const char * libxl_device_disk_local_attach(struct libxl_ctx *ctx, libxl_device_disk *disk) +{ + char *dev = NULL; + int phystype = disk->phystype; + switch (phystype) { + case PHYSTYPE_PHY: { + fprintf(stderr, "attaching PHY disk %s to domain 0\n", disk->physpath); + dev = disk->physpath; + break; + } + case PHYSTYPE_FILE: + /* let''s pretend is tap:aio for the moment */ + phystype = PHYSTYPE_AIO; + case PHYSTYPE_AIO: case PHYSTYPE_QCOW: case PHYSTYPE_QCOW2: case PHYSTYPE_VHD: { + const char *msg; + if (!tap_ctl_check(&msg)) { + const char *type = device_disk_string_of_phystype(phystype); + dev = get_blktap2_device(ctx, disk->physpath, type); + if (!dev) + dev = make_blktap2_device(ctx, disk->physpath, type); + } + break; + } + default: + XL_LOG(ctx, XL_LOG_ERROR, "unrecognized disk physical type: %d\n", phystype); + break; + } + return dev; +} + +int libxl_device_disk_local_detach(struct libxl_ctx *ctx, libxl_device_disk *disk) +{ + /* Nothing to do for PHYSTYPE_PHY. */ + + /* + * For other device types assume that the blktap2 process is + * needed by the soon to be started domain and do nothing. + */ + + return 0; +} + /******************************************************************************/ int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic) { diff -r 2d4475143f70 -r 769e3bc13a6b tools/libxl/libxl.h --- a/tools/libxl/libxl.h Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl.h Mon Jul 12 14:56:37 2010 +0100 @@ -423,6 +423,12 @@ libxl_device_disk *disk, libxl_diskinfo *diskinfo); int libxl_cdrom_insert(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk); +/* + * Make a disk available in this domain. Returns path to a device. + */ +const char * libxl_device_disk_local_attach(struct libxl_ctx *ctx, libxl_device_disk *disk); +int libxl_device_disk_local_detach(struct libxl_ctx *ctx, libxl_device_disk *disk); + typedef struct { char *backend; uint32_t backend_id; _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Campbell
2010-Jul-12 14:01 UTC
[Xen-devel] [PATCH 9 of 9] libxl/xl: support running bootloader (e.g. pygrub) in domain 0
Much of the bootloader interaction (including the Solaris and NetBSD portability bits) are translated pretty much directly from the python in tools/python/xen/xend/XendBootloader.py Signed-off-by: Ian Campbell <ian.campbell@citrix.com> diff -r 769e3bc13a6b -r 5ce5fe094152 tools/libxl/Makefile --- a/tools/libxl/Makefile Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/Makefile Mon Jul 12 15:01:23 2010 +0100 @@ -15,9 +15,9 @@ CFLAGS += -I. -fPIC CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl) -LIBS = $(LDFLAGS_libxenctrl) $(LDFLAGS_libxenguest) $(LDFLAGS_libxenstore) $(LDFLAGS_libblktapctl) +LIBS = $(LDFLAGS_libxenctrl) $(LDFLAGS_libxenguest) $(LDFLAGS_libxenstore) $(LDFLAGS_libblktapctl) -lutil -LIBXL_OBJS-y = osdeps.o libxl_paths.o +LIBXL_OBJS-y = osdeps.o libxl_paths.o libxl_bootloader.o LIBXL_OBJS = flexarray.o libxl.o libxl_dom.o libxl_exec.o libxl_xshelp.o libxl_device.o libxl_internal.o xenguest.o libxl_utils.o $(LIBXL_OBJS-y) AUTOINCS= libxlu_cfg_y.h libxlu_cfg_l.h diff -r 769e3bc13a6b -r 5ce5fe094152 tools/libxl/libxl.h --- a/tools/libxl/libxl.h Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/libxl.h Mon Jul 12 15:01:23 2010 +0100 @@ -132,7 +132,9 @@ } hvm; struct { uint32_t slack_memkb; - const char *cmdline; + const char *bootloader; + const char *bootloader_args; + char *cmdline; libxl_file_reference ramdisk; const char *features; } pv; @@ -329,6 +331,23 @@ int libxl_file_reference_map(struct libxl_ctx *ctx, libxl_file_reference *f); int libxl_file_reference_unmap(struct libxl_ctx *ctx, libxl_file_reference *f); +/* + * Run the configured bootloader for a PV domain and update + * info->kernel, info->u.pv.ramdisk and info->u.pv.cmdline as + * appropriate (any initial values present in these fields must have + * been allocated with malloc). + * + * Is a NOP on non-PV domains or those with no bootloader configured. + * + * Users should call libxl_file_reference_unmap on the kernel and + * ramdisk to cleanup or rely on libxl_domain_{build,restore} to do + * it. + */ +int libxl_run_bootloader(struct libxl_ctx *ctx, + libxl_domain_build_info *info, + libxl_device_disk *disk, + uint32_t domid); + char *libxl_uuid2string(struct libxl_ctx *ctx, uint8_t uuid[16]); /* 0 means ERROR_ENOMEM, which we have logged */ diff -r 769e3bc13a6b -r 5ce5fe094152 tools/libxl/libxl_bootloader.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxl/libxl_bootloader.c Mon Jul 12 15:01:23 2010 +0100 @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2010 Citrix Ltd. + * Author Ian Campbell <ian.campbell@citrix.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; version 2.1 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#include "libxl_osdeps.h" + +#include <string.h> +#include <pty.h> +#include <unistd.h> +#include <fcntl.h> + +#include <sys/stat.h> +#include <sys/types.h> + +#include "libxl.h" +#include "libxl_internal.h" + +#include "flexarray.h" + +#define XENCONSOLED_BUF_SIZE 16 +#define BOOTLOADER_BUF_SIZE 1024 + +static char **make_bootloader_args(struct libxl_ctx *ctx, + libxl_domain_build_info *info, + uint32_t domid, + const char *fifo, const char *disk) +{ + flexarray_t *args; + int nr = 0; + + args = flexarray_make(1, 1); + if (!args) + return NULL; + + flexarray_set(args, nr++, (char *)info->u.pv.bootloader); + + if (info->kernel.path) + flexarray_set(args, nr++, libxl_sprintf(ctx, "--kernel=%s", info->kernel.path)); + if (info->u.pv.ramdisk.path) + flexarray_set(args, nr++, libxl_sprintf(ctx, "--ramdisk=%s", info->u.pv.ramdisk.path)); + if (info->u.pv.cmdline && *info->u.pv.cmdline != ''\0'') + flexarray_set(args, nr++, libxl_sprintf(ctx, "--args=%s", info->u.pv.cmdline)); + + flexarray_set(args, nr++, libxl_sprintf(ctx, "--output=%s", fifo)); + flexarray_set(args, nr++, "--output-format=simple0"); + flexarray_set(args, nr++, libxl_sprintf(ctx, "--output-directory=%s", "/var/run/libxl/")); + + if (info->u.pv.bootloader_args) { + char *saveptr; + /* Operate on a duplicate since strtok modifes the argument */ + char *dup = libxl_strdup(ctx, info->u.pv.bootloader_args); + char *t = strtok_r(dup, " \t\n", &saveptr); + do { + flexarray_set(args, nr++, t); + } while ((t = strtok_r(NULL, " \t\n", &saveptr))); + } + + flexarray_set(args, nr++, strdup(disk)); + + /* Sentinal for execv */ + flexarray_set(args, nr++, NULL); + + return (char **) flexarray_contents(args); /* Frees args */ +} + +static int open_xenconsoled_pty(int *master, int *slave, char *slave_path, size_t slave_path_len) +{ + struct termios termattr; + int ret; + + ret = openpty(master, slave, NULL, NULL, NULL); + if (ret < 0) + return -1; + + ret = ttyname_r(*slave, slave_path, slave_path_len); + if (ret == -1) { + close(*master); + close(*slave); + *master = *slave = -1; + return -1; + } + + /* + * On Solaris, the pty master side will get cranky if we try + * to write to it while there is no slave. To work around this, + * keep the slave descriptor open until we''re done. Set it + * to raw terminal parameters, otherwise it will echo back + * characters, which will confuse the I/O loop below. + * Furthermore, a raw master pty device has no terminal + * semantics on Solaris, so don''t try to set any attributes + * for it. + */ +#if !defined(__sun__) && !defined(__NetBSD__) + tcgetattr(*master, &termattr); + cfmakeraw(&termattr); + tcsetattr(*master, TCSANOW, &termattr); + + close(*slave); + *slave = -1; +#else + tcgetattr(*slave, &termattr); + cfmakeraw(&termattr); + tcsetattr(*slave, TCSANOW, &termattr); +#endif + + fcntl(*master, F_SETFL, O_NDELAY); + + return 0; +} + +static pid_t fork_exec_bootloader(int *master, char *arg0, char **args) +{ + struct termios termattr; + pid_t pid = forkpty(master, NULL, NULL, NULL); + if (pid == -1) + return -1; + else if (pid == 0) { + setenv("TERM", "vt100", 1); + libxl_exec(-1, -1, -1, arg0, args); + return -1; + } + + /* + * On Solaris, the master pty side does not have terminal semantics, + * so don''t try to set any attributes, as it will fail. + */ +#if !defined(__sun__) + tcgetattr(*master, &termattr); + cfmakeraw(&termattr); + tcsetattr(*master, TCSANOW, &termattr); +#endif + + fcntl(*master, F_SETFL, O_NDELAY); + + return pid; +} + +/* + * filedescriptors: + * fifo_fd - bootstring output from the bootloader + * xenconsoled_fd - input/output from/to xenconsole + * bootloader_fd - input/output from/to pty that controls the bootloader + * The filedescriptors are NDELAY, so it''s ok to try to read + * bigger chunks than may be available, to keep e.g. curses + * screen redraws in the bootloader efficient. xenconsoled_fd is the side that + * gets xenconsole input, which will be keystrokes, so a small number + * is sufficient. bootloader_fd is pygrub output, which will be curses screen + * updates, so a larger number (1024) is appropriate there. + * + * For writeable descriptors, only include them in the set for select + * if there is actual data to write, otherwise this would loop too fast, + * eating up CPU time. + */ +static char * bootloader_interact(struct libxl_ctx *ctx, int xenconsoled_fd, int bootloader_fd, int fifo_fd) +{ + int ret; + + size_t nr_out = 0, size_out = 0; + char *output = NULL; + + /* input from xenconsole. read on xenconsoled_fd write to bootloader_fd */ + int xenconsoled_prod = 0, xenconsoled_cons = 0; + char xenconsoled_buf[XENCONSOLED_BUF_SIZE]; + /* output from bootloader. read on bootloader_fd write to xenconsoled_fd */ + int bootloader_prod = 0, bootloader_cons = 0; + char bootloader_buf[BOOTLOADER_BUF_SIZE]; + + while(1) { + fd_set wsel, rsel; + int nfds; + + if (xenconsoled_prod == xenconsoled_cons) + xenconsoled_prod = xenconsoled_cons = 0; + if (bootloader_prod == bootloader_cons) + bootloader_prod = bootloader_cons = 0; + + FD_ZERO(&rsel); + FD_SET(fifo_fd, &rsel); + nfds = fifo_fd + 1; + if (xenconsoled_prod == 0 || (xenconsoled_prod < BOOTLOADER_BUF_SIZE && xenconsoled_cons == 0)) { + FD_SET(xenconsoled_fd, &rsel); + nfds = xenconsoled_fd + 1 > nfds ? xenconsoled_fd + 1 : nfds; + } + if (bootloader_prod == 0 || (bootloader_prod < BOOTLOADER_BUF_SIZE && bootloader_cons == 0)) { + FD_SET(bootloader_fd, &rsel); + nfds = bootloader_fd + 1 > nfds ? bootloader_fd + 1 : nfds; + } + + FD_ZERO(&wsel); + if (bootloader_prod != bootloader_cons) { + FD_SET(xenconsoled_fd, &wsel); + nfds = xenconsoled_fd + 1 > nfds ? xenconsoled_fd + 1 : nfds; + } + if (xenconsoled_prod != xenconsoled_cons) { + FD_SET(bootloader_fd, &wsel); + nfds = bootloader_fd + 1 > nfds ? bootloader_fd + 1 : nfds; + } + + ret = select(nfds, &rsel, &wsel, NULL, NULL); + if (ret < 0) + goto out_err; + + /* Input from xenconsole, read xenconsoled_fd, write bootloader_fd */ + if (FD_ISSET(xenconsoled_fd, &rsel)) { + ret = read(xenconsoled_fd, &xenconsoled_buf[xenconsoled_prod], XENCONSOLED_BUF_SIZE - xenconsoled_prod); + if (ret < 0 && errno != EIO && errno != EAGAIN) + goto out_err; + if (ret > 0) + xenconsoled_prod += ret; + } + if (FD_ISSET(bootloader_fd, &wsel)) { + ret = write(bootloader_fd, &xenconsoled_buf[xenconsoled_cons], xenconsoled_prod - xenconsoled_cons); + if (ret < 0 && errno != EIO && errno != EAGAIN) + goto out_err; + if (ret > 0) + xenconsoled_cons += ret; + } + + /* Input from bootloader, read bootloader_fd, write xenconsoled_fd */ + if (FD_ISSET(bootloader_fd, &rsel)) { + ret = read(bootloader_fd, &bootloader_buf[bootloader_prod], BOOTLOADER_BUF_SIZE - bootloader_prod); + if (ret < 0 && errno != EIO && errno != EAGAIN) + goto out_err; + if (ret > 0) + bootloader_prod += ret; + } + if (FD_ISSET(xenconsoled_fd, &wsel)) { + ret = write(xenconsoled_fd, &bootloader_buf[bootloader_cons], bootloader_prod - bootloader_cons); + if (ret < 0 && errno != EIO && errno != EAGAIN) + goto out_err; + if (ret > 0) + bootloader_cons += ret; + } + + if (FD_ISSET(fifo_fd, &rsel)) { + if (size_out - nr_out < 256) { + char *temp; + size_t new_size = size_out == 0 ? 32 : size_out * 2; + + temp = realloc(output, new_size); + if (temp == NULL) + goto out_err; + output = temp; + memset(output + size_out, new_size - size_out, 0); + size_out = new_size; + } + + ret = read(fifo_fd, output + nr_out, size_out - nr_out); + if (ret > 0) + nr_out += ret; + if (ret == 0) + break; + } + } + + libxl_ptr_add(ctx, output); + return output; + +out_err: + free(output); + return NULL; +} + +static void parse_bootloader_result(struct libxl_ctx *ctx, + libxl_domain_build_info *info, + const char *o) +{ + while (*o != ''\0'') { + if (strncmp("kernel ", o, strlen("kernel ")) == 0) { + free(info->kernel.path); + info->kernel.path = strdup(o + strlen("kernel ")); + libxl_file_reference_map(ctx, &info->kernel); + unlink(info->kernel.path); + } else if (strncmp("ramdisk ", o, strlen("ramdisk ")) == 0) { + free(info->u.pv.ramdisk.path); + info->u.pv.ramdisk.path = strdup(o + strlen("ramdisk ")); + libxl_file_reference_map(ctx, &info->u.pv.ramdisk); + unlink(info->u.pv.ramdisk.path); + } else if (strncmp("args ", o, strlen("args ")) == 0) { + free(info->u.pv.cmdline); + info->u.pv.cmdline = strdup(o + strlen("args ")); + } + + o = o + strlen(o) + 1; + } +} + +int libxl_run_bootloader(struct libxl_ctx *ctx, + libxl_domain_build_info *info, + libxl_device_disk *disk, + uint32_t domid) +{ + int ret; + + char *fifo = NULL; + const char *diskpath = NULL; + char **args = NULL; + + char tempdir_template[] = "/var/run/libxl/bl.XXXXXX"; + char *tempdir; + + char *dom_console_xs_path; + char dom_console_slave_tty_path[PATH_MAX]; + + int xenconsoled_fd = -1, xenconsoled_slave = -1; + int bootloader_fd = -1, fifo_fd = -1; + + int blrc; + pid_t pid; + char *blout; + + struct stat st_buf; + + if (info->hvm || !info->u.pv.bootloader) + return 0; + + if (!disk) + return ERROR_INVAL; + + ret = mkdir("/var/run/libxl/", S_IRWXU); + if (ret < 0 && errno != EEXIST) + return ERROR_FAIL; + + ret = stat("/var/run/libxl/", &st_buf); + if (ret < 0) + return ERROR_FAIL; + + if (!S_ISDIR(st_buf.st_mode)) + return ERROR_FAIL; + + tempdir = mkdtemp(tempdir_template); + if (tempdir == NULL) + return ERROR_FAIL; + + ret = asprintf(&fifo, "%s/fifo", tempdir); + if (ret < 0) { + ret = ERROR_FAIL; + fifo = NULL; + goto out; + } + + ret = mkfifo(fifo, 0600); + if (ret < 0) { + ret = ERROR_FAIL; + goto out; + } + + diskpath = libxl_device_disk_local_attach(ctx, disk); + if (!diskpath) { + ret = ERROR_FAIL; + goto out; + } + + args = make_bootloader_args(ctx, info, domid, fifo, diskpath); + if (args == NULL) { + ret = ERROR_NOMEM; + goto out; + } + + /* + * We need to present the bootloader''s tty as a pty slave that xenconsole + * can access. Since the bootloader itself needs a pty slave, + * we end up with a connection like this: + * + * xenconsole -- (slave pty1 master) <-> (master pty2 slave) -- bootloader + * + * where we copy characters between the two master fds, as well as + * listening on the bootloader''s fifo for the results. + */ + ret = open_xenconsoled_pty(&xenconsoled_fd, &xenconsoled_slave, + &dom_console_slave_tty_path[0], + sizeof(dom_console_slave_tty_path)); + if (ret < 0) { + ret = ERROR_FAIL; + goto out; + } + + dom_console_xs_path = libxl_sprintf(ctx, "%s/serial/0/tty", libxl_xs_get_dompath(ctx, domid)); + libxl_xs_write(ctx, XBT_NULL, dom_console_xs_path, dom_console_slave_tty_path); + + pid = fork_exec_bootloader(&bootloader_fd, (char *)info->u.pv.bootloader, args); + if (pid < 0) { + ret = ERROR_FAIL; + goto out; + } + + while (1) { + fifo_fd = open(fifo, O_RDONLY); + if (fifo_fd > -1) + break; + + if (errno == EINTR) + continue; + + ret = ERROR_FAIL; + goto out; + } + + fcntl(fifo_fd, F_SETFL, O_NDELAY); + + blout = bootloader_interact(ctx, xenconsoled_fd, bootloader_fd, fifo_fd); + if (blout == NULL) { + ret = ERROR_FAIL; + goto out; + } + + pid = waitpid(pid, &blrc, 0); + if (pid == -1 || (pid > 0 && WIFEXITED(blrc) && WEXITSTATUS(blrc) != 0)) { + ret = ERROR_FAIL; + goto out; + } + + libxl_device_disk_local_detach(ctx, disk); + + parse_bootloader_result(ctx, info, blout); + + ret = 0; +out: + if (fifo_fd > -1) + close(fifo_fd); + if (bootloader_fd > -1) + close(bootloader_fd); + if (xenconsoled_fd > -1) + close(xenconsoled_fd); + if (xenconsoled_slave > -1) + close(xenconsoled_fd); + + if (fifo) { + unlink(fifo); + free(fifo); + } + + rmdir(tempdir); + + free(args); + + return ret; +} + diff -r 769e3bc13a6b -r 5ce5fe094152 tools/libxl/xl_cmdimpl.c --- a/tools/libxl/xl_cmdimpl.c Mon Jul 12 14:56:37 2010 +0100 +++ b/tools/libxl/xl_cmdimpl.c Mon Jul 12 15:01:23 2010 +0100 @@ -363,6 +363,12 @@ printf("\t(target_memkb %d)\n", b_info->target_memkb); printf("\t(nomigrate %d)\n", b_info->disable_migrate); + if (!c_info->hvm && b_info->u.pv.bootloader) { + printf("\t(bootloader %s)\n", b_info->u.pv.bootloader); + if (b_info->u.pv.bootloader_args) + printf("\t(bootloader_args %s)\n", b_info->u.pv.bootloader_args); + } + printf("\t(image\n"); if (c_info->hvm) { printf("\t\t(hvm\n"); @@ -598,6 +604,16 @@ if ((root || extra) && !cmdline) { fprintf(stderr, "Failed to allocate memory for cmdline\n"); + exit(1); + } + + if (!xlu_cfg_get_string (config, "bootloader", &buf)) + b_info->u.pv.bootloader = strdup(buf); + if (!xlu_cfg_get_string (config, "bootloader_args", &buf)) + b_info->u.pv.bootloader_args = strdup(buf); + + if (!b_info->u.pv.bootloader && !b_info->kernel.path) { + fprintf(stderr, "Neither kernel nor bootloader specified\n"); exit(1); } @@ -1159,6 +1175,12 @@ goto error_out; } + ret = libxl_run_bootloader(&ctx, &info2, num_disks > 0 ? &disks[0] : NULL, domid); + if (ret) { + fprintf(stderr, "failed to run bootloader: %d\n", ret); + goto error_out; + } + if (!restore_file || !need_daemon) { if (dm_info.saved_state) { free(dm_info.saved_state); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Ian Jackson
2010-Jul-13 18:23 UTC
Re: [Xen-devel] [PATCH 0 of 9] libxl/xl: support for domain 0 bootloader (e.g. pygrub)
Ian Campbell writes ("[Xen-devel] [PATCH 0 of 9] libxl/xl: support for domain 0 bootloader (e.g. pygrub)"):> This series adds support to libxl/xl for running a domain 0 > bootloader (such as pygrub).Does anyone have any comments on this ? It all looks reasonable to me but I haven''t reviewed every line. If no-one objects I will apply the whole series tomorrow. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Zhigang Wang
2010-Jul-14 01:24 UTC
Re: [Xen-devel] [PATCH 0 of 9] libxl/xl: support for domain 0 bootloader (e.g. pygrub)
On 07/14/2010 02:23 AM, Ian Jackson wrote:> Ian Campbell writes ("[Xen-devel] [PATCH 0 of 9] libxl/xl: support for domain 0 bootloader (e.g. pygrub)"): >> This series adds support to libxl/xl for running a domain 0 >> bootloader (such as pygrub). > > Does anyone have any comments on this ? It all looks reasonable to me > but I haven''t reviewed every line. If no-one objects I will apply the > whole series tomorrow. > > Ian.It''s really a necessary feature for xl. I''m happy to test it after you merge it. Thanks, Zhigang _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel