[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v1 06/12] libxl: add support for different hotplug interfaces
Add a new variable to libxl_device_disk "hotplug_version", that will be automatically set to the detected hotplug script interface version. This patch adds the basic support to handle this new scripts, by adding the prepare/unprepare private libxl functions, and modifying the current domain creation/destruction to call this functions at the appropriate spots. The hotplug interface detection is done in the _prepare call. This patch also adds some helpers, that will be used here and in later patches. Signed-off-by: Roger Pau Monnà <roger.pau@xxxxxxxxxx> Cc: Ian Campbell <ian.campbell@xxxxxxxxxx> --- tools/libxl/libxl.c | 171 +++++++++++++++++++++++++++++++++++++++++- tools/libxl/libxl_create.c | 62 +++++++++++++++- tools/libxl/libxl_device.c | 127 ++++++++++++++++++++++++++----- tools/libxl/libxl_internal.h | 43 +++++++++++ tools/libxl/libxl_types.idl | 1 + 5 files changed, 381 insertions(+), 23 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index a67c4dc..9061fdf 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -2011,6 +2011,146 @@ int libxl__device_from_disk(libxl__gc *gc, uint32_t domid, return 0; } +/* Callbacks for libxl__device_disk_prepare */ + +static void device_disk_prepare_cb(libxl__egc *, libxl__ao_device *); + +void libxl__device_disk_prepare(libxl__egc *egc, uint32_t domid, + libxl_device_disk *disk, + libxl__ao_device *prepare_aodev) +{ + STATE_AO_GC(prepare_aodev->ao); + char *hotplug_path; + char *script_path; + int rc; + xs_transaction_t t = XBT_NULL; + libxl__disk_prepare *dp; + libxl__ao_device *aodev; + + if (!disk->script) { + /* If script is not set assume v1 */ + disk->hotplug_version = 1; + prepare_aodev->callback(egc, prepare_aodev); + return; + } + + GCNEW(dp); + dp->disk = disk; + /* Save original aodev, since we will call it once hotplug + * script detection has finished + */ + dp->aodev = prepare_aodev; + aodev = &dp->version_aodev; + libxl__prepare_ao_device(ao, aodev); + + GCNEW(aodev->dev); + rc = libxl__device_from_disk(gc, domid, disk, aodev->dev); + if (rc != 0) { + LOG(ERROR, "Invalid or unsupported virtual disk identifier %s", + disk->vdev); + goto error; + } + + script_path = libxl__abs_path(gc, disk->script, + libxl__xen_script_dir_path()); + + hotplug_path = libxl__device_xs_hotplug_path(gc, aodev->dev); + for (;;) { + rc = libxl__xs_transaction_start(gc, &t); + if (rc) goto error; + + rc = libxl__xs_write_checked(gc, t, + GCSPRINTF("%s/params", hotplug_path), + disk->pdev_path); + if (rc) + goto error; + + rc = libxl__xs_write_checked(gc, t, + GCSPRINTF("%s/script", hotplug_path), + script_path); + if (rc) + goto error; + + rc = libxl__xs_transaction_commit(gc, &t); + if (!rc) break; + if (rc < 0) goto error; + } + + aodev->callback = device_disk_prepare_cb; + aodev->action = LIBXL__DEVICE_ACTION_VERSION; + aodev->disk = disk; + aodev->hotplug.version = 2; + libxl__device_hotplug(egc, aodev); + return; + +error: + assert(rc); + libxl__xs_transaction_abort(gc, &t); + aodev->rc = rc; + aodev->callback(egc, aodev); + return; +} + +static void device_disk_prepare_cb(libxl__egc *egc, + libxl__ao_device *version_aodev) +{ + STATE_AO_GC(version_aodev->ao); + libxl__disk_prepare *dp = CONTAINER_OF(version_aodev, *dp, version_aodev); + libxl__ao_device *aodev = dp->aodev; + + if (dp->disk->hotplug_version == 1) { + aodev->callback(egc, aodev); + return; + } + + aodev->action = LIBXL__DEVICE_ACTION_PREPARE; + aodev->hotplug.version = dp->disk->hotplug_version; + aodev->dev = version_aodev->dev; + libxl__device_hotplug(egc, aodev); + return; +} + +void libxl__device_disk_unprepare(libxl__egc *egc, uint32_t domid, + libxl_device_disk *disk, + libxl__ao_device *aodev) +{ + STATE_AO_GC(aodev->ao); + char *hotplug_path; + int rc; + + if (disk->hotplug_version == 1) { + aodev->callback(egc, aodev); + return; + } + + GCNEW(aodev->dev); + rc = libxl__device_from_disk(gc, domid, disk, aodev->dev); + if (rc != 0) { + LOG(ERROR, "Invalid or unsupported virtual disk identifier %s", + disk->vdev); + goto error; + } + + hotplug_path = libxl__device_xs_hotplug_path(gc, aodev->dev); + if (!libxl__xs_read(gc, XBT_NULL, hotplug_path)) { + LOG(DEBUG, "unable to unprepare device because %s doesn't exist", + hotplug_path); + aodev->callback(egc, aodev); + return; + } + + aodev->action = LIBXL__DEVICE_ACTION_UNPREPARE; + aodev->hotplug.version = disk->hotplug_version; + libxl__device_hotplug(egc, aodev); + return; + +error: + assert(rc); + aodev->rc = rc; + aodev->callback(egc, aodev); + return; +} + /* Specific function called directly only by local disk attach, * all other users should instead use the regular * libxl__device_disk_add wrapper @@ -2070,8 +2210,15 @@ static void device_disk_add(libxl__egc *egc, uint32_t domid, dev = disk->pdev_path; do_backend_phy: - flexarray_append(back, "params"); - flexarray_append(back, dev); + if (disk->hotplug_version == 1) { + /* + * If the new hotplug version is used params is + * stored under a private path, since it can contain + * data that the guest should not see. + */ + flexarray_append(back, "params"); + flexarray_append(back, dev); + } script = libxl__abs_path(gc, disk->script?: "block", libxl__xen_script_dir_path()); @@ -2164,6 +2311,8 @@ static void device_disk_add(libxl__egc *egc, uint32_t domid, aodev->dev = device; aodev->action = LIBXL__DEVICE_ACTION_ADD; + aodev->hotplug.version = disk->hotplug_version; + aodev->disk = disk; libxl__wait_device_connection(egc, aodev); rc = 0; @@ -2257,6 +2406,7 @@ int libxl_vdev_to_device_disk(libxl_ctx *ctx, uint32_t domid, GC_INIT(ctx); char *dompath, *path; int devid = libxl__device_disk_dev_number(vdev, NULL, NULL); + libxl__device dev; int rc = ERROR_FAIL; if (devid < 0) @@ -2275,6 +2425,23 @@ int libxl_vdev_to_device_disk(libxl_ctx *ctx, uint32_t domid, goto out; rc = libxl__device_disk_from_xs_be(gc, path, disk); + if (rc) { + LOG(ERROR, "unable to parse disk device from path %s", path); + goto out; + } + + /* Check if the device is using the new hotplug interface */ + rc = libxl__device_from_disk(gc, domid, disk, &dev); + if (rc) { + LOG(ERROR, "invalid or unsupported virtual disk identifier %s", + disk->vdev); + goto out; + } + disk->hotplug_version = 1; + path = libxl__device_xs_hotplug_path(gc, &dev); + if (libxl__xs_read(gc, XBT_NULL, path)) + disk->hotplug_version = 2; + out: GC_FREE; return rc; diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index a8dfe61..aadec00 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -554,6 +554,10 @@ static int store_libxl_entry(libxl__gc *gc, uint32_t domid, */ /* Event callbacks, in this order: */ + +static void domcreate_launch_bootloader(libxl__egc *egc, + libxl__multidev *multidev, + int ret); static void domcreate_devmodel_started(libxl__egc *egc, libxl__dm_spawn_state *dmss, int rc); @@ -590,6 +594,12 @@ static void domcreate_destruction_cb(libxl__egc *egc, libxl__domain_destroy_state *dds, int rc); +/* If creation is not successful, this callback will be executed + * when devices have been unprepared */ +static void domcreate_unprepare_cb(libxl__egc *egc, + libxl__multidev *multidev, + int ret); + static void initiate_domain_create(libxl__egc *egc, libxl__domain_create_state *dcs) { @@ -600,7 +610,6 @@ static void initiate_domain_create(libxl__egc *egc, /* convenience aliases */ libxl_domain_config *const d_config = dcs->guest_config; - const int restore_fd = dcs->restore_fd; memset(&dcs->build_state, 0, sizeof(dcs->build_state)); domid = 0; @@ -633,6 +642,33 @@ static void initiate_domain_create(libxl__egc *egc, if (ret) goto error_out; } + libxl__multidev_begin(ao, &dcs->multidev); + dcs->multidev.callback = domcreate_launch_bootloader; + libxl__prepare_disks(egc, ao, domid, d_config, &dcs->multidev); + libxl__multidev_prepared(egc, &dcs->multidev, 0); + return; + +error_out: + assert(ret); + domcreate_complete(egc, dcs, ret); +} + +static void domcreate_launch_bootloader(libxl__egc *egc, + libxl__multidev *multidev, + int ret) +{ + libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev); + STATE_AO_GC(dcs->ao); + + /* convenience aliases */ + const int restore_fd = dcs->restore_fd; + libxl_domain_config *const d_config = dcs->guest_config; + + if (ret) { + LOG(ERROR, "unable to prepare devices"); + goto error_out; + } + dcs->bl.ao = ao; libxl_device_disk *bootdisk = d_config->num_disks > 0 ? &d_config->disks[0] : NULL; @@ -1171,11 +1207,35 @@ static void domcreate_destruction_cb(libxl__egc *egc, { STATE_AO_GC(dds->ao); libxl__domain_create_state *dcs = CONTAINER_OF(dds, *dcs, dds); + uint32_t domid = dcs->guest_domid; + libxl_domain_config *const d_config = dcs->guest_config; if (rc) LOG(ERROR, "unable to destroy domain %u following failed creation", dds->domid); + /* + * We might have devices that have been prepared, but with no + * frontend xenstore entries, so domain destruction fails to + * find them, that is why we have to unprepare them manually. + */ + libxl__multidev_begin(ao, &dcs->multidev); + dcs->multidev.callback = domcreate_unprepare_cb; + libxl__unprepare_disks(egc, ao, domid, d_config, &dcs->multidev); + libxl__multidev_prepared(egc, &dcs->multidev, 0); + return; +} + +static void domcreate_unprepare_cb(libxl__egc *egc, + libxl__multidev *multidev, + int ret) +{ + libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev); + STATE_AO_GC(dcs->ao); + + if (ret) + LOG(ERROR, "unable to unprepare devices"); + dcs->callback(egc, dcs, ERROR_FAIL, dcs->guest_domid); } diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c index 904853a..df4ea11 100644 --- a/tools/libxl/libxl_device.c +++ b/tools/libxl/libxl_device.c @@ -498,18 +498,21 @@ void libxl__multidev_prepared(libxl__egc *egc, /******************************************************************************/ -/* Macro for defining the functions that will add a bunch of disks when +/* Macro for defining the functions that will operate a bunch of devices when * inside an async op with multidev. * This macro is added to prevent repetition of code. * * The following functions are defined: + * libxl__prepare_disks + * libxl__unprepare_disks * libxl__add_disks * libxl__add_nics * libxl__add_vtpms */ -#define DEFINE_DEVICES_ADD(type) \ - void libxl__add_##type##s(libxl__egc *egc, libxl__ao *ao, uint32_t domid, \ +#define DEFINE_DEVICES_FUNC(type, op) \ + void libxl__##op##_##type##s(libxl__egc *egc, libxl__ao *ao, \ + uint32_t domid, \ libxl_domain_config *d_config, \ libxl__multidev *multidev) \ { \ @@ -517,16 +520,19 @@ void libxl__multidev_prepared(libxl__egc *egc, int i; \ for (i = 0; i < d_config->num_##type##s; i++) { \ libxl__ao_device *aodev = libxl__multidev_prepare(multidev); \ - libxl__device_##type##_add(egc, domid, &d_config->type##s[i], \ + libxl__device_##type##_##op(egc, domid, &d_config->type##s[i], \ aodev); \ } \ } -DEFINE_DEVICES_ADD(disk) -DEFINE_DEVICES_ADD(nic) -DEFINE_DEVICES_ADD(vtpm) +DEFINE_DEVICES_FUNC(disk, add) +DEFINE_DEVICES_FUNC(nic, add) +DEFINE_DEVICES_FUNC(vtpm, add) -#undef DEFINE_DEVICES_ADD +DEFINE_DEVICES_FUNC(disk, prepare) +DEFINE_DEVICES_FUNC(disk, unprepare) + +#undef DEFINE_DEVICES_FUNC /******************************************************************************/ @@ -534,6 +540,7 @@ int libxl__device_destroy(libxl__gc *gc, libxl__device *dev) { const char *be_path = libxl__device_backend_path(gc, dev); const char *fe_path = libxl__device_frontend_path(gc, dev); + const char *hotplug_path = libxl__device_xs_hotplug_path(gc, dev); const char *tapdisk_path = GCSPRINTF("%s/%s", be_path, "tapdisk-params"); const char *tapdisk_params; xs_transaction_t t = 0; @@ -549,6 +556,7 @@ int libxl__device_destroy(libxl__gc *gc, libxl__device *dev) libxl__xs_path_cleanup(gc, t, fe_path); libxl__xs_path_cleanup(gc, t, be_path); + libxl__xs_path_cleanup(gc, t, hotplug_path); rc = libxl__xs_transaction_commit(gc, &t); if (!rc) break; @@ -621,6 +629,14 @@ void libxl__devices_destroy(libxl__egc *egc, libxl__devices_remove_state *drs) continue; } aodev = libxl__multidev_prepare(multidev); + /* + * Check if the device has hotplug entries in xenstore, + * which would mean it's using the new hotplug calling + * convention. + */ + path = libxl__device_xs_hotplug_path(gc, dev); + if (libxl__xs_read(gc, XBT_NULL, path)) + aodev->hotplug.version = 2; aodev->action = LIBXL__DEVICE_ACTION_REMOVE; aodev->dev = dev; aodev->force = drs->force; @@ -673,8 +689,6 @@ static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds, static void device_backend_cleanup(libxl__gc *gc, libxl__ao_device *aodev); -static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev); - static void device_hotplug_timeout_cb(libxl__egc *egc, libxl__ev_time *ev, const struct timeval *requested_abs); @@ -709,7 +723,7 @@ void libxl__wait_device_connection(libxl__egc *egc, libxl__ao_device *aodev) * If Qemu is running, it will set the state of the device to * 4 directly, without waiting in state 2 for any hotplug execution. */ - device_hotplug(egc, aodev); + libxl__device_hotplug(egc, aodev); return; } @@ -841,7 +855,7 @@ static void device_qemu_timeout(libxl__egc *egc, libxl__ev_time *ev, rc = libxl__xs_write_checked(gc, XBT_NULL, state_path, "6"); if (rc) goto out; - device_hotplug(egc, aodev); + libxl__device_hotplug(egc, aodev); return; out: @@ -871,7 +885,7 @@ static void device_backend_callback(libxl__egc *egc, libxl__ev_devstate *ds, goto out; } - device_hotplug(egc, aodev); + libxl__device_hotplug(egc, aodev); return; out: @@ -886,7 +900,7 @@ static void device_backend_cleanup(libxl__gc *gc, libxl__ao_device *aodev) libxl__ev_devstate_cancel(gc, &aodev->backend_ds); } -static void device_hotplug(libxl__egc *egc, libxl__ao_device *aodev) +void libxl__device_hotplug(libxl__egc *egc, libxl__ao_device *aodev) { STATE_AO_GC(aodev->ao); char *be_path = libxl__device_backend_path(gc, aodev->dev); @@ -994,10 +1008,13 @@ static void device_hotplug_child_death_cb(libxl__egc *egc, if (hotplug_error) LOG(ERROR, "script: %s", hotplug_error); aodev->rc = ERROR_FAIL; - if (aodev->action == LIBXL__DEVICE_ACTION_ADD) + if (aodev->action == LIBXL__DEVICE_ACTION_ADD || + aodev->action == LIBXL__DEVICE_ACTION_PREPARE || + aodev->action == LIBXL__DEVICE_ACTION_LOCALATTACH) /* - * Only fail on device connection, on disconnection - * ignore error, and continue with the remove process + * Only fail on device connection, prepare or localattach, + * on other cases ignore error, and continue with the remove + * process. */ goto error; } @@ -1007,7 +1024,7 @@ static void device_hotplug_child_death_cb(libxl__egc *egc, * device_hotplug_done breaking the loop. */ aodev->hotplug.num_exec++; - device_hotplug(egc, aodev); + libxl__device_hotplug(egc, aodev); return; @@ -1019,17 +1036,87 @@ error: static void device_hotplug_done(libxl__egc *egc, libxl__ao_device *aodev) { STATE_AO_GC(aodev->ao); + char *hotplug_path; + const char *pdev, *hotplug_version; int rc; device_hotplug_clean(gc, aodev); - /* Clean xenstore if it's a disconnection */ - if (aodev->action == LIBXL__DEVICE_ACTION_REMOVE) { + switch (aodev->action) { + case LIBXL__DEVICE_ACTION_REMOVE: + switch (aodev->hotplug.version) { + case 1: + /* Clean xenstore if it's a disconnection */ + rc = libxl__device_destroy(gc, aodev->dev); + if (!aodev->rc) + aodev->rc = rc; + break; + case 2: + /* + * Chain unprepare hotplug execution + * after disconnection of device. + */ + aodev->hotplug.num_exec = 0; + aodev->action = LIBXL__DEVICE_ACTION_UNPREPARE; + libxl__device_hotplug(egc, aodev); + return; + default: + LOG(ERROR, "unknown hotplug script version (%d)", + aodev->hotplug.version); + if (!aodev->rc) + aodev->rc = ERROR_FAIL; + break; + } + break; + case LIBXL__DEVICE_ACTION_UNPREPARE: + /* Clean hotplug xenstore path */ rc = libxl__device_destroy(gc, aodev->dev); if (!aodev->rc) aodev->rc = rc; + break; + case LIBXL__DEVICE_ACTION_ADD: + if (aodev->hotplug.version == 1) + goto out; + /* + * Update pdev_path in libxl_device_disk to point to the block + * device + */ + hotplug_path = libxl__device_xs_hotplug_path(gc, aodev->dev); + rc = libxl__xs_read_checked(gc, XBT_NULL, + GCSPRINTF("%s/pdev", hotplug_path), + &pdev); + if (rc || !pdev) { + LOG(ERROR, "unable to get physical disk from %s", + GCSPRINTF("%s/pdev", hotplug_path)); + aodev->rc = rc ? rc : ERROR_FAIL; + goto out; + } + + free(aodev->disk->pdev_path); + aodev->disk->pdev_path = libxl__strdup(NOGC, pdev); + break; + case LIBXL__DEVICE_ACTION_VERSION: + /* Fetch hotplug version output */ + hotplug_path = libxl__device_xs_hotplug_path(gc, aodev->dev); + rc = libxl__xs_read_checked(gc, XBT_NULL, + GCSPRINTF("%s/version", hotplug_path), + &hotplug_version); + if (rc) { + LOG(ERROR, "unable to get hotplug_version from %s", + GCSPRINTF("%s/version", hotplug_path)); + aodev->rc = rc; + goto out; + } + if (!hotplug_version) + aodev->disk->hotplug_version = 1; + else + aodev->disk->hotplug_version = atoi(hotplug_version); + break; + default: + break; } +out: aodev->callback(egc, aodev); return; } diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index e819bbd..67fb95e 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -2012,6 +2012,12 @@ struct libxl__multidev { _hidden void libxl__device_disk_add(libxl__egc *egc, uint32_t domid, libxl_device_disk *disk, libxl__ao_device *aodev); +_hidden void libxl__device_disk_prepare(libxl__egc *egc, uint32_t domid, + libxl_device_disk *disk, + libxl__ao_device *aodev); +_hidden void libxl__device_disk_unprepare(libxl__egc *egc, uint32_t domid, + libxl_device_disk *disk, + libxl__ao_device *aodev); /* AO operation to connect a nic device */ _hidden void libxl__device_nic_add(libxl__egc *egc, uint32_t domid, @@ -2088,6 +2094,28 @@ _hidden int libxl__get_hotplug_script_info(libxl__gc *gc, libxl__device *dev, libxl__device_action action, libxl__hotplug *hotplug); +/* + * libxl__device_hotplug runs the hotplug script associated + * with the device passed in aodev->dev. + * + * The libxl__ao_device passed to this function should be + * prepared using libxl__prepare_ao_device prior to calling + * this function. + * + * Once finished, aodev->callback will be executed. + */ +_hidden void libxl__device_hotplug(libxl__egc *egc, + libxl__ao_device *aodev); + +/* Internal structure to hold device_disk_prepare specific information */ +typedef struct libxl__disk_prepare libxl__disk_prepare; +struct libxl__disk_prepare { + libxl__ao_device version_aodev; + libxl__ao_device *aodev; + libxl_device_disk *disk; + libxl__device_callback *callback; +}; + /*----- local disk attach: attach a disk locally to run the bootloader -----*/ typedef struct libxl__disk_local_state libxl__disk_local_state; @@ -2461,6 +2489,21 @@ _hidden void libxl__add_disks(libxl__egc *egc, libxl__ao *ao, uint32_t domid, libxl_domain_config *d_config, libxl__multidev *multidev); +_hidden void libxl__prepare_disks(libxl__egc *egc, libxl__ao *ao, + uint32_t domid, + libxl_domain_config *d_config, + libxl__multidev *multidev); + +_hidden void libxl__prepare_undisks(libxl__egc *egc, libxl__ao *ao, + uint32_t domid, + libxl_domain_config *d_config, + libxl__multidev *multidev); + +_hidden void libxl__unprepare_disks(libxl__egc *egc, libxl__ao *ao, + uint32_t domid, + libxl_domain_config *d_config, + libxl__multidev *multidev); + _hidden void libxl__add_nics(libxl__egc *egc, libxl__ao *ao, uint32_t domid, libxl_domain_config *d_config, libxl__multidev *multidev); diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index acc4bc9..8d8cd6a 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -367,6 +367,7 @@ libxl_device_disk = Struct("device_disk", [ ("removable", integer), ("readwrite", integer), ("is_cdrom", integer), + ("hotplug_version", integer), ]) libxl_device_nic = Struct("device_nic", [ -- 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 |