[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 3/5] libxl: call hotplug scripts from libxl for vbd
This is a rather big change, that adds the necessary machinery to perform hotplug script calling from libxl for Linux. This patch launches the necessary scripts to attach and detach PHY and TAP backend types (Qemu doesn't use hotplug scripts). Here's a list of the major changes introduced: * libxl_device_disk_add makes use of the new event library and takes the optional parameter libxl_asyncop_how, to choose how the operation has to be issued (sync or async). * libxl_device_disk_add waits for backend to switch to state 2 (XenbusInitWait) and then launches the hotplug script. * libxl__devices_destroy no longer calls libxl__device_destroy, and instead calls libxl__initiate_device_remove, so we can disconnect the device and execute the necessary hotplug scripts instead of just deleting the backend entries. So libxl__devices_destroy now uses the event library, and so does libxl_domain_destroy. * Since libxl__devices_destroy calls multiple times libxl__initiate_device_remove, this function now returns a different value regarding the actions taken (if an event was added or not). The user has to call libxl__ao_complete after using this function if necessary. * The internal API for hotplug scripts has been added, which consists of one function; libxl__device_hotplug that takes the device and the action to execute. * Linux hotplug scripts are called by setting the necessary env variables to emulate udev rules, so there's no need to change them (although a rework to pass this as parameters insted of env variables would be suitable, so both NetBSD and Linux hotplug scripts take the same parameters). * Added a check in xen-hotplug-common.sh, so scripts are only executed from udev when using xend. xl adds a disable_udev=y to xenstore private directory and with the modification of the udev rules every call from udev gets HOTPLUG_GATE passed, that points to disable_udev. If HOTPLUG_GATE is passed and points to a value, the hotplug script is not executed. I've also modified the python binding for pyxl_domain_destroy, that now take the ao_how parameter, but I'm not really sure if it's done correctly, let's just say that it compiles. Changes since v3: * disable_udev is now stored in /libxl/backend/vbd/<domid>/<devid>/. * Passed NULL as ao_how in Python bindings. Changes since v1: * Replaced the hotplug snippet that prevents execution from udev when necessary, and now we set the env var from udev rules instead of libxl. * Replaced the libxl_device_disk_add "if" with a "switch". * Removed libxl__xs_path_cleanup (replaced with xs_rm). * Fixed several spelling mistakes. Signed-off-by: Roger Pau Monne <roger.pau@xxxxxxxxxx> Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx> --- tools/hotplug/Linux/xen-backend.rules | 6 +- tools/hotplug/Linux/xen-hotplug-common.sh | 6 + tools/libxl/Makefile | 3 +- tools/libxl/libxl.c | 144 ++++++++++++++++++++++----- tools/libxl/libxl.h | 7 +- tools/libxl/libxl_create.c | 4 +- tools/libxl/libxl_device.c | 152 ++++++++++++++++++++++++++--- tools/libxl/libxl_dm.c | 4 +- tools/libxl/libxl_hotplug.c | 67 +++++++++++++ tools/libxl/libxl_internal.h | 46 ++++++++- tools/libxl/libxl_linux.c | 117 ++++++++++++++++++++++ tools/libxl/libxl_pci.c | 5 +- tools/libxl/xl_cmdimpl.c | 14 ++-- tools/python/xen/lowlevel/xl/xl.c | 2 +- 14 files changed, 516 insertions(+), 61 deletions(-) create mode 100644 tools/libxl/libxl_hotplug.c diff --git a/tools/hotplug/Linux/xen-backend.rules b/tools/hotplug/Linux/xen-backend.rules index 19bd0fa..19f3d27 100644 --- a/tools/hotplug/Linux/xen-backend.rules +++ b/tools/hotplug/Linux/xen-backend.rules @@ -1,11 +1,11 @@ -SUBSYSTEM=="xen-backend", KERNEL=="tap*", RUN+="/etc/xen/scripts/blktap $env{ACTION}" -SUBSYSTEM=="xen-backend", KERNEL=="vbd*", RUN+="/etc/xen/scripts/block $env{ACTION}" +SUBSYSTEM=="xen-backend", KERNEL=="tap*", ENV{HOTPLUG_GATE}="/libxl/$env{XENBUS_PATH}/disable_udev", RUN+="/etc/xen/scripts/blktap $env{ACTION}" +SUBSYSTEM=="xen-backend", KERNEL=="vbd*", ENV{HOTPLUG_GATE}="/libxl/$env{XENBUS_PATH}/disable_udev", RUN+="/etc/xen/scripts/block $env{ACTION}" SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm $env{ACTION}" SUBSYSTEM=="xen-backend", KERNEL=="vif2-*", RUN+="/etc/xen/scripts/vif2 $env{ACTION}" SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="online", RUN+="/etc/xen/scripts/vif-setup online type_if=vif" SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="offline", RUN+="/etc/xen/scripts/vif-setup offline type_if=vif" SUBSYSTEM=="xen-backend", KERNEL=="vscsi*", RUN+="/etc/xen/scripts/vscsi $env{ACTION}" -SUBSYSTEM=="xen-backend", ACTION=="remove", RUN+="/etc/xen/scripts/xen-hotplug-cleanup" +SUBSYSTEM=="xen-backend", ACTION=="remove", ENV{HOTPLUG_GATE}="/libxl/$env{XENBUS_PATH}/disable_udev", RUN+="/etc/xen/scripts/xen-hotplug-cleanup" KERNEL=="evtchn", NAME="xen/%k" SUBSYSTEM=="xen", KERNEL=="blktap[0-9]*", NAME="xen/%k", MODE="0600" SUBSYSTEM=="blktap2", KERNEL=="blktap[0-9]*", NAME="xen/blktap-2/%k", MODE="0600" diff --git a/tools/hotplug/Linux/xen-hotplug-common.sh b/tools/hotplug/Linux/xen-hotplug-common.sh index 8f6557d..d2aac3a 100644 --- a/tools/hotplug/Linux/xen-hotplug-common.sh +++ b/tools/hotplug/Linux/xen-hotplug-common.sh @@ -15,6 +15,12 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # +# Hack to prevent the execution of hotplug scripts from udev if the domain +# has been launched from libxl +if [ -n "${HOTPLUG_GATE}" ] && \ + `xenstore-read "$HOTPLUG_GATE" >/dev/null 2>&1`; then + exit 0 +fi dir=$(dirname "$0") . "$dir/hotplugpath.sh" diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile index e5ea867..0ac43bd 100644 --- a/tools/libxl/Makefile +++ b/tools/libxl/Makefile @@ -53,7 +53,8 @@ LIBXL_LIBS += -lyajl LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \ libxl_dom.o libxl_exec.o libxl_xshelp.o libxl_device.o \ libxl_internal.o libxl_utils.o libxl_uuid.o libxl_json.o \ - libxl_qmp.o libxl_event.o libxl_fork.o $(LIBXL_OBJS-y) + libxl_qmp.o libxl_event.o libxl_fork.o libxl_hotplug.o \ + $(LIBXL_OBJS-y) LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl) -include $(XEN_ROOT)/tools/config.h diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index f0372d0..eaa3095 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -1062,13 +1062,15 @@ void libxl_evdisable_disk_eject(libxl_ctx *ctx, libxl_evgen_disk_eject *evg) { GC_FREE; } -int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid) +int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, + const libxl_asyncop_how *ao_how) { - GC_INIT(ctx); + AO_CREATE(ctx, domid, ao_how); char *dom_path; char *vm_path; char *pid; int rc, dm_present; + int rc_ao = 0; rc = libxl_domain_info(ctx, NULL, domid); switch(rc) { @@ -1110,7 +1112,8 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid) libxl__qmp_cleanup(gc, domid); } - if (libxl__devices_destroy(gc, domid) < 0) + rc_ao = libxl__devices_destroy(egc, ao, domid); + if (rc_ao < 0) LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl__devices_destroy failed for %d", domid); @@ -1133,9 +1136,10 @@ int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid) goto out; } rc = 0; + out: - GC_FREE; - return rc; + if (rc_ao) return AO_ABORT(rc_ao); + return AO_INPROGRESS; } int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num, libxl_console_type type) @@ -1313,11 +1317,14 @@ static int libxl__device_from_disk(libxl__gc *gc, uint32_t domid, return 0; } -int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk) +int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, + libxl_device_disk *disk, + const libxl_asyncop_how *ao_how) { - GC_INIT(ctx); + AO_CREATE(ctx, domid, ao_how); flexarray_t *front; flexarray_t *back; + flexarray_t *private; char *dev; libxl__device device; int major, minor, rc; @@ -1330,10 +1337,15 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis rc = ERROR_NOMEM; goto out; } - back = flexarray_make(16, 1); + back = flexarray_make(20, 1); if (!back) { rc = ERROR_NOMEM; - goto out_free; + goto out_free_f; + } + private = flexarray_make(2, 1); + if (!private) { + rc = ERROR_NOMEM; + goto out_free_b; } if (disk->script) { @@ -1361,6 +1373,11 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis flexarray_append(back, "params"); flexarray_append(back, dev); + flexarray_append(back, "script"); + flexarray_append(back, libxl__sprintf(gc, "%s/%s", + libxl_xen_script_dir_path(), + "block")); + assert(device.backend_kind == LIBXL__DEVICE_KIND_VBD); break; case LIBXL_DISK_BACKEND_TAP: @@ -1374,6 +1391,11 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis libxl__device_disk_string_of_format(disk->format), disk->pdev_path)); + flexarray_append(back, "script"); + flexarray_append(back, libxl__sprintf(gc, "%s/%s", + libxl_xen_script_dir_path(), + "blktap")); + /* now create a phy device to export the device to the guest */ goto do_backend_phy; case LIBXL_DISK_BACKEND_QDISK: @@ -1416,18 +1438,38 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis flexarray_append(front, "device-type"); flexarray_append(front, disk->is_cdrom ? "cdrom" : "disk"); + /* compatibility addon to keep udev rules */ + flexarray_append(private, "disable_udev"); + flexarray_append(private, "y"); + libxl__device_generic_add(gc, &device, - libxl__xs_kvs_of_flexarray(gc, back, back->count), - libxl__xs_kvs_of_flexarray(gc, front, front->count)); + libxl__xs_kvs_of_flexarray(gc, back, back->count), + libxl__xs_kvs_of_flexarray(gc, front, front->count), + libxl__xs_kvs_of_flexarray(gc, private, private->count)); + + switch(disk->backend) { + case LIBXL_DISK_BACKEND_PHY: + case LIBXL_DISK_BACKEND_TAP: + rc = libxl__initiate_device_add(egc, ao, &device); + if (rc) goto out_free; + break; + case LIBXL_DISK_BACKEND_QDISK: + default: + libxl__ao_complete(egc, ao, 0); + break; + } rc = 0; out_free: + flexarray_free(private); +out_free_b: flexarray_free(back); +out_free_f: flexarray_free(front); out: - GC_FREE; - return rc; + if (rc) return AO_ABORT(rc); + return AO_INPROGRESS; } int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t domid, @@ -1442,7 +1484,18 @@ int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t domid, if (rc != 0) goto out; rc = libxl__initiate_device_remove(egc, ao, &device); - if (rc) goto out; + switch(rc) { + case 1: + /* event added */ + break; + case 0: + /* no event added */ + libxl__ao_complete(egc, ao, 0); + break; + default: + /* error */ + goto out; + } return AO_INPROGRESS; @@ -1666,11 +1719,11 @@ int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk) ret = 0; libxl_device_disk_remove(ctx, domid, disks + i, 0); - libxl_device_disk_add(ctx, domid, disk); + libxl_device_disk_add(ctx, domid, disk, 0); stubdomid = libxl_get_stubdom_id(ctx, domid); if (stubdomid) { libxl_device_disk_remove(ctx, stubdomid, disks + i, 0); - libxl_device_disk_add(ctx, stubdomid, disk); + libxl_device_disk_add(ctx, stubdomid, disk, 0); } out: for (i = 0; i < num; i++) @@ -1884,8 +1937,9 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic) flexarray_append(front, libxl__sprintf(gc, LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac))); libxl__device_generic_add(gc, &device, - libxl__xs_kvs_of_flexarray(gc, back, back->count), - libxl__xs_kvs_of_flexarray(gc, front, front->count)); + libxl__xs_kvs_of_flexarray(gc, back, back->count), + libxl__xs_kvs_of_flexarray(gc, front, front->count), + NULL); /* FIXME: wait for plug */ rc = 0; @@ -1909,7 +1963,18 @@ int libxl_device_nic_remove(libxl_ctx *ctx, uint32_t domid, if (rc != 0) goto out; rc = libxl__initiate_device_remove(egc, ao, &device); - if (rc) goto out; + switch(rc) { + case 1: + /* event added */ + break; + case 0: + /* no event added */ + libxl__ao_complete(egc, ao, 0); + break; + default: + /* error */ + goto out; + } return AO_INPROGRESS; @@ -2162,8 +2227,9 @@ int libxl__device_console_add(libxl__gc *gc, uint32_t domid, } libxl__device_generic_add(gc, &device, - libxl__xs_kvs_of_flexarray(gc, back, back->count), - libxl__xs_kvs_of_flexarray(gc, front, front->count)); + libxl__xs_kvs_of_flexarray(gc, back, back->count), + libxl__xs_kvs_of_flexarray(gc, front, front->count), + NULL); rc = 0; out_free: flexarray_free(back); @@ -2233,8 +2299,9 @@ int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb) flexarray_append(front, libxl__sprintf(gc, "%d", 1)); libxl__device_generic_add(gc, &device, - libxl__xs_kvs_of_flexarray(gc, back, back->count), - libxl__xs_kvs_of_flexarray(gc, front, front->count)); + libxl__xs_kvs_of_flexarray(gc, back, back->count), + libxl__xs_kvs_of_flexarray(gc, front, front->count), + NULL); rc = 0; out_free: flexarray_free(back); @@ -2256,7 +2323,18 @@ int libxl_device_vkb_remove(libxl_ctx *ctx, uint32_t domid, if (rc != 0) goto out; rc = libxl__initiate_device_remove(egc, ao, &device); - if (rc) goto out; + switch(rc) { + case 1: + /* event added */ + break; + case 0: + /* no event added */ + libxl__ao_complete(egc, ao, 0); + break; + default: + /* error */ + goto out; + } return AO_INPROGRESS; @@ -2366,8 +2444,9 @@ int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb) flexarray_append_pair(front, "state", libxl__sprintf(gc, "%d", 1)); libxl__device_generic_add(gc, &device, - libxl__xs_kvs_of_flexarray(gc, back, back->count), - libxl__xs_kvs_of_flexarray(gc, front, front->count)); + libxl__xs_kvs_of_flexarray(gc, back, back->count), + libxl__xs_kvs_of_flexarray(gc, front, front->count), + NULL); rc = 0; out_free: flexarray_free(front); @@ -2389,7 +2468,18 @@ int libxl_device_vfb_remove(libxl_ctx *ctx, uint32_t domid, if (rc != 0) goto out; rc = libxl__initiate_device_remove(egc, ao, &device); - if (rc) goto out; + switch(rc) { + case 1: + /* event added */ + break; + case 0: + /* no event added */ + libxl__ao_complete(egc, ao, 0); + break; + default: + /* error */ + goto out; + } return AO_INPROGRESS; diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index edbca53..6687e2e 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -472,7 +472,8 @@ int libxl_domain_suspend(libxl_ctx *ctx, libxl_domain_suspend_info *info, int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid); int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid); int libxl_domain_reboot(libxl_ctx *ctx, uint32_t domid); -int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid); +int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, + const libxl_asyncop_how *ao_how); int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, libxl_domain_create_info *info, const char *name_suffix, libxl_uuid new_uuid); /* get max. number of cpus supported by hypervisor */ @@ -601,7 +602,9 @@ void libxl_vminfo_list_free(libxl_vminfo *list, int nr); */ /* Disks */ -int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk); +int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, + libxl_device_disk *disk, + const libxl_asyncop_how *ao_how); int libxl_device_disk_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk, const libxl_asyncop_how *ao_how); diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index 3675afe..de598ad 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -598,7 +598,7 @@ static int do_domain_create(libxl__gc *gc, libxl_domain_config *d_config, store_libxl_entry(gc, domid, &d_config->b_info); for (i = 0; i < d_config->num_disks; i++) { - ret = libxl_device_disk_add(ctx, domid, &d_config->disks[i]); + ret = libxl_device_disk_add(ctx, domid, &d_config->disks[i], 0); if (ret) { LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot add disk %d to domain: %d", i, ret); @@ -721,7 +721,7 @@ static int do_domain_create(libxl__gc *gc, libxl_domain_config *d_config, error_out: if (domid) - libxl_domain_destroy(ctx, domid); + libxl_domain_destroy(ctx, domid, 0); return ret; } diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c index 36d58cd..aa19fab 100644 --- a/tools/libxl/libxl_device.c +++ b/tools/libxl/libxl_device.c @@ -40,6 +40,13 @@ char *libxl__device_backend_path(libxl__gc *gc, libxl__device *device) device->domid, device->devid); } +char *libxl__device_private_path(libxl__gc *gc, libxl__device *device) +{ + return libxl__sprintf(gc, "/libxl/backend/%s/%u/%d", + libxl__device_kind_to_string(device->backend_kind), + device->domid, device->devid); +} + int libxl__parse_backend_path(libxl__gc *gc, const char *path, libxl__device *dev) @@ -59,16 +66,18 @@ int libxl__parse_backend_path(libxl__gc *gc, } int libxl__device_generic_add(libxl__gc *gc, libxl__device *device, - char **bents, char **fents) + char **bents, char **fents, char **private) { libxl_ctx *ctx = libxl__gc_owner(gc); - char *frontend_path, *backend_path; + char *frontend_path, *backend_path, *private_path; xs_transaction_t t; struct xs_permissions frontend_perms[2]; struct xs_permissions backend_perms[2]; + struct xs_permissions private_perms[1]; frontend_path = libxl__device_frontend_path(gc, device); backend_path = libxl__device_backend_path(gc, device); + private_path = libxl__device_private_path(gc, device); frontend_perms[0].id = device->domid; frontend_perms[0].perms = XS_PERM_NONE; @@ -80,6 +89,9 @@ int libxl__device_generic_add(libxl__gc *gc, libxl__device *device, backend_perms[1].id = device->domid; backend_perms[1].perms = XS_PERM_READ; + private_perms[0].id = device->backend_domid; + private_perms[0].perms = XS_PERM_NONE; + retry_transaction: t = xs_transaction_start(ctx->xsh); /* FIXME: read frontend_path and check state before removing stuff */ @@ -100,6 +112,14 @@ retry_transaction: libxl__xs_writev(gc, t, backend_path, bents); } + if (private) { + xs_rm(ctx->xsh, t, private_path); + xs_mkdir(ctx->xsh, t, private_path); + xs_set_permissions(ctx->xsh, t, private_path, private_perms, + ARRAY_SIZE(private_perms)); + libxl__xs_writev(gc, t, private_path, private); + } + if (!xs_transaction_end(ctx->xsh, t, 0)) { if (errno == EAGAIN) goto retry_transaction; @@ -359,22 +379,71 @@ int libxl__device_disk_dev_number(const char *virtpath, int *pdisk, typedef struct { libxl__ao *ao; libxl__ev_devstate ds; + libxl__device *dev; } libxl__ao_device_remove; +typedef struct { + libxl__ao *ao; + libxl__ev_devstate ds; + libxl__device *dev; +} libxl__ao_device_add; + static void device_remove_cleanup(libxl__gc *gc, libxl__ao_device_remove *aorm) { if (!aorm) return; libxl__ev_devstate_cancel(gc, &aorm->ds); } +static void device_add_cleanup(libxl__gc *gc, + libxl__ao_device_add *aorm) { + if (!aorm) return; + libxl__ev_devstate_cancel(gc, &aorm->ds); +} + static void device_remove_callback(libxl__egc *egc, libxl__ev_devstate *ds, int rc) { libxl__ao_device_remove *aorm = CONTAINER_OF(ds, *aorm, ds); libxl__gc *gc = &aorm->ao->gc; + libxl_ctx *ctx = libxl__gc_owner(gc); + + rc = libxl__device_hotplug(gc, aorm->dev, DISCONNECT); + if (rc) + LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable to execute hotplug script for" + " device %"PRIu32, aorm->dev->devid); + libxl__xs_path_cleanup(gc, libxl__device_frontend_path(gc, aorm->dev)); + libxl__xs_path_cleanup(gc, libxl__device_backend_path(gc, aorm->dev)); + libxl__xs_path_cleanup(gc, libxl__device_private_path(gc, aorm->dev)); libxl__ao_complete(egc, aorm->ao, rc); device_remove_cleanup(gc, aorm); } +static void device_add_callback(libxl__egc *egc, libxl__ev_devstate *ds, + int rc) +{ + libxl__ao_device_add *aorm = CONTAINER_OF(ds, *aorm, ds); + libxl__gc *gc = &aorm->ao->gc; + libxl_ctx *ctx = libxl__gc_owner(gc); + + rc = libxl__device_hotplug(gc, aorm->dev, CONNECT); + if (rc) + LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable to execute hotplug script for" + " device %"PRIu32, aorm->dev->devid); + libxl__ao_complete(egc, aorm->ao, rc); + if (aorm) + libxl__ev_devstate_cancel(gc, &aorm->ds); + return; +} + +/* + * Return codes: + * 1 Success and event(s) HAVE BEEN added + * 0 Success and NO events were added + * < 0 Error + * + * Since this function can be called several times, and several events + * can be added to the same context, the user has to call + * libxl__ao_complete when necessary (if no events are added). + */ int libxl__initiate_device_remove(libxl__egc *egc, libxl__ao *ao, libxl__device *dev) { @@ -391,7 +460,6 @@ int libxl__initiate_device_remove(libxl__egc *egc, libxl__ao *ao, goto out_ok; if (atoi(state) != 4) { libxl__device_destroy_tapdisk(gc, be_path); - xs_rm(ctx->xsh, XBT_NULL, be_path); goto out_ok; } @@ -412,6 +480,7 @@ retry_transaction: aorm = libxl__zalloc(gc, sizeof(*aorm)); aorm->ao = ao; + aorm->dev = dev; libxl__ev_devstate_init(&aorm->ds); rc = libxl__ev_devstate_wait(gc, &aorm->ds, device_remove_callback, @@ -419,7 +488,7 @@ retry_transaction: LIBXL_DESTROY_TIMEOUT * 1000); if (rc) goto out_fail; - return 0; + return 1; out_fail: assert(rc); @@ -427,31 +496,77 @@ retry_transaction: return rc; out_ok: - libxl__ao_complete(egc, ao, 0); + rc = libxl__device_hotplug(gc, dev, DISCONNECT); + libxl__xs_path_cleanup(gc, libxl__device_frontend_path(gc, dev)); + libxl__xs_path_cleanup(gc, be_path); + libxl__xs_path_cleanup(gc, libxl__device_private_path(gc, dev)); return 0; } -int libxl__device_destroy(libxl__gc *gc, libxl__device *dev) +int libxl__initiate_device_add(libxl__egc *egc, libxl__ao *ao, + libxl__device *dev) { + AO_GC; libxl_ctx *ctx = libxl__gc_owner(gc); char *be_path = libxl__device_backend_path(gc, dev); + char *state_path = libxl__sprintf(gc, "%s/state", be_path); + char *state = libxl__xs_read(gc, XBT_NULL, state_path); + int rc = 0; + libxl__ao_device_add *aorm = 0; + + if (atoi(state) == XenbusStateInitWait) + goto out_ok; + + aorm = libxl__zalloc(gc, sizeof(*aorm)); + aorm->ao = ao; + aorm->dev = dev; + libxl__ev_devstate_init(&aorm->ds); + + rc = libxl__ev_devstate_wait(gc, &aorm->ds, device_add_callback, + state_path, XenbusStateInitWait, + LIBXL_INIT_TIMEOUT * 1000); + if (rc) { + LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable to initialize device %" + PRIu32, dev->devid); + libxl__ev_devstate_cancel(gc, &aorm->ds); + goto out_fail; + } + + return 0; + +out_fail: + assert(rc); + device_add_cleanup(gc, aorm); + return rc; +out_ok: + rc = libxl__device_hotplug(gc, dev, CONNECT); + libxl__ao_complete(egc, ao, 0); + return rc; +} + +int libxl__device_destroy(libxl__gc *gc, libxl__device *dev) +{ + char *be_path = libxl__device_backend_path(gc, dev); char *fe_path = libxl__device_frontend_path(gc, dev); + char *pr_path = libxl__device_private_path(gc, dev); - xs_rm(ctx->xsh, XBT_NULL, be_path); - xs_rm(ctx->xsh, XBT_NULL, fe_path); + libxl__xs_path_cleanup(gc, be_path); + libxl__xs_path_cleanup(gc, fe_path); + libxl__xs_path_cleanup(gc, pr_path); libxl__device_destroy_tapdisk(gc, be_path); return 0; } -int libxl__devices_destroy(libxl__gc *gc, uint32_t domid) +int libxl__devices_destroy(libxl__egc *egc, libxl__ao *ao, uint32_t domid) { + AO_GC; libxl_ctx *ctx = libxl__gc_owner(gc); char *path; unsigned int num_kinds, num_devs; char **kinds = NULL, **devs = NULL; - int i, j; + int i, j, events = 0, rc; libxl__device dev; libxl__device_kind kind; @@ -481,11 +596,24 @@ int libxl__devices_destroy(libxl__gc *gc, uint32_t domid) dev.domid = domid; dev.kind = kind; dev.devid = atoi(devs[j]); - - libxl__device_destroy(gc, &dev); + rc = libxl__initiate_device_remove(egc, ao, &dev); + switch(rc) { + case 1: + events++; + break; + case 0: + /* no events added */ + break; + default: + LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Could not remove device " + "%s", path); + } } } } + /* Check if any events were added */ + if (!events) + libxl__ao_complete(egc, ao, 0); /* console 0 frontend directory is not under /local/domain/<domid>/device */ path = libxl__sprintf(gc, "/local/domain/%d/console/backend", domid); diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c index 15e24b9..4ce58f6 100644 --- a/tools/libxl/libxl_dm.c +++ b/tools/libxl/libxl_dm.c @@ -789,7 +789,7 @@ retry_transaction: goto retry_transaction; for (i = 0; i < dm_config.num_disks; i++) { - ret = libxl_device_disk_add(ctx, dm_domid, &dm_config.disks[i]); + ret = libxl_device_disk_add(ctx, dm_domid, &dm_config.disks[i], 0); if (ret) goto out_free; } @@ -1047,7 +1047,7 @@ int libxl__destroy_device_model(libxl__gc *gc, uint32_t domid) goto out; } LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device model is a stubdom, domid=%d", stubdomid); - ret = libxl_domain_destroy(ctx, stubdomid); + ret = libxl_domain_destroy(ctx, stubdomid, 0); if (ret) goto out; diff --git a/tools/libxl/libxl_hotplug.c b/tools/libxl/libxl_hotplug.c new file mode 100644 index 0000000..2eace0c --- /dev/null +++ b/tools/libxl/libxl_hotplug.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012 + * Author Roger Pau Monne <roger.pau@xxxxxxxxxx> + * + * 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. with the special + * exception on linking described in file LICENSE. + * + * 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" /* must come before any other headers */ + +#include "libxl_internal.h" + +/* + * Generic hotplug helpers + * + * This helpers are both used by Linux and NetBSD hotplug script + * dispatcher functions. + */ + +static void hotplug_exited(libxl__egc *egc, libxl__ev_child *child, + pid_t pid, int status) +{ + libxl__hotplug_state *hs = CONTAINER_OF(child, *hs, child); + EGC_GC; + + if (status) { + libxl_report_child_exitstatus(CTX, hs->rc ? LIBXL__LOG_ERROR + : LIBXL__LOG_WARNING, + "hotplug child", pid, status); + } +} + +int libxl__hotplug_exec(libxl__gc *gc, char *arg0, char **args, char **env) +{ + int rc = 0; + pid_t pid = -1; + libxl__hotplug_state *hs; + + hs = libxl__zalloc(gc, sizeof(*hs)); + + pid = libxl__ev_child_fork(gc, &hs->child, hotplug_exited); + if (pid == -1) { + rc = ERROR_FAIL; + goto out; + } + if (!pid) { + /* child */ + signal(SIGCHLD, SIG_DFL); + libxl__exec(-1, -1, -1, arg0, args, env); + } +out: + if (libxl__ev_child_inuse(&hs->child)) { + hs->rc = rc; + /* we will get a callback when the child dies */ + return 0; + } + + assert(rc); + return rc; +} diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 020810a..95d5c40 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -70,6 +70,7 @@ #include "_libxl_types_internal_json.h" #define LIBXL_DESTROY_TIMEOUT 10 +#define LIBXL_INIT_TIMEOUT 10 #define LIBXL_DEVICE_MODEL_START_TIMEOUT 10 #define LIBXL_XENCONSOLE_LIMIT 1048576 #define LIBXL_XENCONSOLE_PROTOCOL "vt100" @@ -464,6 +465,37 @@ _hidden char *libxl__xs_libxl_path(libxl__gc *gc, uint32_t domid); */ _hidden int libxl__xs_path_cleanup(libxl__gc *gc, char *path); +/* + * Hotplug handling + * + * Hotplug scripts are launched automatically by libxl at guest creation & + * shutdown/destroy. + */ + +/* Action to pass to hotplug caller functions */ +typedef enum { + CONNECT = 1, + DISCONNECT = 2 +} libxl__hotplug_action; + +typedef struct libxl__hotplug_state libxl__hotplug_state; + +struct libxl__hotplug_state { + /* public, result, caller may only read in callback */ + int rc; + /* private for implementation */ + libxl__ev_child child; +}; + +/* + * libxl__hotplug_exec is an internal function that should not be used + * directly, all hotplug script calls have to implement and use + * libxl__device_hotplug. + */ +_hidden int libxl__device_hotplug(libxl__gc *gc, libxl__device *dev, + libxl__hotplug_action action); +_hidden int libxl__hotplug_exec(libxl__gc *gc, char *arg0, char **args, + char **env); /* * Event generation functions provided by the libxl event core to the @@ -743,13 +775,15 @@ _hidden int libxl__device_console_add(libxl__gc *gc, uint32_t domid, libxl__domain_build_state *state); _hidden int libxl__device_generic_add(libxl__gc *gc, libxl__device *device, - char **bents, char **fents); + char **bents, char **fents, char **private); _hidden char *libxl__device_backend_path(libxl__gc *gc, libxl__device *device); +_hidden char *libxl__device_private_path(libxl__gc *gc, libxl__device *device); _hidden char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device); _hidden int libxl__parse_backend_path(libxl__gc *gc, const char *path, libxl__device *dev); _hidden int libxl__device_destroy(libxl__gc *gc, libxl__device *dev); -_hidden int libxl__devices_destroy(libxl__gc *gc, uint32_t domid); +_hidden int libxl__devices_destroy(libxl__egc *egc, libxl__ao *ao, + uint32_t domid); _hidden int libxl__wait_for_backend(libxl__gc *gc, char *be_path, char *state); /* @@ -772,6 +806,14 @@ _hidden int libxl__wait_for_backend(libxl__gc *gc, char *be_path, char *state); _hidden int libxl__initiate_device_remove(libxl__egc*, libxl__ao*, libxl__device *dev); +/* Arranges that dev will be added to the guest, and the + * hotplug scripts will be executed (if necessary). When + * this is done, the ao will be completed. An error + * return from libxl__initiate_device_add means that the ao + * will _not_ be completed and the caller must do so. */ +_hidden int libxl__initiate_device_add(libxl__egc*, libxl__ao*, + libxl__device *dev); + /* * libxl__ev_devstate - waits a given time for a device to * reach a given state. Follows the libxl_ev_* conventions. diff --git a/tools/libxl/libxl_linux.c b/tools/libxl/libxl_linux.c index 925248b..7c107dc 100644 --- a/tools/libxl/libxl_linux.c +++ b/tools/libxl/libxl_linux.c @@ -25,3 +25,120 @@ int libxl__try_phy_backend(mode_t st_mode) return 1; } + +/* Hotplug scripts helpers */ +static char **get_hotplug_env(libxl__gc *gc, libxl__device *dev) +{ + libxl_ctx *ctx = libxl__gc_owner(gc); + char *be_path = libxl__device_backend_path(gc, dev); + char *script; + flexarray_t *f_env; + char **env; + int nr = 0; + + script = libxl__xs_read(gc, XBT_NULL, + libxl__sprintf(gc, "%s/%s", be_path, "script")); + if (!script) { + LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable to read script from %s", + be_path); + return NULL; + } + + f_env = flexarray_make(9, 1); + if (!f_env) { + LIBXL__LOG(ctx, LIBXL__LOG_ERROR, + "unable to create environment array"); + return NULL; + } + + flexarray_set(f_env, nr++, "script"); + flexarray_set(f_env, nr++, script); + flexarray_set(f_env, nr++, "XENBUS_TYPE"); + flexarray_set(f_env, nr++, (char *) + libxl__device_kind_to_string(dev->backend_kind)); + flexarray_set(f_env, nr++, "XENBUS_PATH"); + flexarray_set(f_env, nr++, + libxl__sprintf(gc, "backend/%s/%u/%d", + libxl__device_kind_to_string(dev->backend_kind), + dev->domid, dev->devid)); + flexarray_set(f_env, nr++, "XENBUS_BASE_PATH"); + flexarray_set(f_env, nr++, "backend"); + + flexarray_set(f_env, nr++, NULL); + + env = (char **) flexarray_contents(f_env); + + return env; +} + +/* Hotplug scripts caller functions */ + +static int libxl__hotplug_disk(libxl__gc *gc, libxl__device *dev, + libxl__hotplug_action action) +{ + libxl_ctx *ctx = libxl__gc_owner(gc); + char *be_path = libxl__device_backend_path(gc, dev); + char *what, *script; + char **args, **env; + int nr = 0, rc = 0; + flexarray_t *f_args; + + script = libxl__xs_read(gc, XBT_NULL, + libxl__sprintf(gc, "%s/%s", be_path, "script")); + if (!script) { + LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable to read script from %s", + be_path); + return -1; + } + + env = get_hotplug_env(gc, dev); + if (!env) + return -1; + + f_args = flexarray_make(3, 1); + if (!f_args) { + LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable to create arguments array"); + return -1; + } + + flexarray_set(f_args, nr++, script); + flexarray_set(f_args, nr++, action == CONNECT ? "add" : "remove"); + flexarray_set(f_args, nr++, NULL); + + args = (char **) flexarray_contents(f_args); + what = libxl__sprintf(gc, "%s %s", args[0], + action == CONNECT ? "connect" : "disconnect"); + LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, + "Calling hotplug script: %s %s", + args[0], args[1]); + rc = libxl__hotplug_exec(gc, args[0], args, env); + if (rc) { + LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unable execute hotplug scripts for " + "device %"PRIu32, dev->devid); + goto out_free; + } + + rc = 0; + +out_free: + free(env); + free(args); + return rc; +} + +int libxl__device_hotplug(libxl__gc *gc, libxl__device *dev, + libxl__hotplug_action action) +{ + int rc = 0; + + switch (dev->backend_kind) { + case LIBXL__DEVICE_KIND_VBD: + rc = libxl__hotplug_disk(gc, dev, action); + break; + default: + rc = 0; + break; + } + + return rc; +} diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c index e8b8839..fd79d1d 100644 --- a/tools/libxl/libxl_pci.c +++ b/tools/libxl/libxl_pci.c @@ -103,8 +103,9 @@ int libxl__create_pci_backend(libxl__gc *gc, uint32_t domid, flexarray_append_pair(front, "state", libxl__sprintf(gc, "%d", 1)); libxl__device_generic_add(gc, &device, - libxl__xs_kvs_of_flexarray(gc, back, back->count), - libxl__xs_kvs_of_flexarray(gc, front, front->count)); + libxl__xs_kvs_of_flexarray(gc, back, back->count), + libxl__xs_kvs_of_flexarray(gc, front, front->count), + NULL); out: if (back) diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index c9e9943..0bc3ac2 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -1306,7 +1306,7 @@ static int handle_domain_death(libxl_ctx *ctx, uint32_t domid, /* fall-through */ case LIBXL_ACTION_ON_SHUTDOWN_DESTROY: LOG("Domain %d needs to be cleaned up: destroying the domain", domid); - libxl_domain_destroy(ctx, domid); + libxl_domain_destroy(ctx, domid, 0); break; case LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY: @@ -1867,7 +1867,7 @@ start: error_out: release_lock(); if (libxl_domid_valid_guest(domid)) - libxl_domain_destroy(ctx, domid); + libxl_domain_destroy(ctx, domid, 0); out: if (logfile != 2) @@ -2354,7 +2354,7 @@ static void destroy_domain(const char *p) fprintf(stderr, "Cannot destroy privileged domain 0.\n\n"); exit(-1); } - rc = libxl_domain_destroy(ctx, domid); + rc = libxl_domain_destroy(ctx, domid, 0); if (rc) { fprintf(stderr,"destroy failed (rc=%d)\n",rc); exit(-1); } } @@ -2628,7 +2628,7 @@ static int save_domain(const char *p, const char *filename, int checkpoint, if (checkpoint) libxl_domain_unpause(ctx, domid); else - libxl_domain_destroy(ctx, domid); + libxl_domain_destroy(ctx, domid, 0); exit(0); } @@ -2861,7 +2861,7 @@ static void migrate_domain(const char *domain_spec, const char *rune, } fprintf(stderr, "migration sender: Target reports successful startup.\n"); - libxl_domain_destroy(ctx, domid); /* bang! */ + libxl_domain_destroy(ctx, domid, 0); /* bang! */ fprintf(stderr, "Migration successful.\n"); exit(0); @@ -2979,7 +2979,7 @@ static void migrate_receive(int debug, int daemonize, int monitor) if (rc) { fprintf(stderr, "migration target: Failure, destroying our copy.\n"); - rc2 = libxl_domain_destroy(ctx, domid); + rc2 = libxl_domain_destroy(ctx, domid, 0); if (rc2) { fprintf(stderr, "migration target: Failed to destroy our copy" " (code %d).\n", rc2); @@ -5026,7 +5026,7 @@ int main_blockattach(int argc, char **argv) return 0; } - if (libxl_device_disk_add(ctx, fe_domid, &disk)) { + if (libxl_device_disk_add(ctx, fe_domid, &disk, 0)) { fprintf(stderr, "libxl_device_disk_add failed.\n"); } return 0; diff --git a/tools/python/xen/lowlevel/xl/xl.c b/tools/python/xen/lowlevel/xl/xl.c index c4f7c52..ce7a2b2 100644 --- a/tools/python/xen/lowlevel/xl/xl.c +++ b/tools/python/xen/lowlevel/xl/xl.c @@ -447,7 +447,7 @@ static PyObject *pyxl_domain_destroy(XlObject *self, PyObject *args) int domid; if ( !PyArg_ParseTuple(args, "i", &domid) ) return NULL; - if ( libxl_domain_destroy(self->ctx, domid) ) { + if ( libxl_domain_destroy(self->ctx, domid, NULL) ) { PyErr_SetString(xl_error_obj, "cannot destroy domain"); return NULL; } -- 1.7.7.5 (Apple Git-26) _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |