[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2 11/18] libxl: synchronise configuration when we hotplug a device
We update JSON version first, then write to xenstore, so that we maintain the following invariant: any device which is present in xenstore has a corresponding entry in JSON. The locking pattern is as followed: 1. lock JSON domain config 2. write JSON entry 3. write xenstore entry for a device 4. unlock JSON domain config And we ensure in code that JSON entry is always written before the xenstore entry is written. That is, if 2 fails, 3 will not be executed. As those routines are called both during domain creation and device hotplug, we add a flag to indicate whether we need to update JSON config. This flag is only set to true when we hotplug a device. We cannot update JSON config during domain creation as JSON config is committed to disk only when domain creation finishes. Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx> --- tools/libxl/libxl.c | 64 ++++++++++++++++++ tools/libxl/libxl_internal.h | 151 ++++++++++++++++++++++++++++++++++++++++++ tools/libxl/libxl_pci.c | 20 ++++++ 3 files changed, 235 insertions(+) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index e6fe238..184e126 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -1888,6 +1888,11 @@ void libxl__device_vtpm_add(libxl__egc *egc, uint32_t domid, flexarray_t *back; libxl__device *device; int rc; + libxl_device_vtpm vtpm_saved; + libxl__carefd *lock = NULL; + + libxl_device_vtpm_init(&vtpm_saved); + libxl_device_vtpm_copy(CTX, &vtpm_saved, vtpm); rc = libxl__device_vtpm_setdefault(gc, vtpm); if (rc) goto out; @@ -1902,6 +1907,8 @@ void libxl__device_vtpm_add(libxl__egc *egc, uint32_t domid, } } + libxl__update_config_vtpm(gc, &vtpm_saved, vtpm); + GCNEW(device); rc = libxl__device_from_vtpm(gc, domid, vtpm, device); if ( rc != 0 ) goto out; @@ -1936,6 +1943,18 @@ void libxl__device_vtpm_add(libxl__egc *egc, uint32_t domid, flexarray_append(front, "handle"); flexarray_append(front, GCSPRINTF("%d", vtpm->devid)); + if (aodev->update_json) { + lock = libxl__lock_domain_data(gc, domid); + if (!lock) { + rc = ERROR_LOCK_FAIL; + goto out; + } + + rc = DEVICE_ADD_JSON(vtpm, vtpms, num_vtpms, domid, &vtpm_saved, + COMPARE_DEVID); + if (rc) goto out; + } + libxl__device_generic_add(gc, XBT_NULL, device, libxl__xs_kvs_of_flexarray(gc, back, back->count), libxl__xs_kvs_of_flexarray(gc, front, front->count), @@ -1947,6 +1966,8 @@ void libxl__device_vtpm_add(libxl__egc *egc, uint32_t domid, rc = 0; out: + if (lock) libxl__unlock_domain_data(lock); + libxl_device_vtpm_dispose(&vtpm_saved); aodev->rc = rc; if(rc) aodev->callback(egc, aodev); return; @@ -2186,6 +2207,10 @@ static void device_disk_add(libxl__egc *egc, uint32_t domid, int rc; libxl_ctx *ctx = gc->owner; xs_transaction_t t = XBT_NULL; + libxl_device_disk disk_saved; + libxl__carefd *lock = NULL; + + libxl_device_disk_init(&disk_saved); libxl_domain_type type = libxl__domain_type(gc, domid); if (type == LIBXL_DOMAIN_TYPE_INVALID) { @@ -2198,6 +2223,8 @@ static void device_disk_add(libxl__egc *egc, uint32_t domid, * we need to check if this device already exists in xenstore. */ if (!get_vdev) { + libxl_device_disk_copy(CTX, &disk_saved, disk); + /* Construct libxl__device from libxl_device_disk */ libxl__device_disk_setdefault(gc, disk); GCNEW(device); @@ -2216,6 +2243,18 @@ static void device_disk_add(libxl__egc *egc, uint32_t domid, rc = ERROR_DEVICE_EXISTS; goto out; } + + if (aodev && aodev->update_json) { + lock = libxl__lock_domain_data(gc, domid); + if (!lock) { + rc = ERROR_LOCK_FAIL; + goto out; + } + + rc = DEVICE_ADD_JSON(disk, disks, num_disks, domid, + &disk_saved, COMPARE_DISK); + if (rc) goto out; + } } for (;;) { @@ -2378,6 +2417,8 @@ static void device_disk_add(libxl__egc *egc, uint32_t domid, rc = 0; out: + if (lock) libxl__unlock_domain_data(lock); + libxl_device_disk_dispose(&disk_saved); libxl__xs_transaction_abort(gc, &t); aodev->rc = rc; if (rc) aodev->callback(egc, aodev); @@ -3034,6 +3075,11 @@ void libxl__device_nic_add(libxl__egc *egc, uint32_t domid, flexarray_t *back; libxl__device *device; int rc; + libxl_device_nic nic_saved; + libxl__carefd *lock = NULL; + + libxl_device_nic_init(&nic_saved); + libxl_device_nic_copy(CTX, &nic_saved, nic); rc = libxl__device_nic_setdefault(gc, nic, domid); if (rc) goto out; @@ -3048,6 +3094,8 @@ void libxl__device_nic_add(libxl__egc *egc, uint32_t domid, } } + libxl__update_config_nic(gc, &nic_saved, nic); + GCNEW(device); rc = libxl__device_from_nic(gc, domid, nic, device); if ( rc != 0 ) goto out; @@ -3113,6 +3161,19 @@ void libxl__device_nic_add(libxl__egc *egc, uint32_t domid, flexarray_append(front, "mac"); flexarray_append(front, libxl__sprintf(gc, LIBXL_MAC_FMT, LIBXL_MAC_BYTES(nic->mac))); + + if (aodev->update_json) { + lock = libxl__lock_domain_data(gc, domid); + if (!lock) { + rc = ERROR_LOCK_FAIL; + goto out; + } + + rc = DEVICE_ADD_JSON(nic, nics, num_nics, domid, &nic_saved, + COMPARE_DEVID); + if (rc) goto out; + } + libxl__device_generic_add(gc, XBT_NULL, device, libxl__xs_kvs_of_flexarray(gc, back, back->count), libxl__xs_kvs_of_flexarray(gc, front, front->count), @@ -3124,6 +3185,8 @@ void libxl__device_nic_add(libxl__egc *egc, uint32_t domid, rc = 0; out: + if (lock) libxl__unlock_domain_data(lock); + libxl_device_nic_dispose(&nic_saved); aodev->rc = rc; if (rc) aodev->callback(egc, aodev); return; @@ -3702,6 +3765,7 @@ DEFINE_DEVICE_REMOVE(vtpm, destroy, 1) \ GCNEW(aodev); \ libxl__prepare_ao_device(ao, aodev); \ + aodev->update_json = true; \ aodev->callback = device_add_aocomplete; \ libxl__device_##type##_add(egc, domid, type, aodev); \ \ diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index 1b44c2c..a5eb7d4 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -2144,6 +2144,8 @@ struct libxl__ao_device { int num_exec; /* for calling hotplug scripts */ libxl__async_exec_state aes; + /* If we need to udpate JSON config */ + bool update_json; }; /* @@ -3271,6 +3273,155 @@ static inline void libxl__update_config_vtpm(libxl__gc *gc, libxl_uuid_copy(CTX, &dst->uuid, &src->uuid); } +/* Macros used to compare device identifier. Returns true if the two + * devices have same identifier. */ +#define COMPARE_DEVID(a, b) ((a)->devid == (b)->devid) +#define COMPARE_DISK(a, b) (!strcmp((a)->vdev, (b)->vdev)) +#define COMPARE_PCI(a, b) ((a)->func == (b)->func && \ + (a)->bus == (b)->bus && \ + (a)->dev == (b)->dev) + +/* Expression int DEVICE_{ADD,REMOVE,UPDATE}_JSON + * + * Add / remove / update a device in JSON config file. Caller + * must hold data store lock before invoking these macros. + * + * They take 6 parameters: + * type: the type of the device, say nic, vtpm, disk, pci etc + * ptr: the pointer to array inside libxl_domain_config + * cnt: the counter of array + * domid: domain id of target domain + * dev: the device that is to be added / removed / updated + * compare: the COMPARE_* macro used to compare @dev's identifier to + * those in the array pointed to by @ptr + * + * Return 0 if no error occurs, ERROR_* otherwise. + * + * For most device types (nic, vtpm), the array name @ptr and array + * counter @cnt can be derived from @type, pci device being the + * exception, hence we need to have @ptr and @cnt. + */ + +/* Add a device to JSON config. If there is already device with the + * same identifier in JSON config, no action will be taken. + * Use the "update" macro to update JSON config of a device. + */ +#define DEVICE_ADD_JSON(type, ptr, cnt, domid, dev, compare) \ + ({ \ + int DAJ_x, DAJ_rc; \ + libxl_domain_config DAJ_d_config; \ + libxl_device_##type *DAJ_p; \ + \ + libxl_domain_config_init(&DAJ_d_config); \ + \ + DAJ_rc = libxl__get_domain_configuration(gc, (domid), \ + &DAJ_d_config); \ + if (DAJ_rc) \ + goto DAJ_out; \ + \ + /* Check for duplicated device */ \ + for (DAJ_x = 0; DAJ_x < DAJ_d_config.cnt; DAJ_x++) { \ + if (compare(&DAJ_d_config.ptr[DAJ_x], (dev))) { \ + DAJ_rc = 0; \ + goto DAJ_out; \ + } \ + } \ + \ + DAJ_d_config.ptr = \ + libxl__realloc(NOGC, DAJ_d_config.ptr, \ + (DAJ_d_config.cnt + 1) * \ + sizeof(libxl_device_##type)); \ + DAJ_p = &DAJ_d_config.ptr[DAJ_d_config.cnt]; \ + DAJ_d_config.cnt++; \ + libxl_device_##type##_copy(CTX, DAJ_p, (dev)); \ + \ + DAJ_rc = libxl__set_domain_configuration(gc, (domid), \ + &DAJ_d_config); \ + \ + DAJ_out: \ + libxl_domain_config_dispose(&DAJ_d_config); \ + DAJ_rc; \ + }) + +/* Remove a device from JSON config. */ +#define DEVICE_REMOVE_JSON(type, ptr, cnt, domid, dev, compare) \ + ({ \ + int DRJ_i, DRJ_j, DRJ_rc; \ + libxl_device_##type *DRJ_p = dev; \ + libxl_domain_config DRJ_d_config; \ + \ + libxl_domain_config_init(&DRJ_d_config); \ + \ + DRJ_rc = libxl__get_domain_configuration(gc, (domid), \ + &DRJ_d_config); \ + if (DRJ_rc) \ + goto DRJ_out; \ + \ + /* This loop may shuffle down the array */ \ + for (DRJ_i = DRJ_j = 0; DRJ_i < DRJ_d_config.cnt; DRJ_i++) { \ + if (!compare(&DRJ_d_config.ptr[DRJ_i], DRJ_p)) { \ + if (DRJ_i != DRJ_j) { \ + libxl_device_##type DRJ_tmp; \ + DRJ_tmp = DRJ_d_config.ptr[DRJ_j]; \ + DRJ_d_config.ptr[DRJ_j] = DRJ_d_config.ptr[DRJ_i]; \ + DRJ_d_config.ptr[DRJ_i] = DRJ_tmp; \ + } \ + DRJ_j++; \ + } \ + } \ + \ + if (DRJ_i == DRJ_j) /* no matching entry found */ \ + goto DRJ_out; \ + \ + libxl_device_##type##_dispose(&DRJ_d_config.ptr[DRJ_j]); \ + DRJ_d_config.ptr = \ + libxl__realloc(NOGC, DRJ_d_config.ptr, \ + DRJ_j * sizeof(libxl_device_##type)); \ + DRJ_d_config.cnt = DRJ_j; \ + \ + DRJ_rc = libxl__set_domain_configuration(gc, (domid), \ + &DRJ_d_config); \ + \ + DRJ_out: \ + libxl_domain_config_dispose(&DRJ_d_config); \ + DRJ_rc; \ + }) + +/* Search device list for device with the same identifier as "dev", + * update that device with the content pointed to by "dev". + */ +#define DEVICE_UPDATE_JSON(type, ptr, cnt, domid, dev, compare) \ + ({ \ + int DUJ_x, DUJ_rc; \ + libxl_domain_config DUJ_d_config; \ + bool DUJ_updated = false; \ + \ + libxl_domain_config_init(&DUJ_d_config); \ + \ + DUJ_rc = libxl__get_domain_configuration(gc, domid, \ + &DUJ_d_config); \ + if (DUJ_rc) \ + goto DUJ_out; \ + \ + for (DUJ_x = 0; DUJ_x < DUJ_d_config.cnt; DUJ_x++) { \ + if (compare(&DUJ_d_config.ptr[DUJ_x], (dev))) { \ + libxl_device_##type##_dispose( \ + &DUJ_d_config.ptr[DUJ_x]); \ + libxl_device_##type##_copy(CTX, \ + &DUJ_d_config.ptr[DUJ_x], \ + (dev)); \ + DUJ_updated = true; \ + } \ + } \ + if (DUJ_updated) \ + DUJ_rc = libxl__set_domain_configuration(gc, domid, \ + &DUJ_d_config); \ + \ + DUJ_out: \ + libxl_domain_config_dispose(&DUJ_d_config); \ + DUJ_rc; \ + }) + #endif /* diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c index e05f047..357e274 100644 --- a/tools/libxl/libxl_pci.c +++ b/tools/libxl/libxl_pci.c @@ -1044,6 +1044,10 @@ int libxl__device_pci_add(libxl__gc *gc, uint32_t domid, libxl_device_pci *pcide int num_assigned, i, rc; libxl__device device; int stubdomid = 0; + libxl_device_pci pcidev_saved; + libxl__carefd *lock = NULL; + + libxl_device_pci_init(&pcidev_saved); if (libxl__domain_type(gc, domid) == LIBXL_DOMAIN_TYPE_HVM) { rc = xc_test_assign_device(ctx->xch, domid, pcidev_encode_bdf(pcidev)); @@ -1057,6 +1061,8 @@ int libxl__device_pci_add(libxl__gc *gc, uint32_t domid, libxl_device_pci *pcide } } + libxl_device_pci_copy(CTX, &pcidev_saved, pcidev); + rc = libxl__device_pci_setdefault(gc, pcidev); if (rc) goto out; @@ -1125,6 +1131,18 @@ int libxl__device_pci_add(libxl__gc *gc, uint32_t domid, libxl_device_pci *pcide pfunc_mask = (1 << pcidev->func); } + if (!starting) { + lock = libxl__lock_domain_data(gc, domid); + if (!lock) { + rc = ERROR_LOCK_FAIL; + goto out; + } + + rc = DEVICE_ADD_JSON(pci, pcidevs, num_pcidevs, domid, pcidev, + COMPARE_PCI); + if (rc) goto out; + } + for(rc = 0, i = 7; i >= 0; --i) { if ( (1 << i) & pfunc_mask ) { if ( pcidev->vfunc_mask == pfunc_mask ) { @@ -1143,6 +1161,8 @@ int libxl__device_pci_add(libxl__gc *gc, uint32_t domid, libxl_device_pci *pcide } out: + if (lock) libxl__unlock_domain_data(lock); + libxl_device_pci_dispose(&pcidev_saved); return rc; } -- 1.7.10.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |