[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v1 05/10] libxl: synchronise configuration when we hotplug a device
On Wed, Jul 16, 2014 at 05:48:59PM +0100, Ian Campbell wrote: > On Thu, 2014-07-10 at 15:32 +0100, Wei Liu wrote: > > 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. > > We also ensure that if 2 and 3 are invoked in a loop, the previous > > added JSON entry is removed before writing new one. > > > > The locking patten is designed like this, because when adding a disk, > > "pattern". Apparently a patten is a type of clog or shoe l-) > > > the caller might specify get_vdev which will get called in the middle > > of a xenstore transaction to determine the identifier of a disk. Other > > devices don't have this property, but I make them follow the same > > pattern for consistency. > > I don't know if it is helpful but AIUI the get_vdev there is purely to > handle the case where the disk is being attached to the toolstack domain > (e.g. for pygrub). I don't know if that simplifies anything for you. > Probably not if get_vdev is set to be called in this loop and embedded in a xenstore transaction. For other device, determining devid only requires XBT_NULL, so that I can safely move the call earlier. I'm not confident that I can do the same for disk. > > As we don't have a JSON config file for libxl toolstack domain > > (currently Dom0) we need to skip JSON manipulation for it. > > How hard would it be to create a stub/stunt JSON for dom0 when we notice > it is missing? Or from e.g. xencommons perhaps? > We need to determine: 1. when / where to generate such thing (xencommons?) 2. what to put in it I have yet had answers for #2. The simplest version can be "{}" I think. That is an empty configuration that every fields gets the default value. But we probably need more than that. > > Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx> > > @@ -1917,6 +1922,8 @@ void libxl__device_vtpm_add(libxl__egc *egc, uint32_t > > domid, > > goto out; > > } > > } > > + vtpm_saved.devid = vtpm->devid; > > Why isn't this in the update_config fn? > Sure, this can be done. > > + libxl__update_config_vtpm(gc, &vtpm_saved, vtpm); > > > > GCNEW(device); > > rc = libxl__device_from_vtpm(gc, domid, vtpm, device); > > @@ -1943,17 +1950,30 @@ void libxl__device_vtpm_add(libxl__egc *egc, > > uint32_t domid, > > flexarray_append(front, "handle"); > > flexarray_append(front, GCSPRINTF("%d", vtpm->devid)); > > > > + LOCK_DOMAIN_JSON_CONFIG(gc, domid, lock, rc); > > + if (rc) goto out; > > I can't see anything in this macro (or the unlock one) which > necessitates it being a macro rather than a helper function. > Helper funtion it is. > Couldn't you just do the LIBXL_TOOLSTACK_DOMID check in > libxl__lock_domain_configuration? > This can be done. > > + > > + DEVICE_ADD_JSON(vtpm, vtpms, num_vtpms, domid, &vtpm_saved, > > The second and third of these arguments could be derived from the first. > Unfortunately not: PCI device doesn't follow this rule. Otherwise I would have done it already. :-( > > @@ -2193,21 +2217,56 @@ static void device_disk_add(libxl__egc *egc, > > uint32_t domid, > > goto out; > > } > > > > + libxl_device_disk_copy(CTX, &disk_saved, disk); > > + > > + LOCK_DOMAIN_JSON_CONFIG(gc, domid, lock, rc); > > + if (rc) goto out; > > + > > for (;;) { > > rc = libxl__xs_transaction_start(gc, &t); > > - if (rc) goto out; > > + if (rc) { > > + UNLOCK_DOMAIN_JSON_CONFIG(gc, domid, lock); > > + goto out; > > + } > > + > > + /* This is a loop, if disk has been added to JSON before, we > > + * need to remove it, then add it later, because disk->vdev > > + * might change. > > Has the old device been removed from xenstore at this point? Otherwise > aren't you breaking your invariant that a device in xenstore is always > described in the json. > Not yet, we're here (again) because the transaction hasn't been committed. > > + */ > > + DEVICE_REMOVE_JSON(disk, disks, num_disks, domid, &disk_saved, > > + COMPARE_DISK, rc); > > + if (rc) { > > + UNLOCK_DOMAIN_JSON_CONFIG(gc, domid, lock); > > + goto out; > > I wonder if you can arrange the exit path such that this can happen > there and save all of these? > I will see what I can do. > > +#define DEVICE_ADD_JSON(type, ptr, cnt, domid, dev, compare, rc) \ > > + do { \ > > + int x; \ > > + libxl_domain_config d_config; \ > > + libxl_device_##type *p; \ > > + \ > > + if (domid == LIBXL_TOOLSTACK_DOMID) \ > > + break; \ > > + \ > > + libxl_domain_config_init(&d_config); \ > > + \ > > + rc = libxl__get_domain_configuration(gc, (domid), &d_config); \ > > + if (rc) \ > > + goto add_done; \ > > + \ > > + /* Check for duplicated device */ \ > > + for (x = 0; x < d_config.cnt; x++) { \ > > + if (compare(&d_config.ptr[x], (dev))) { \ > > Compare just checks ->devid etc, right? > It depends on specific device type. See those COMPARE_* macros. Disk and PCI devices don't have devid. > What if this device has the same devid but a different config? > > That probably ought to be an error, have we already caught that or are > we relying on something later? > Then the caller should use DEVICE_UPDATE_JSON which is introduced in later patch. > I suppose either way we don't want to add the device again now. > Yes. > > + rc = 0; \ > > + goto add_done; \ > > + } \ > > + } \ > > + \ > > + d_config.ptr = \ > > + libxl__realloc(gc, d_config.ptr, \ > > + (d_config.cnt + 1) * \ > > + sizeof(libxl_device_##type)); \ > > + p = &d_config.ptr[d_config.cnt]; \ > > + d_config.cnt++; \ > > + libxl_device_##type##_copy(CTX, p, (dev)); \ > > + \ > > + rc = libxl__set_domain_configuration(gc, (domid), &d_config); \ > > How close to being possible is it to do this as a proper helper function > which takes a size_t and a bunch of fn pointers with void where the type > would be? > We need to know the type of this structure otherwise we don't know what *_copy function to call. Sadly there's no way to pass in type information in C in runtime. > > + \ > > + add_done: \ > > You are going to have multiple of these labels in this source file. Not > sure quite what that means in C. The simple answer would be to involve > ##type## in the name. > That would break compilation I think. But I haven't seen it so far because this macro only gets used once in those caller functions. I will make this change as you suggest anyway. > > + libxl_domain_config_dispose(&d_config); \ > > + } while (0) > > + > > +#define DEVICE_REMOVE_JSON(type, ptr, cnt, domid, dev, compare, rc) \ > > Same comments as on add. > Same reply as on add. :-) > > + do { \ > > + int i, j; \ > > + libxl_device_##type *p = dev; \ > > + libxl_domain_config d_config; \ > > + bool removed = false; \ > > + \ > > + if (domid == LIBXL_TOOLSTACK_DOMID) \ > > + break; \ > > + \ > > + libxl_domain_config_init(&d_config); \ > > + \ > > + rc = libxl__get_domain_configuration(gc, (domid), &d_config); \ > > + if (rc) \ > > + goto remove_done; \ > > + \ > > + for (i = j = 0; i < d_config.cnt; i++) { \ > > + if (!compare(&d_config.ptr[i], p)) { \ > > + if (i != j) { \ > > + libxl_device_##type##_dispose(&d_config.ptr[j]); \ > > + d_config.ptr[j] = d_config.ptr[i]; \ > > + removed = true; \ > > + } \ > > + j++; \ > > + } \ > > + } \ > > + \ > > + if (!removed) /* no matching entry found */ \ > > + goto remove_done; \ > > + \ > > + d_config.ptr = \ > > + libxl__realloc(NOGC, d_config.ptr, \ > > + j * sizeof(libxl_device_##type)); \ > > + d_config.cnt = j; \ > > The fact that the compare loop also shuffles everything down is worthy > of noting in a comment I think. > OK. Wei. > Ian. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |