Roger Pau Monne
2013-Nov-18 14:56 UTC
[PATCH v3 00/9] libxl: add driver domain backend daemon
This patch series introduces support to launch device backends from driver domains using libxl, removing the need to setup udev on driver domains. The daemon currently supports vbds, vifs and qdisks as backends. Patches from 1 to 9 focus on getting libxl to work on driver domains, and add several helper functions that will be used to build the infraestructure needed for libxl to work on domains different than Dom0. The last patch (10) adds a new xl command, "devd", that can be used to launch a daemon that will listen to changes in the xenstore "backend" directory for the domain and perform the necessary actions to attach the devices. *Acked *[PATCH v3 1/9] libxl: create a local xenstore libxl and device-model *[PATCH v3 2/9] libxl: don''t remove device frontend path from driver *[PATCH v3 3/9] libxl: synchronize device removal when using driver *[PATCH v3 4/9] libxl: remove the Qemu bodge for driver domain *[PATCH v3 5/9] libxl: don''t launch Qemu on Dom0 for Qdisk devices on [PATCH v3 6/9] libxl: add Qdisk backend launch helper *[PATCH v3 7/9] xl: put daemonize code in it''s own function *[PATCH v3 8/9] libxl: revert 326a7b74 *[PATCH v3 9/9] libxl: add device backend listener in order to launch
Roger Pau Monne
2013-Nov-18 14:56 UTC
[PATCH v3 1/9] libxl: create a local xenstore libxl and device-model dir for guests
If libxl is executed inside a guest domain it needs write access to the local libxl xenstore dir (/local/<domid>/libxl) to store internal data. This also applies to Qemu which needs a /local/<domid>/device-model xenstore directory. This patch creates the mentioned directories for each guest launched from libxl. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Ian Jackson <Ian.Jackson@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> --- Changes since v1: * Change documentation for the xs paths. * Add a "driver_domain" option that gates the creation of the specifc xs paths. Changes since RFC: * Add documentation for the new paths. --- docs/man/xl.cfg.pod.5 | 5 +++++ docs/misc/xenstore-paths.markdown | 10 ++++++++++ tools/libxl/libxl.h | 9 +++++++++ tools/libxl/libxl_create.c | 17 +++++++++++++++++ tools/libxl/libxl_types.idl | 1 + tools/libxl/xl_cmdimpl.c | 2 ++ 6 files changed, 44 insertions(+), 0 deletions(-) diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5 index e6fc83f..3b227b7 100644 --- a/docs/man/xl.cfg.pod.5 +++ b/docs/man/xl.cfg.pod.5 @@ -307,6 +307,11 @@ which are incompatible with migration. Currently this is limited to enabling the invariant TSC feature flag in cpuid results when TSC is not emulated. +=item B<driver_domain=BOOLEAN> + +Specify that this domain is a driver domain. This enables certain +features needed in order to run a driver domain. + =back =head2 Devices diff --git a/docs/misc/xenstore-paths.markdown b/docs/misc/xenstore-paths.markdown index 1c634b5..a0fc003 100644 --- a/docs/misc/xenstore-paths.markdown +++ b/docs/misc/xenstore-paths.markdown @@ -318,6 +318,16 @@ protocol definition. A domain writable path. Available for arbitrary domain use. +### Paths private to the toolstack + +#### ~/device-model/$DOMID/state [w] + +Contains the status of the device models running on the domain. + +#### ~/libxl/$DOMID/qdisk-backend-pid [w] + +Contains the PIDs of the device models running on the domain. + ## Virtual Machine Paths The /vm/$UUID namespace is used by toolstacks to store various diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index c7dceda..18dd420 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -375,6 +375,15 @@ */ #define LIBXL_HAVE_CREATEINFO_PVH 1 +/* + * LIBXL_HAVE_DRIVER_DOMAIN_CREATION 1 + * + * If this is defined, libxl_domain_create_info contains a driver_domain + * field that can be used to tell libxl that the domain that is going + * to be created is a driver domain, so the necessary actions are taken. + */ +#define LIBXL_HAVE_DRIVER_DOMAIN_CREATION 1 + /* Functions annotated with LIBXL_EXTERNAL_CALLERS_ONLY may not be * called from within libxl itself. Callers outside libxl, who * do not #include libxl_internal.h, are fine. */ diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index 5e9cdcc..fe7ba0d 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -39,6 +39,7 @@ int libxl__domain_create_info_setdefault(libxl__gc *gc, } libxl_defbool_setdefault(&c_info->run_hotplug_scripts, true); + libxl_defbool_setdefault(&c_info->driver_domain, false); return 0; } @@ -546,6 +547,22 @@ retry_transaction: libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/data", dom_path), rwperm, ARRAY_SIZE(rwperm)); + + if (libxl_defbool_val(info->driver_domain)) { + /* + * Create a local "libxl" directory for each guest, since we might want + * to use libxl from inside the guest + */ + libxl__xs_mkdir(gc, t, GCSPRINTF("%s/libxl", dom_path), rwperm, + ARRAY_SIZE(rwperm)); + /* + * Create a local "device-model" directory for each guest, since we + * might want to use Qemu from inside the guest + */ + libxl__xs_mkdir(gc, t, GCSPRINTF("%s/device-model", dom_path), rwperm, + ARRAY_SIZE(rwperm)); + } + if (info->type == LIBXL_DOMAIN_TYPE_HVM) libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/hvmloader/generation-id-address", dom_path), diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index de5bac3..cba8eff 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -275,6 +275,7 @@ libxl_domain_create_info = Struct("domain_create_info",[ ("poolid", uint32), ("run_hotplug_scripts",libxl_defbool), ("pvh", libxl_defbool), + ("driver_domain",libxl_defbool), ], dir=DIR_IN) libxl_domain_restore_params = Struct("domain_restore_params", [ diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 8690ec7..1928424 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -849,6 +849,8 @@ static void parse_config_data(const char *config_source, if (!xlu_cfg_get_long(config, "max_event_channels", &l, 0)) b_info->event_channels = l; + xlu_cfg_get_defbool(config, "driver_domain", &c_info->driver_domain, 0); + switch(b_info->type) { case LIBXL_DOMAIN_TYPE_HVM: if (!xlu_cfg_get_string (config, "kernel", &buf, 0)) -- 1.7.7.5 (Apple Git-26) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Roger Pau Monne
2013-Nov-18 14:56 UTC
[PATCH v3 2/9] libxl: don''t remove device frontend path from driver domains
A domain different than LIBXL_TOOLSTACK_DOMID should not try to remove the frontend paths of a device. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Ian Jackson <Ian.Jackson@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> --- Changes since RFC: * Toolstack domain is in charge of cleaning both the frontend and the backend paths, driver domain only removes the first directory of the backend path. * I have decided to not take IanC Ack on this patch because it has changed since RFC. --- tools/libxl/libxl_device.c | 20 ++++++++++++++++++-- 1 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c index cce9e32..d5f23cf 100644 --- a/tools/libxl/libxl_device.c +++ b/tools/libxl/libxl_device.c @@ -551,6 +551,10 @@ int libxl__device_destroy(libxl__gc *gc, libxl__device *dev) const char *tapdisk_params; xs_transaction_t t = 0; int rc; + uint32_t domid; + + rc = libxl__get_domid(gc, &domid); + if (rc) goto out; for (;;) { rc = libxl__xs_transaction_start(gc, &t); @@ -560,8 +564,20 @@ int libxl__device_destroy(libxl__gc *gc, libxl__device *dev) rc = libxl__xs_read_checked(gc, t, tapdisk_path, &tapdisk_params); if (rc) goto out; - libxl__xs_path_cleanup(gc, t, fe_path); - libxl__xs_path_cleanup(gc, t, be_path); + if (domid == LIBXL_TOOLSTACK_DOMID) { + /* + * The toolstack domain is in charge for removing both the + * frontend and the backend path + */ + libxl__xs_path_cleanup(gc, t, fe_path); + libxl__xs_path_cleanup(gc, t, be_path); + } else if (dev->backend_domid == domid) { + /* + * The driver domain is in charge for removing what it can + * from the backend path + */ + libxl__xs_path_cleanup(gc, t, be_path); + } rc = libxl__xs_transaction_commit(gc, &t); if (!rc) break; -- 1.7.7.5 (Apple Git-26) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Roger Pau Monne
2013-Nov-18 14:56 UTC
[PATCH v3 3/9] libxl: synchronize device removal when using driver domains
Synchronize the clean up of the backend from the toolstack domain when the driver domain has actually finished closing the backend for the device. This is accomplished by waiting for the driver domain to remove the directory containing the backend keys, then the toolstack domain will finish the cleanup by removing the empty folders on the backend path. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Ian Jackson <Ian.Jackson@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> --- Changes since v1: * Place cleanup of aodev events in device_hotplug_clean, get rid of some code duplication. Changes since RFC: * This patch has been reworked to synchronize the toolstack and the driver domain, by making the driver domain only remove the first directory of the backend path, and the toolstack domain remove the rest. --- tools/libxl/libxl_device.c | 80 ++++++++++++++++++++++++++++++++++++++++- tools/libxl/libxl_internal.h | 2 + 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c index d5f23cf..b7168d4 100644 --- a/tools/libxl/libxl_device.c +++ b/tools/libxl/libxl_device.c @@ -432,6 +432,11 @@ void libxl__prepare_ao_device(libxl__ao *ao, libxl__ao_device *aodev) aodev->num_exec = 0; /* Initialize timer for QEMU Bodge and hotplug execution */ libxl__ev_time_init(&aodev->timeout); + /* + * Initialize xs_watch, because it's not used on all possible + * execution paths, but it's unconditionally destroyed when finished. + */ + libxl__ev_xswatch_init(&aodev->xs_watch); aodev->active = 1; /* We init this here because we might call device_hotplug_done * without actually calling any hotplug script */ @@ -709,6 +714,14 @@ static void device_hotplug_child_death_cb(libxl__egc *egc, libxl__ev_child *child, pid_t pid, int status); +static void device_destroy_be_timeout_cb(libxl__egc *egc, libxl__ev_time *ev, + const struct timeval *requested_abs); + +static void device_destroy_be_watch_cb(libxl__egc *egc, + libxl__ev_xswatch *watch, + const char *watch_path, + const char *event_path); + static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev); static void device_hotplug_clean(libxl__gc *gc, libxl__ao_device *aodev); @@ -768,6 +781,7 @@ void libxl__initiate_device_remove(libxl__egc *egc, LOG(ERROR, "unable to get info for domain %d", domid); goto out; } + if (QEMU_BACKEND(aodev->dev) && (info.paused || info.dying || info.shutdown)) { /* @@ -919,8 +933,28 @@ static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev) */ rc = libxl__get_domid(gc, &domid); if (rc) goto out; - if (aodev->dev->backend_domid != domid) - goto out; + if (aodev->dev->backend_domid != domid) { + if (aodev->action != LIBXL__DEVICE_ACTION_REMOVE) + goto out; + + rc = libxl__ev_time_register_rel(gc, &aodev->timeout, + device_destroy_be_timeout_cb, + LIBXL_DESTROY_TIMEOUT * 1000); + if (rc) { + LOG(ERROR, "setup of xs watch timeout failed"); + goto out; + } + + rc = libxl__ev_xswatch_register(gc, &aodev->xs_watch, + device_destroy_be_watch_cb, + be_path); + if (rc) { + LOG(ERROR, "setup of xs watch for %s failed", be_path); + libxl__ev_time_deregister(gc, &aodev->timeout); + goto out; + } + return; + } /* Check if we have to execute hotplug scripts for this device * and return the necessary args/env vars for execution */ @@ -1038,6 +1072,47 @@ error: device_hotplug_done(egc, aodev); } +static void device_destroy_be_timeout_cb(libxl__egc *egc, libxl__ev_time *ev, + const struct timeval *requested_abs) +{ + libxl__ao_device *aodev = CONTAINER_OF(ev, *aodev, timeout); + STATE_AO_GC(aodev->ao); + + LOG(ERROR, "timed out while waiting for %s to be removed", + libxl__device_backend_path(gc, aodev->dev)); + + aodev->rc = ERROR_TIMEDOUT; + + device_hotplug_done(egc, aodev); + return; +} + +static void device_destroy_be_watch_cb(libxl__egc *egc, + libxl__ev_xswatch *watch, + const char *watch_path, + const char *event_path) +{ + libxl__ao_device *aodev = CONTAINER_OF(watch, *aodev, xs_watch); + STATE_AO_GC(aodev->ao); + const char *dir; + int rc; + + rc = libxl__xs_read_checked(gc, XBT_NULL, watch_path, &dir); + if (rc) { + LOG(ERROR, "unable to read backend path: %s", watch_path); + aodev->rc = rc; + goto out; + } + if (dir) { + /* backend path still exists, wait a little longer... */ + return; + } + +out: + /* We are done, backend path no longer exists */ + device_hotplug_done(egc, aodev); +} + static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev) { STATE_AO_GC(aodev->ao); @@ -1060,6 +1135,7 @@ static void device_hotplug_clean(libxl__gc *gc, libxl__ao_device *aodev) { /* Clean events and check reentrancy */ libxl__ev_time_deregister(gc, &aodev->timeout); + libxl__ev_xswatch_deregister(gc, &aodev->xs_watch); assert(!libxl__ev_child_inuse(&aodev->child)); } diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 23ff265..e3b9fb4 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -1928,6 +1928,8 @@ struct libxl__ao_device { libxl__ev_devstate backend_ds; /* Bodge for Qemu devices, also used for timeout of hotplug execution */ libxl__ev_time timeout; + /* xenstore watch for backend path of driver domains */ + libxl__ev_xswatch xs_watch; /* device hotplug execution */ const char *what; int num_exec; -- 1.7.7.5 (Apple Git-26) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Roger Pau Monne
2013-Nov-18 14:56 UTC
[PATCH v3 4/9] libxl: remove the Qemu bodge for driver domain devices
When Qemu is launched from a driver domain to act as a PV disk backend we can make sure that Qemu is running before detaching devices, so there's no need for the bodge there. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Ian Jackson <Ian.Jackson@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> --- Changes since v1: * Remove a superfluous return. --- tools/libxl/libxl_device.c | 69 ++++++++++++++++++++++++++++++++----------- 1 files changed, 51 insertions(+), 18 deletions(-) diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c index b7168d4..d995c83 100644 --- a/tools/libxl/libxl_device.c +++ b/tools/libxl/libxl_device.c @@ -772,31 +772,38 @@ void libxl__initiate_device_remove(libxl__egc *egc, char *online_path = GCSPRINTF("%s/online", be_path); const char *state; libxl_dominfo info; - uint32_t domid = aodev->dev->domid; + uint32_t my_domid, domid = aodev->dev->domid; int rc = 0; - libxl_dominfo_init(&info); - rc = libxl_domain_info(CTX, &info, domid); + rc = libxl__get_domid(gc, &my_domid); if (rc) { - LOG(ERROR, "unable to get info for domain %d", domid); + LOG(ERROR, "unable to get my domid"); goto out; } - if (QEMU_BACKEND(aodev->dev) && - (info.paused || info.dying || info.shutdown)) { - /* - * TODO: 4.2 Bodge due to QEMU, see comment on top of - * libxl__initiate_device_remove in libxl_internal.h - */ - rc = libxl__ev_time_register_rel(gc, &aodev->timeout, - device_qemu_timeout, - LIBXL_QEMU_BODGE_TIMEOUT * 1000); + if (my_domid == LIBXL_TOOLSTACK_DOMID) { + libxl_dominfo_init(&info); + rc = libxl_domain_info(CTX, &info, domid); if (rc) { - LOG(ERROR, "unable to register timeout for Qemu device %s", - be_path); + LOG(ERROR, "unable to get info for domain %d", domid); goto out; } - return; + if (QEMU_BACKEND(aodev->dev) && + (info.paused || info.dying || info.shutdown)) { + /* + * TODO: 4.2 Bodge due to QEMU, see comment on top of + * libxl__initiate_device_remove in libxl_internal.h + */ + rc = libxl__ev_time_register_rel(gc, &aodev->timeout, + device_qemu_timeout, + LIBXL_QEMU_BODGE_TIMEOUT * 1000); + if (rc) { + LOG(ERROR, "unable to register timeout for Qemu device %s", + be_path); + goto out; + } + return; + } } for (;;) { @@ -865,17 +872,43 @@ static void device_qemu_timeout(libxl__egc *egc, libxl__ev_time *ev, STATE_AO_GC(aodev->ao); char *be_path = libxl__device_backend_path(gc, aodev->dev); char *state_path = GCSPRINTF("%s/state", be_path); + const char *xs_state; + xs_transaction_t t = 0; int rc = 0; libxl__ev_time_deregister(gc, &aodev->timeout); - rc = libxl__xs_write_checked(gc, XBT_NULL, state_path, "6"); - if (rc) goto out; + for (;;) { + rc = libxl__xs_transaction_start(gc, &t); + if (rc) { + LOG(ERROR, "unable to start transaction"); + goto out; + } + + /* + * Check that the state path exists and is actually different than + * 6 before unconditionally setting it. If Qemu runs on a driver + * domain it is possible that the driver domain has already cleaned + * the backend path if the device has reached state 6. + */ + rc = libxl__xs_read_checked(gc, XBT_NULL, state_path, &xs_state); + if (rc) goto out; + + if (xs_state && atoi(xs_state) != XenbusStateClosed) { + rc = libxl__xs_write_checked(gc, XBT_NULL, state_path, "6"); + if (rc) goto out; + } + + rc = libxl__xs_transaction_commit(gc, &t); + if (!rc) break; + if (rc < 0) goto out; + } device_hotplug(egc, aodev); return; out: + libxl__xs_transaction_abort(gc, &t); aodev->rc = rc; device_hotplug_done(egc, aodev); } -- 1.7.7.5 (Apple Git-26) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Roger Pau Monne
2013-Nov-18 14:56 UTC
[PATCH v3 5/9] libxl: don''t launch Qemu on Dom0 for Qdisk devices on driver domains
In libxl__need_xenpv_qemu check that the backend domain of the Qdisk device is Dom0 before launching a Qemu instance in the toolstack domain. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Ian Jackson <Ian.Jackson@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> --- Changes since RFC: * Fetch and use domid instead of LIBXL_TOOLSTACK_DOMID (altough the function is only called on Dom0 right now). --- tools/libxl/libxl_dm.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c index 85a08af..b4798b8 100644 --- a/tools/libxl/libxl_dm.c +++ b/tools/libxl/libxl_dm.c @@ -1354,6 +1354,7 @@ int libxl__need_xenpv_qemu(libxl__gc *gc, int nr_disks, libxl_device_disk *disks) { int i, ret = 0; + uint32_t domid; /* * qemu is required in order to support 2 or more consoles. So switch all @@ -1379,8 +1380,11 @@ int libxl__need_xenpv_qemu(libxl__gc *gc, } if (nr_disks > 0) { + ret = libxl__get_domid(gc, &domid); + if (ret) goto out; for (i = 0; i < nr_disks; i++) { - if (disks[i].backend == LIBXL_DISK_BACKEND_QDISK) { + if (disks[i].backend == LIBXL_DISK_BACKEND_QDISK && + disks[i].backend_domid == domid) { ret = 1; goto out; } -- 1.7.7.5 (Apple Git-26) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Roger Pau Monne
2013-Nov-18 14:56 UTC
[PATCH v3 6/9] libxl: add Qdisk backend launch helper
Current Qemu launch functions in libxl require the usage of data structures only avaialbe on domain creation. All this information is not need in order to launch a Qemu instance to serve Qdisk backends, so introduce a new simplified helper that can be used to launch Qemu/Qdisk, that will be used to launch Qdisk in driver domains. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Cc: Ian Jackson <Ian.Jackson@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> Cc: Anthony PERARD <anthony.perard@citrix.com> Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- tools/libxl/libxl_dm.c | 146 +++++++++++++++++++++++++++++++++++++----- tools/libxl/libxl_internal.h | 6 ++ 2 files changed, 136 insertions(+), 16 deletions(-) diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c index b4798b8..64123aa 100644 --- a/tools/libxl/libxl_dm.c +++ b/tools/libxl/libxl_dm.c @@ -42,6 +42,21 @@ static const char *qemu_xen_path(libxl__gc *gc) #endif } +static int libxl__create_qemu_logfile(libxl__gc *gc, char *name) +{ + char *logfile; + int logfile_w; + + libxl_create_logfile(CTX, name, &logfile); + logfile_w = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); + free(logfile); + + if (logfile_w < 0) + LOGE(ERROR, "unable to open Qemu logfile"); + + return logfile_w; +} + const char *libxl__domain_device_model(libxl__gc *gc, const libxl_domain_build_info *info) { @@ -1149,7 +1164,7 @@ void libxl__spawn_local_dm(libxl__egc *egc, libxl__dm_spawn_state *dmss) const libxl_domain_create_info *c_info = &guest_config->c_info; const libxl_domain_build_info *b_info = &guest_config->b_info; const libxl_vnc_info *vnc = libxl__dm_vnc(guest_config); - char *path, *logfile; + char *path; int logfile_w, null; int rc; char **args, **arg; @@ -1204,11 +1219,12 @@ void libxl__spawn_local_dm(libxl__egc *egc, libxl__dm_spawn_state *dmss) libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/disable_pf", path), "%d", !libxl_defbool_val(b_info->u.hvm.xen_platform_pci)); - libxl_create_logfile(ctx, - libxl__sprintf(gc, "qemu-dm-%s", c_info->name), - &logfile); - logfile_w = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); - free(logfile); + logfile_w = libxl__create_qemu_logfile(gc, GCSPRINTF("qemu-dm-%s", + c_info->name)); + if (logfile_w < 0) { + rc = logfile_w; + goto out; + } null = open("/dev/null", O_RDONLY); const char *dom_path = libxl__xs_get_dompath(gc, domid); @@ -1268,7 +1284,6 @@ out: static void device_model_confirm(libxl__egc *egc, libxl__spawn_state *spawn, const char *xsdata) { - libxl__dm_spawn_state *dmss = CONTAINER_OF(spawn, *dmss, spawn); STATE_AO_GC(spawn->ao); if (!xsdata) @@ -1320,18 +1335,91 @@ static void device_model_spawn_outcome(libxl__egc *egc, dmss->callback(egc, dmss, rc); } -int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid) +void libxl__spawn_qdisk_backend(libxl__egc *egc, libxl__dm_spawn_state *dmss) { - char *pid; - int ret; + STATE_AO_GC(dmss->spawn.ao); + flexarray_t *dm_args; + char **args; + const char *dm; + int logfile_w, null, rc; + uint32_t domid = dmss->guest_domid; + + /* Always use qemu-xen as device model */ + dm = qemu_xen_path(gc); + + dm_args = flexarray_make(gc, 15, 1); + flexarray_vappend(dm_args, dm, "-xen-domid", + GCSPRINTF("%d", domid), NULL); + flexarray_append(dm_args, "-xen-attach"); + flexarray_vappend(dm_args, "-name", + GCSPRINTF("domain-%u", domid), NULL); + flexarray_append(dm_args, "-nographic"); + flexarray_vappend(dm_args, "-M", "xenpv", NULL); + flexarray_vappend(dm_args, "-monitor", "/dev/null", NULL); + flexarray_vappend(dm_args, "-serial", "/dev/null", NULL); + flexarray_vappend(dm_args, "-parallel", "/dev/null", NULL); + flexarray_append(dm_args, NULL); + args = (char **) flexarray_contents(dm_args); - pid = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "/local/domain/%d/image/device-model-pid", domid)); - if (!pid || !atoi(pid)) { - LOG(ERROR, "could not find device-model's pid for dom %u", domid); - ret = ERROR_FAIL; + logfile_w = libxl__create_qemu_logfile(gc, GCSPRINTF("qdisk-%u", domid)); + if (logfile_w < 0) { + rc = logfile_w; + goto error; + } + null = open("/dev/null", O_RDONLY); + + dmss->guest_config = NULL; + /* + * Clearly specify Qemu not using a saved state, so + * device_model_spawn_outcome doesn't try to unlink it. + */ + dmss->build_state = libxl__zalloc(gc, sizeof(*dmss->build_state)); + dmss->build_state->saved_state = 0; + + dmss->spawn.what = GCSPRINTF("domain %u Qdisk backend", domid); + dmss->spawn.xspath = GCSPRINTF("device-model/%u/state", domid); + dmss->spawn.timeout_ms = LIBXL_DEVICE_MODEL_START_TIMEOUT * 1000; + /* + * We cannot save Qemu pid anywhere in the xenstore guest dir, + * because we will call this from unprivileged driver domains, + * so save it in the current domain libxl private dir. + */ + dmss->spawn.pidpath = GCSPRINTF("libxl/%u/qdisk-backend-pid", domid); + dmss->spawn.midproc_cb = libxl__spawn_record_pid; + dmss->spawn.confirm_cb = device_model_confirm; + dmss->spawn.failure_cb = device_model_startup_failed; + dmss->spawn.detached_cb = device_model_detached; + rc = libxl__spawn_spawn(egc, &dmss->spawn); + if (rc < 0) + goto error; + if (!rc) { /* inner child */ + setsid(); + libxl__exec(gc, null, logfile_w, logfile_w, dm, args, NULL); + } + + return; + +error: + assert(rc); + dmss->callback(egc, dmss, rc); + return; +} + +/* Generic function to signal a Qemu instance to exit */ +static int kill_device_model(libxl__gc *gc, const char *xs_path_pid) +{ + const char *xs_pid; + int ret, pid; + + ret = libxl__xs_read_checked(gc, XBT_NULL, xs_path_pid, &xs_pid); + if (ret || !xs_pid) { + LOG(ERROR, "unable to find device model pid in %s", xs_path_pid); + ret = ret ? : ERROR_FAIL; goto out; } - ret = kill(atoi(pid), SIGHUP); + pid = atoi(xs_pid); + + ret = kill(pid, SIGHUP); if (ret < 0 && errno == ESRCH) { LOG(ERROR, "Device Model already exited"); ret = 0; @@ -1339,7 +1427,7 @@ int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid) LOG(DEBUG, "Device Model signaled"); ret = 0; } else { - LOGE(ERROR, "failed to kill Device Model [%d]", atoi(pid)); + LOGE(ERROR, "failed to kill Device Model [%d]", pid); ret = ERROR_FAIL; goto out; } @@ -1348,6 +1436,32 @@ out: return ret; } +/* Helper to destroy a Qdisk backend */ +int libxl__destroy_qdisk_backend(libxl__gc *gc, uint32_t domid) +{ + char *pid_path; + int rc; + + pid_path = GCSPRINTF("libxl/%u/qdisk-backend-pid", domid); + + rc = kill_device_model(gc, pid_path); + if (rc) + goto out; + + libxl__xs_rm_checked(gc, XBT_NULL, pid_path); + libxl__xs_rm_checked(gc, XBT_NULL, + GCSPRINTF("device-model/%u", domid)); + +out: + return rc; +} + +int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid) +{ + return kill_device_model(gc, + GCSPRINTF("/local/domain/%d/image/device-model-pid", domid)); +} + int libxl__need_xenpv_qemu(libxl__gc *gc, int nr_consoles, libxl__device_console *consoles, int nr_vfbs, libxl_device_vfb *vfbs, diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index e3b9fb4..cff3518 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -2548,6 +2548,12 @@ _hidden void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state*); _hidden char *libxl__stub_dm_name(libxl__gc *gc, const char * guest_name); +/* Qdisk backend launch helpers */ + +_hidden void libxl__spawn_qdisk_backend(libxl__egc *egc, + libxl__dm_spawn_state *dmss); +_hidden int libxl__destroy_qdisk_backend(libxl__gc *gc, uint32_t domid); + /*----- Domain creation -----*/ typedef struct libxl__domain_create_state libxl__domain_create_state; -- 1.7.7.5 (Apple Git-26) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Roger Pau Monne
2013-Nov-18 14:56 UTC
[PATCH v3 7/9] xl: put daemonize code in it''s own function
Move the daemonizer code from create_domain into it's own function that can be called from other places different than create_domain. This will be used to daemonize the driver domain backend handler. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Ian Jackson <Ian.Jackson@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> --- tools/libxl/xl_cmdimpl.c | 97 ++++++++++++++++++++++++++------------------- 1 files changed, 56 insertions(+), 41 deletions(-) diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 1928424..2d147d4 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -402,6 +402,56 @@ out: if (ferror(stdout) || fflush(stdout)) { perror("stdout"); exit(-1); } } +static int do_daemonize(char *name) +{ + char *fullname; + pid_t child1, got_child; + int nullfd, ret = 0; + int status = 0; + + child1 = xl_fork(child_waitdaemon); + if (child1) { + for (;;) { + got_child = xl_waitpid(child_waitdaemon, &status, 0); + if (got_child == child1) break; + assert(got_child == -1); + perror("failed to wait for daemonizing child"); + ret = ERROR_FAIL; + goto out; + } + if (status) { + libxl_report_child_exitstatus(ctx, XTL_ERROR, + "daemonizing child", child1, status); + ret = ERROR_FAIL; + goto out; + } + ret = 1; + goto out; + } + + postfork(); + + ret = libxl_create_logfile(ctx, name, &fullname); + if (ret) { + LOG("failed to open logfile %s: %s",fullname,strerror(errno)); + exit(-1); + } + + CHK_ERRNO(( logfile = open(fullname, O_WRONLY|O_CREAT|O_APPEND, + 0644) )<0); + free(fullname); + + CHK_ERRNO(( nullfd = open("/dev/null", O_RDONLY) )<0); + dup2(nullfd, 0); + dup2(logfile, 1); + dup2(logfile, 2); + + CHK_ERRNO(daemon(0, 1) < 0); + +out: + return ret; +} + static int parse_action_on_shutdown(const char *buf, libxl_action_on_shutdown *a) { int i; @@ -1902,7 +1952,6 @@ static uint32_t create_domain(struct domain_create *dom_info) void *config_data = 0; int config_len = 0; int restore_fd = -1; - int status = 0; const libxl_asyncprogress_how *autoconnect_console_how; struct save_file_header hdr; @@ -2141,52 +2190,18 @@ start: autoconnect_vncviewer(domid, vncautopass); if (need_daemon) { - char *fullname, *name; - pid_t child1, got_child; - int nullfd; - - child1 = xl_fork(child_waitdaemon); - if (child1) { - got_child = xl_waitpid(child_waitdaemon, &status, 0); - if (got_child != child1) { - assert(got_child == -1); - perror("failed to wait for daemonizing child"); - ret = ERROR_FAIL; - goto out; - } - if (status) { - libxl_report_child_exitstatus(ctx, XTL_ERROR, - "daemonizing child", child1, status); - ret = ERROR_FAIL; - goto out; - } - ret = domid; - goto out; - } - - postfork(); + char *name; if (asprintf(&name, "xl-%s", d_config.c_info.name) < 0) { LOG("Failed to allocate memory in asprintf"); exit(1); } - rc = libxl_create_logfile(ctx, name, &fullname); - if (rc) { - LOG("failed to open logfile %s: %s",fullname,strerror(errno)); - exit(-1); - } - - CHK_ERRNO(( logfile = open(fullname, O_WRONLY|O_CREAT|O_APPEND, - 0644) )<0); - free(fullname); + ret = do_daemonize(name); free(name); - - CHK_ERRNO(( nullfd = open("/dev/null", O_RDONLY) )<0); - dup2(nullfd, 0); - dup2(logfile, 1); - dup2(logfile, 2); - - CHK_ERRNO(daemon(0, 1) < 0); + if (ret) { + ret = (ret == 1) ? domid : ret; + goto out; + } need_daemon = 0; } LOG("Waiting for domain %s (domid %d) to die [pid %ld]", -- 1.7.7.5 (Apple Git-26) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
When running libxl from a driver domain there's no xenstore pid file (because xenstore is not running on the driver domain). Also, at that point in libxl initialization there's no way to know wether libxl is running on a domain different than Dom0, so just revert the change in order to allow libxl to work on driver domains. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Ian Jackson <Ian.Jackson@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> --- tools/libxl/libxl.c | 7 ------- tools/libxl/libxl_internal.h | 1 - 2 files changed, 0 insertions(+), 8 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 0de1112..b89b7f4 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -25,7 +25,6 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, unsigned flags, xentoollog_logger * lg) { libxl_ctx *ctx = NULL; - struct stat stat_buf; int rc; if (version != LIBXL_VERSION) { rc = ERROR_VERSION; goto out; } @@ -82,12 +81,6 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version, rc = libxl__poller_init(ctx, &ctx->poller_app); if (rc) goto out; - if ( stat(XENSTORE_PID_FILE, &stat_buf) != 0 ) { - LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Is xenstore daemon running?\n" - "failed to stat %s", XENSTORE_PID_FILE); - rc = ERROR_FAIL; goto out; - } - ctx->xch = xc_interface_open(lg,lg,0); if (!ctx->xch) { LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno, diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index cff3518..670234b 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -378,7 +378,6 @@ typedef struct { #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) #define PCI_FUNC(devfn) ((devfn) & 0x07) #define AUTO_PHP_SLOT 0x100 -#define XENSTORE_PID_FILE "/var/run/xenstored.pid" #define PROC_PCI_NUM_RESOURCES 7 #define PCI_BAR_IO 0x01 -- 1.7.7.5 (Apple Git-26) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Roger Pau Monne
2013-Nov-18 14:56 UTC
[PATCH v3 9/9] libxl: add device backend listener in order to launch backends
Add the necessary logic in libxl to allow it to act as a listener for launching backends in a driver domain, replacing udev (like we already do on Dom0). This new functionality is acomplished by watching the domain backend path (/local/domain/<domid>/backend) and reacting to device creation/destruction. The way to launch this listener daemon is from xl, using the newly introduced "devd" command. The command will daemonize by default, using "xldevd.log" as it's logfile. Optionally the user can force the execution of the listener in the foreground by passing the "-F" option to the devd command. Current backends handled by this daemon include Qdisk, vbd and vif device types. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Ian Jackson <Ian.Jackson@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> --- In order to use Qdisk on a driver domain the following patch has to be applied to Qemu: http://marc.info/?l=qemu-devel&m=137953390608727&w=2 --- Changes since v1: * Use nested aos. * Reword some comments. --- tools/libxl/libxl.c | 339 +++++++++++++++++++++++++++++++++++++++++++++ tools/libxl/libxl.h | 12 ++ tools/libxl/xl.h | 1 + tools/libxl/xl_cmdimpl.c | 24 +++ tools/libxl/xl_cmdtable.c | 6 + 5 files changed, 382 insertions(+), 0 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index b89b7f4..4292c78 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -3528,6 +3528,345 @@ DEFINE_DEVICE_ADD(vtpm) /******************************************************************************/ +/* + * Data structures used to track devices handled by driver domains + */ + +/* + * Structure that describes a device handled by a driver domain + */ +typedef struct libxl__ddomain_device { + libxl__device *dev; + LIBXL_SLIST_ENTRY(struct libxl__ddomain_device) next; +} libxl__ddomain_device; + +/* + * Structure that describes a domain and it's associated devices + */ +typedef struct libxl__ddomain_guest { + uint32_t domid; + int num_vifs, num_vbds, num_qdisks; + LIBXL_SLIST_HEAD(, struct libxl__ddomain_device) devices; + LIBXL_SLIST_ENTRY(struct libxl__ddomain_guest) next; +} libxl__ddomain_guest; + +/* + * Main structure used by a driver domain to keep track of devices + * currently in use + */ +typedef struct { + libxl__ao *ao; + libxl__ev_xswatch watch; + LIBXL_SLIST_HEAD(, struct libxl__ddomain_guest) guests; +} libxl__ddomain; + +static libxl__ddomain_guest *search_for_guest(libxl__ddomain *ddomain, + uint32_t domid) +{ + libxl__ddomain_guest *dguest; + + LIBXL_SLIST_FOREACH(dguest, &ddomain->guests, next) { + if (dguest->domid == domid) + return dguest; + } + return NULL; +} + +static libxl__ddomain_device *search_for_device(libxl__ddomain_guest *dguest, + libxl__device *dev) +{ + libxl__ddomain_device *ddev; + + LIBXL_SLIST_FOREACH(ddev, &dguest->devices, next) { +#define LIBXL_DEVICE_CMP(dev1, dev2, entry) (dev1->entry == dev2->entry) + if (LIBXL_DEVICE_CMP(ddev->dev, dev, backend_devid) && + LIBXL_DEVICE_CMP(ddev->dev, dev, backend_domid) && + LIBXL_DEVICE_CMP(ddev->dev, dev, devid) && + LIBXL_DEVICE_CMP(ddev->dev, dev, domid) && + LIBXL_DEVICE_CMP(ddev->dev, dev, backend_kind) && + LIBXL_DEVICE_CMP(ddev->dev, dev, kind)) + return ddev; +#undef LIBXL_DEVICE_CMP + } + + return NULL; +} + +static void device_complete(libxl__egc *egc, libxl__ao_device *aodev) +{ + STATE_AO_GC(aodev->ao); + + if (aodev->action == LIBXL__DEVICE_ACTION_REMOVE) + free(aodev->dev); + + LOG(DEBUG, "device %s %s %s", + libxl__device_backend_path(gc, aodev->dev), + libxl__device_action_to_string(aodev->action), + aodev->rc ? "failed" : "succeed"); + + libxl__nested_ao_free(aodev->ao); +} + +static void qdisk_spawn_outcome(libxl__egc *egc, libxl__dm_spawn_state *dmss, + int rc) +{ + STATE_AO_GC(dmss->spawn.ao); + + LOG(DEBUG, "qdisk backend spawn for domain %u %s", dmss->guest_domid, + rc ? "failed" : "succeed"); + + libxl__nested_ao_free(dmss->spawn.ao); +} + +/* + * The following comment applies to both add_device and remove_device. + * + * If the return value is greater than 0, it means there's no ao dispatched, + * so the free of the nested ao should be done by the parent when it has + * finished. + */ +static int add_device(libxl__egc *egc, libxl__ao *ao, + libxl__ddomain_guest *dguest, + libxl__ddomain_device *ddev) +{ + AO_GC; + libxl__device *dev = ddev->dev; + libxl__ao_device *aodev; + libxl__dm_spawn_state *dmss; + int rc = 0; + + switch(dev->backend_kind) { + case LIBXL__DEVICE_KIND_VBD: + case LIBXL__DEVICE_KIND_VIF: + if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds++; + if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs++; + + GCNEW(aodev); + libxl__prepare_ao_device(ao, aodev); + aodev->dev = dev; + aodev->action = LIBXL__DEVICE_ACTION_ADD; + aodev->callback = device_complete; + libxl__wait_device_connection(egc, aodev); + + break; + case LIBXL__DEVICE_KIND_QDISK: + if (dguest->num_qdisks == 0) { + GCNEW(dmss); + dmss->guest_domid = dev->domid; + dmss->spawn.ao = ao; + dmss->callback = qdisk_spawn_outcome; + + libxl__spawn_qdisk_backend(egc, dmss); + } + dguest->num_qdisks++; + + break; + default: + rc = 1; + break; + } + + return rc; +} + +static int remove_device(libxl__egc *egc, libxl__ao *ao, + libxl__ddomain_guest *dguest, + libxl__ddomain_device *ddev) +{ + AO_GC; + libxl__device *dev = ddev->dev; + libxl__ao_device *aodev; + int rc = 0; + + switch(ddev->dev->backend_kind) { + case LIBXL__DEVICE_KIND_VBD: + case LIBXL__DEVICE_KIND_VIF: + if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds--; + if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs--; + + GCNEW(aodev); + libxl__prepare_ao_device(ao, aodev); + aodev->dev = dev; + aodev->action = LIBXL__DEVICE_ACTION_REMOVE; + aodev->callback = device_complete; + libxl__initiate_device_remove(egc, aodev); + break; + case LIBXL__DEVICE_KIND_QDISK: + if (--dguest->num_qdisks == 0) { + rc = libxl__destroy_qdisk_backend(gc, dev->domid); + if (rc) + goto out; + } + libxl__device_destroy(gc, dev); + free(dev); + /* Fall through to return > 0, no ao has been dispatched */ + default: + rc = 1; + break; + } + +out: + return rc; +} + +static void backend_watch_callback(libxl__egc *egc, libxl__ev_xswatch *watch, + const char *watch_path, + const char *event_path) +{ + libxl__ddomain *ddomain = CONTAINER_OF(watch, *ddomain, watch); + libxl__ao *nested_ao = libxl__nested_ao_create(ddomain->ao); + STATE_AO_GC(nested_ao); + char *p, *path; + const char *sstate; + int state, rc, num_devs; + libxl__device *dev = NULL; + libxl__ddomain_device *ddev = NULL; + libxl__ddomain_guest *dguest = NULL; + bool free_ao = false; + + /* Check if event_path ends with "state" and truncate it */ + if (strlen(event_path) < strlen("state")) + goto skip; + + path = libxl__strdup(gc, event_path); + p = path + strlen(path) - strlen("state") - 1; + if (*p != '/') + goto skip; + *p = '\0'; + p++; + if (strcmp(p, "state") != 0) + goto skip; + + /* Check if the state is 1 (XenbusStateInitialising) or greater */ + rc = libxl__xs_read_checked(gc, XBT_NULL, event_path, &sstate); + if (rc || !sstate) + goto skip; + state = atoi(sstate); + + dev = libxl__zalloc(NOGC, sizeof(*dev)); + rc = libxl__parse_backend_path(gc, path, dev); + if (rc) + goto skip; + + dguest = search_for_guest(ddomain, dev->domid); + if (dguest == NULL && state == XenbusStateClosed) { + /* + * Spurious state change, device has already been disconnected + * or never attached. + */ + goto skip; + } + if (dguest == NULL) { + /* Create a new guest struct and initialize it */ + dguest = libxl__zalloc(NOGC, sizeof(*dguest)); + dguest->domid = dev->domid; + LIBXL_SLIST_INIT(&dguest->devices); + LIBXL_SLIST_INSERT_HEAD(&ddomain->guests, dguest, next); + LOG(DEBUG, "added domain %u to the list of active guests", + dguest->domid); + } + ddev = search_for_device(dguest, dev); + if (ddev == NULL && state == XenbusStateClosed) { + /* + * Spurious state change, device has already been disconnected + * or never attached. + */ + goto skip; + } else if (ddev == NULL) { + /* + * New device addition, allocate a struct to hold it and add it + * to the list of active devices for a given guest. + */ + ddev = libxl__zalloc(NOGC, sizeof(*ddev)); + ddev->dev = dev; + LIBXL_SLIST_INSERT_HEAD(&dguest->devices, ddev, next); + LOG(DEBUG, "added device %s to the list of active devices", path); + rc = add_device(egc, nested_ao, dguest, ddev); + if (rc > 0) + free_ao = true; + } else if (state == XenbusStateClosed) { + /* + * Removal of an active device, remove it from the list and + * free it's data structures if they are no longer needed. + * + * The free of the associated libxl__device is left to the + * helper remove_device function. + */ + LIBXL_SLIST_REMOVE(&dguest->devices, ddev, libxl__ddomain_device, + next); + LOG(DEBUG, "removed device %s from the list of active devices", path); + rc = remove_device(egc, nested_ao, dguest, ddev); + if (rc > 0) + free_ao = true; + + free(ddev); + /* If this was the last device in the domain, remove it from the list */ + num_devs = dguest->num_vifs + dguest->num_vbds + dguest->num_qdisks; + if (num_devs == 0) { + LIBXL_SLIST_REMOVE(&ddomain->guests, dguest, libxl__ddomain_guest, + next); + LOG(DEBUG, "removed domain %u from the list of active guests", + dguest->domid); + /* Clear any leftovers in libxl/<domid> */ + libxl__xs_rm_checked(gc, XBT_NULL, + GCSPRINTF("libxl/%u", dguest->domid)); + free(dguest); + } + } + + if (free_ao) + libxl__nested_ao_free(nested_ao); + + return; + +skip: + libxl__nested_ao_free(nested_ao); + free(dev); + free(ddev); + free(dguest); + return; +} + +/* Handler of events for device driver domains */ +int libxl_device_events_handler(libxl_ctx *ctx, + const libxl_asyncop_how *ao_how) +{ + AO_CREATE(ctx, 0, ao_how); + int rc; + uint32_t domid; + libxl__ddomain ddomain; + char *be_path; + + ddomain.ao = ao; + LIBXL_SLIST_INIT(&ddomain.guests); + + rc = libxl__get_domid(gc, &domid); + if (rc) { + LOG(ERROR, "unable to get domain id"); + goto out; + } + + rc = libxl__xs_write_checked(gc, XBT_NULL, DISABLE_UDEV_PATH, "1"); + if (rc) { + LOGE(ERROR, "unable to write %s = 1", DISABLE_UDEV_PATH); + goto out; + } + + /* + * We use absolute paths because we want xswatch to also return + * absolute paths that can be parsed by libxl__parse_backend_path. + */ + be_path = GCSPRINTF("/local/domain/%u/backend", domid); + rc = libxl__ev_xswatch_register(gc, &ddomain.watch, backend_watch_callback, + be_path); + +out: + GC_FREE; + return rc ? : AO_INPROGRESS; +} + +/******************************************************************************/ + int libxl_domain_setmaxmem(libxl_ctx *ctx, uint32_t domid, uint32_t max_memkb) { GC_INIT(ctx); diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 18dd420..a9663e4 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -911,6 +911,18 @@ libxl_device_pci *libxl_device_pci_list(libxl_ctx *ctx, uint32_t domid, int *num); /* + * Turns the current process into a backend device service daemon + * for a driver domain. + * + * From a libxl API point of view, this starts a long-running + * operation. That operation consists of "being a driver domain" + * and never completes. + */ +int libxl_device_events_handler(libxl_ctx *ctx, + const libxl_asyncop_how *ao_how) + LIBXL_EXTERNAL_CALLERS_ONLY; + +/* * Functions related to making devices assignable -- that is, bound to * the pciback driver, ready to be given to a guest via * libxl_pci_device_add. diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h index e005c39..c876a33 100644 --- a/tools/libxl/xl.h +++ b/tools/libxl/xl.h @@ -105,6 +105,7 @@ int main_getenforce(int argc, char **argv); int main_setenforce(int argc, char **argv); int main_loadpolicy(int argc, char **argv); int main_remus(int argc, char **argv); +int main_devd(int argc, char **argv); void help(const char *command); diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 2d147d4..341863e 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -7210,6 +7210,30 @@ int main_remus(int argc, char **argv) return -ERROR_FAIL; } +int main_devd(int argc, char **argv) +{ + int ret = 0, opt = 0, daemonize = 1; + + SWITCH_FOREACH_OPT(opt, "F", NULL, "devd", 0) { + case 'F': + daemonize = 0; + break; + } + + if (daemonize) { + ret = do_daemonize("xldevd"); + if (ret) { + ret = (ret == 1) ? 0 : ret; + goto out; + } + } + + libxl_device_events_handler(ctx, 0); + +out: + return ret; +} + /* * Local variables: * mode: C diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c index 326a660..7709206 100644 --- a/tools/libxl/xl_cmdtable.c +++ b/tools/libxl/xl_cmdtable.c @@ -488,6 +488,12 @@ struct cmd_spec cmd_table[] = { " of the domain." }, + { "devd", + &main_devd, 0, 1, + "Daemon that listens for devices and launches backends", + "[options]", + "-F Run in the foreground", + }, }; int cmdtable_len = sizeof(cmd_table)/sizeof(struct cmd_spec); -- 1.7.7.5 (Apple Git-26) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Roger Pau Monné
2013-Nov-18 15:00 UTC
Re: [PATCH v3 00/9] libxl: add driver domain backend daemon
On 18/11/13 15:56, Roger Pau Monne wrote:> This patch series introduces support to launch device backends from > driver domains using libxl, removing the need to setup udev on driver > domains. > > The daemon currently supports vbds, vifs and qdisks as backends. > > Patches from 1 to 9 focus on getting libxl to work on driver domains, > and add several helper functions that will be used to build the > infraestructure needed for libxl to work on domains different than > Dom0. > > The last patch (10) adds a new xl command, "devd", that can be used to > launch a daemon that will listen to changes in the xenstore "backend" > directory for the domain and perform the necessary actions to attach > the devices.Forgot to say the series can also be found in my git repo under branch driver_domains_v3: http://xenbits.xen.org/gitweb/?p=people/royger/xen.git;a=shortlog;h=refs/heads/driver_domains_v3
Ian Jackson
2013-Nov-18 15:20 UTC
Re: [PATCH v3 6/9] libxl: add Qdisk backend launch helper
Roger Pau Monne writes ("[PATCH v3 6/9] libxl: add Qdisk backend launch helper"):> Current Qemu launch functions in libxl require the usage of data > structures only avaialbe on domain creation. All this information is > not need in order to launch a Qemu instance to serve Qdisk backends, > so introduce a new simplified helper that can be used to launch > Qemu/Qdisk, that will be used to launch Qdisk in driver domains....> +static int libxl__create_qemu_logfile(libxl__gc *gc, char *name) > +{...> + logfile_w = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); > + free(logfile); > + > + if (logfile_w < 0) > + LOGE(ERROR, "unable to open Qemu logfile"); > + > + return logfile_w;This function ought to have a comment stating its return type. AFAICT the return type is "the same as syscalls", but we don''t do that in libxl. libxl functions ought to return libxl error codes on error.> @@ -1204,11 +1219,12 @@ void libxl__spawn_local_dm(libxl__egc *egc, libxl__dm_spawn_state *dmss)...> - libxl_create_logfile(ctx, > - libxl__sprintf(gc, "qemu-dm-%s", c_info->name), > - &logfile); > - logfile_w = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); > - free(logfile); > + logfile_w = libxl__create_qemu_logfile(gc, GCSPRINTF("qemu-dm-%s", > + c_info->name)); > + if (logfile_w < 0) { > + rc = logfile_w; > + goto out; > + }And here we assume that it does indeed return a libxl error code. The other changes you''ve made here look good. Thanks, Ian.
Ian Jackson
2013-Nov-18 15:26 UTC
Re: [PATCH v3 6/9] libxl: add Qdisk backend launch helper
Ian Jackson writes ("Re: [PATCH v3 6/9] libxl: add Qdisk backend launch helper"):> And here we assume that it does indeed return a libxl error code. > > The other changes you''ve made here look good.I propose to grant a freeze exception for this series, assuming that the final patch is acked and committed today or tomorrow. Lack of proper support for driver domains is a regression from xm/xend. The likely kind of bugs being introduced here aren''t hard to find races, but simple functionality problems (probably in hotplug script corner cases). Please (anyone) say if you object. Ian.
Roger Pau Monne
2013-Nov-18 15:36 UTC
[PATCH v4 6/9] libxl: add Qdisk backend launch helper
Current Qemu launch functions in libxl require the usage of data structures only avaialbe on domain creation. All this information is not need in order to launch a Qemu instance to serve Qdisk backends, so introduce a new simplified helper that can be used to launch Qemu/Qdisk, that will be used to launch Qdisk in driver domains. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Cc: Ian Jackson <Ian.Jackson@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> Cc: Anthony PERARD <anthony.perard@citrix.com> Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com> --- tools/libxl/libxl_dm.c | 148 +++++++++++++++++++++++++++++++++++++----- tools/libxl/libxl_internal.h | 6 ++ 2 files changed, 138 insertions(+), 16 deletions(-) diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c index b4798b8..292e351 100644 --- a/tools/libxl/libxl_dm.c +++ b/tools/libxl/libxl_dm.c @@ -42,6 +42,23 @@ static const char *qemu_xen_path(libxl__gc *gc) #endif } +static int libxl__create_qemu_logfile(libxl__gc *gc, char *name) +{ + char *logfile; + int logfile_w; + + libxl_create_logfile(CTX, name, &logfile); + logfile_w = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); + free(logfile); + + if (logfile_w < 0) { + LOGE(ERROR, "unable to open Qemu logfile"); + return ERROR_FAIL; + } + + return logfile_w; +} + const char *libxl__domain_device_model(libxl__gc *gc, const libxl_domain_build_info *info) { @@ -1149,7 +1166,7 @@ void libxl__spawn_local_dm(libxl__egc *egc, libxl__dm_spawn_state *dmss) const libxl_domain_create_info *c_info = &guest_config->c_info; const libxl_domain_build_info *b_info = &guest_config->b_info; const libxl_vnc_info *vnc = libxl__dm_vnc(guest_config); - char *path, *logfile; + char *path; int logfile_w, null; int rc; char **args, **arg; @@ -1204,11 +1221,12 @@ void libxl__spawn_local_dm(libxl__egc *egc, libxl__dm_spawn_state *dmss) libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/disable_pf", path), "%d", !libxl_defbool_val(b_info->u.hvm.xen_platform_pci)); - libxl_create_logfile(ctx, - libxl__sprintf(gc, "qemu-dm-%s", c_info->name), - &logfile); - logfile_w = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); - free(logfile); + logfile_w = libxl__create_qemu_logfile(gc, GCSPRINTF("qemu-dm-%s", + c_info->name)); + if (logfile_w < 0) { + rc = logfile_w; + goto out; + } null = open("/dev/null", O_RDONLY); const char *dom_path = libxl__xs_get_dompath(gc, domid); @@ -1268,7 +1286,6 @@ out: static void device_model_confirm(libxl__egc *egc, libxl__spawn_state *spawn, const char *xsdata) { - libxl__dm_spawn_state *dmss = CONTAINER_OF(spawn, *dmss, spawn); STATE_AO_GC(spawn->ao); if (!xsdata) @@ -1320,18 +1337,91 @@ static void device_model_spawn_outcome(libxl__egc *egc, dmss->callback(egc, dmss, rc); } -int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid) +void libxl__spawn_qdisk_backend(libxl__egc *egc, libxl__dm_spawn_state *dmss) { - char *pid; - int ret; + STATE_AO_GC(dmss->spawn.ao); + flexarray_t *dm_args; + char **args; + const char *dm; + int logfile_w, null, rc; + uint32_t domid = dmss->guest_domid; + + /* Always use qemu-xen as device model */ + dm = qemu_xen_path(gc); + + dm_args = flexarray_make(gc, 15, 1); + flexarray_vappend(dm_args, dm, "-xen-domid", + GCSPRINTF("%d", domid), NULL); + flexarray_append(dm_args, "-xen-attach"); + flexarray_vappend(dm_args, "-name", + GCSPRINTF("domain-%u", domid), NULL); + flexarray_append(dm_args, "-nographic"); + flexarray_vappend(dm_args, "-M", "xenpv", NULL); + flexarray_vappend(dm_args, "-monitor", "/dev/null", NULL); + flexarray_vappend(dm_args, "-serial", "/dev/null", NULL); + flexarray_vappend(dm_args, "-parallel", "/dev/null", NULL); + flexarray_append(dm_args, NULL); + args = (char **) flexarray_contents(dm_args); - pid = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "/local/domain/%d/image/device-model-pid", domid)); - if (!pid || !atoi(pid)) { - LOG(ERROR, "could not find device-model's pid for dom %u", domid); - ret = ERROR_FAIL; + logfile_w = libxl__create_qemu_logfile(gc, GCSPRINTF("qdisk-%u", domid)); + if (logfile_w < 0) { + rc = logfile_w; + goto error; + } + null = open("/dev/null", O_RDONLY); + + dmss->guest_config = NULL; + /* + * Clearly specify Qemu not using a saved state, so + * device_model_spawn_outcome doesn't try to unlink it. + */ + dmss->build_state = libxl__zalloc(gc, sizeof(*dmss->build_state)); + dmss->build_state->saved_state = 0; + + dmss->spawn.what = GCSPRINTF("domain %u Qdisk backend", domid); + dmss->spawn.xspath = GCSPRINTF("device-model/%u/state", domid); + dmss->spawn.timeout_ms = LIBXL_DEVICE_MODEL_START_TIMEOUT * 1000; + /* + * We cannot save Qemu pid anywhere in the xenstore guest dir, + * because we will call this from unprivileged driver domains, + * so save it in the current domain libxl private dir. + */ + dmss->spawn.pidpath = GCSPRINTF("libxl/%u/qdisk-backend-pid", domid); + dmss->spawn.midproc_cb = libxl__spawn_record_pid; + dmss->spawn.confirm_cb = device_model_confirm; + dmss->spawn.failure_cb = device_model_startup_failed; + dmss->spawn.detached_cb = device_model_detached; + rc = libxl__spawn_spawn(egc, &dmss->spawn); + if (rc < 0) + goto error; + if (!rc) { /* inner child */ + setsid(); + libxl__exec(gc, null, logfile_w, logfile_w, dm, args, NULL); + } + + return; + +error: + assert(rc); + dmss->callback(egc, dmss, rc); + return; +} + +/* Generic function to signal a Qemu instance to exit */ +static int kill_device_model(libxl__gc *gc, const char *xs_path_pid) +{ + const char *xs_pid; + int ret, pid; + + ret = libxl__xs_read_checked(gc, XBT_NULL, xs_path_pid, &xs_pid); + if (ret || !xs_pid) { + LOG(ERROR, "unable to find device model pid in %s", xs_path_pid); + ret = ret ? : ERROR_FAIL; goto out; } - ret = kill(atoi(pid), SIGHUP); + pid = atoi(xs_pid); + + ret = kill(pid, SIGHUP); if (ret < 0 && errno == ESRCH) { LOG(ERROR, "Device Model already exited"); ret = 0; @@ -1339,7 +1429,7 @@ int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid) LOG(DEBUG, "Device Model signaled"); ret = 0; } else { - LOGE(ERROR, "failed to kill Device Model [%d]", atoi(pid)); + LOGE(ERROR, "failed to kill Device Model [%d]", pid); ret = ERROR_FAIL; goto out; } @@ -1348,6 +1438,32 @@ out: return ret; } +/* Helper to destroy a Qdisk backend */ +int libxl__destroy_qdisk_backend(libxl__gc *gc, uint32_t domid) +{ + char *pid_path; + int rc; + + pid_path = GCSPRINTF("libxl/%u/qdisk-backend-pid", domid); + + rc = kill_device_model(gc, pid_path); + if (rc) + goto out; + + libxl__xs_rm_checked(gc, XBT_NULL, pid_path); + libxl__xs_rm_checked(gc, XBT_NULL, + GCSPRINTF("device-model/%u", domid)); + +out: + return rc; +} + +int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid) +{ + return kill_device_model(gc, + GCSPRINTF("/local/domain/%d/image/device-model-pid", domid)); +} + int libxl__need_xenpv_qemu(libxl__gc *gc, int nr_consoles, libxl__device_console *consoles, int nr_vfbs, libxl_device_vfb *vfbs, diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index e3b9fb4..cff3518 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -2548,6 +2548,12 @@ _hidden void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state*); _hidden char *libxl__stub_dm_name(libxl__gc *gc, const char * guest_name); +/* Qdisk backend launch helpers */ + +_hidden void libxl__spawn_qdisk_backend(libxl__egc *egc, + libxl__dm_spawn_state *dmss); +_hidden int libxl__destroy_qdisk_backend(libxl__gc *gc, uint32_t domid); + /*----- Domain creation -----*/ typedef struct libxl__domain_create_state libxl__domain_create_state; -- 1.7.7.5 (Apple Git-26) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Ian Jackson
2013-Nov-18 15:59 UTC
Re: [PATCH v4 6/9] libxl: add Qdisk backend launch helper
Roger Pau Monne writes ("[PATCH v4 6/9] libxl: add Qdisk backend launch helper"):> Current Qemu launch functions in libxl require the usage of data > structures only avaialbe on domain creation. All this information is > not need in order to launch a Qemu instance to serve Qdisk backends, > so introduce a new simplified helper that can be used to launch > Qemu/Qdisk, that will be used to launch Qdisk in driver domains.Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Ian Jackson
2013-Nov-18 17:24 UTC
Re: [PATCH v3 6/9] libxl: add Qdisk backend launch helper [and 1 more messages]
Ian Jackson writes ("Re: [PATCH v3 6/9] libxl: add Qdisk backend launch helper"):> I propose to grant a freeze exception for this series, assuming that > the final patch is acked and committed today or tomorrow. Lack of > proper support for driver domains is a regression from xm/xend. The > likely kind of bugs being introduced here aren''t hard to find races, > but simple functionality problems (probably in hotplug script corner > cases).I have now committed Roger''s series (including v4 of 6/9) to staging. Ian.
Anthony PERARD
2013-Nov-18 17:44 UTC
Re: [PATCH v3 6/9] libxl: add Qdisk backend launch helper
On Mon, Nov 18, 2013 at 03:56:28PM +0100, Roger Pau Monne wrote:> Current Qemu launch functions in libxl require the usage of data > structures only avaialbe on domain creation. All this information is > not need in order to launch a Qemu instance to serve Qdisk backends, > so introduce a new simplified helper that can be used to launch > Qemu/Qdisk, that will be used to launch Qdisk in driver domains. > > Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> > Cc: Ian Jackson <Ian.Jackson@eu.citrix.com> > Cc: Ian Campbell <ian.campbell@citrix.com> > Cc: Anthony PERARD <anthony.perard@citrix.com> > Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > --- > tools/libxl/libxl_dm.c | 146 +++++++++++++++++++++++++++++++++++++----- > tools/libxl/libxl_internal.h | 6 ++ > 2 files changed, 136 insertions(+), 16 deletions(-) > > diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c > index b4798b8..64123aa 100644 > --- a/tools/libxl/libxl_dm.c > +++ b/tools/libxl/libxl_dm.c > @@ -1320,18 +1335,91 @@ static void device_model_spawn_outcome(libxl__egc *egc, > dmss->callback(egc, dmss, rc); > } > > -int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid) > +void libxl__spawn_qdisk_backend(libxl__egc *egc, libxl__dm_spawn_state *dmss) > { > - char *pid; > - int ret; > + STATE_AO_GC(dmss->spawn.ao); > + flexarray_t *dm_args; > + char **args; > + const char *dm; > + int logfile_w, null, rc; > + uint32_t domid = dmss->guest_domid; > + > + /* Always use qemu-xen as device model */ > + dm = qemu_xen_path(gc); > + > + dm_args = flexarray_make(gc, 15, 1); > + flexarray_vappend(dm_args, dm, "-xen-domid", > + GCSPRINTF("%d", domid), NULL); > + flexarray_append(dm_args, "-xen-attach"); > + flexarray_vappend(dm_args, "-name", > + GCSPRINTF("domain-%u", domid), NULL); > + flexarray_append(dm_args, "-nographic"); > + flexarray_vappend(dm_args, "-M", "xenpv", NULL); > + flexarray_vappend(dm_args, "-monitor", "/dev/null", NULL); > + flexarray_vappend(dm_args, "-serial", "/dev/null", NULL); > + flexarray_vappend(dm_args, "-parallel", "/dev/null", NULL);You might want to look at the -nodefaults option of QEMU instead of using -nographic -monitor -serial -parallel. -- Anthony PERARD
Ian Jackson
2013-Nov-18 17:46 UTC
Re: [PATCH v3 6/9] libxl: add Qdisk backend launch helper
Anthony PERARD writes ("Re: [PATCH v3 6/9] libxl: add Qdisk backend launch helper"):> On Mon, Nov 18, 2013 at 03:56:28PM +0100, Roger Pau Monne wrote: > > Current Qemu launch functions in libxl require the usage of data > > structures only avaialbe on domain creation. All this information is > > not need in order to launch a Qemu instance to serve Qdisk backends, > > so introduce a new simplified helper that can be used to launch > > Qemu/Qdisk, that will be used to launch Qdisk in driver domains....> You might want to look at the -nodefaults option of QEMU instead of > using -nographic -monitor -serial -parallel.Ah. Well, I have just committed this. Roger, do you want to do a followup ? Thanks, Ian.
Roger Pau Monné
2013-Nov-18 18:12 UTC
Re: [PATCH v3 6/9] libxl: add Qdisk backend launch helper
On 18/11/13 18:46, Ian Jackson wrote:> Anthony PERARD writes ("Re: [PATCH v3 6/9] libxl: add Qdisk backend launch helper"): >> On Mon, Nov 18, 2013 at 03:56:28PM +0100, Roger Pau Monne wrote: >>> Current Qemu launch functions in libxl require the usage of data >>> structures only avaialbe on domain creation. All this information is >>> not need in order to launch a Qemu instance to serve Qdisk backends, >>> so introduce a new simplified helper that can be used to launch >>> Qemu/Qdisk, that will be used to launch Qdisk in driver domains. > ... >> You might want to look at the -nodefaults option of QEMU instead of >> using -nographic -monitor -serial -parallel. > > Ah. > > Well, I have just committed this. Roger, do you want to do a followup ?Thanks, yes, I will test the change and send a followup if it''s OK. Roger.