aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxl/libxl_internal.h
diff options
context:
space:
mode:
authorIan Jackson <ian.jackson@eu.citrix.com>2012-08-03 09:54:09 +0100
committerIan Jackson <ian.jackson@eu.citrix.com>2012-08-03 09:54:09 +0100
commit258cd4e261de3b3f4470ba390b16c73101c802ce (patch)
tree390951657fdda2f1142cafa01d3662105c3f1eb6 /tools/libxl/libxl_internal.h
parent7253e0fd1aeb3ae7d4714bcc1d86b846b3331995 (diff)
downloadxen-258cd4e261de3b3f4470ba390b16c73101c802ce.tar.gz
xen-258cd4e261de3b3f4470ba390b16c73101c802ce.tar.bz2
xen-258cd4e261de3b3f4470ba390b16c73101c802ce.zip
libxl: fix device counting race in libxl__devices_destroy
Don't have a fixed number of devices in the aodevs array, and instead size it depending on the devices present in xenstore. Somewhat formalise the multiple device addition/removal machinery to make this clearer and easier to do. As a side-effect we fix a few "lost thread of control" bug which would occur if there were no devices of a particular kind. (Various if statements which checked for there being no devices have become redundant, but are retained to avoid making the patch bigger.) Specifically: * Users of libxl__ao_devices are no longer expected to know in advance how many device operations they are going to do. Instead they can initiate them one at a time, between bracketing calls to "begin" and "prepared". * The array of aodevs used for this is dynamically sized; to support this it's an array of pointers rather than of structs. * Users of libxl__ao_devices are presented with a more opaque interface. They are are no longer expected to, themselves, - look into the array of aodevs (this is now private) - know that the individual addition/removal completions are handled by libxl__ao_devices_callback (this callback function is now a private function for the multidev machinery) - ever deal with populating the contents of an aodevs * The doc comments relating to some of the members of libxl__ao_device are clarified. (And the member `aodevs' is moved to put it with the other members with the same status.) * The multidev machinery allocates an aodev to represent the operation of preparing all of the other operations. See the comment in libxl__multidev_begin. A wrinkle is that the functions are called "multidev" but the structs are called "libxl__ao_devices" and "aodevs". I have given these functions this name to distinguish them from "libxl__ao_device" and "aodev" and so forth by more than just the use of the plural "s" suffix. In the next patch we will rename the structs. Signed-off-by: Roger Pau Monne <roger.pau@citrix.com> Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@eu.citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
Diffstat (limited to 'tools/libxl/libxl_internal.h')
-rw-r--r--tools/libxl/libxl_internal.h77
1 files changed, 46 insertions, 31 deletions
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 2d6c71a815..07e92fbc35 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1816,20 +1816,6 @@ typedef void libxl__device_callback(libxl__egc*, libxl__ao_device*);
*/
_hidden void libxl__prepare_ao_device(libxl__ao *ao, libxl__ao_device *aodev);
-/* Prepare a bunch of devices for addition/removal. Every ao_device in
- * ao_devices is set to 'active', and the ao_device 'base' field is set to
- * the one pointed by aodevs.
- */
-_hidden void libxl__prepare_ao_devices(libxl__ao *ao,
- libxl__ao_devices *aodevs);
-
-/* Generic callback to use when adding/removing several devices, this will
- * check if the given aodev is the last one, and call the callback in the
- * parent libxl__ao_devices struct, passing the appropriate error if found.
- */
-_hidden void libxl__ao_devices_callback(libxl__egc *egc,
- libxl__ao_device *aodev);
-
struct libxl__ao_device {
/* filled in by user */
libxl__ao *ao;
@@ -1837,32 +1823,60 @@ struct libxl__ao_device {
libxl__device *dev;
int force;
libxl__device_callback *callback;
- /* private for implementation */
- int active;
+ /* return value, zeroed by user on entry, is valid on callback */
int rc;
+ /* private for multidev */
+ int active;
+ libxl__ao_devices *aodevs; /* reference to the containing multidev */
+ /* private for add/remove implementation */
libxl__ev_devstate backend_ds;
/* Bodge for Qemu devices, also used for timeout of hotplug execution */
libxl__ev_time timeout;
- /* Used internally to have a reference to the upper libxl__ao_devices
- * struct when present */
- libxl__ao_devices *aodevs;
/* device hotplug execution */
const char *what;
int num_exec;
libxl__ev_child child;
};
-/* Helper struct to simply the plug/unplug of multiple devices at the same
- * time.
- *
- * This structure holds several devices, and the callback is only called
- * when all the devices inside of the array have finished.
- */
+/*
+ * Multiple devices "multidev" handling.
+ *
+ * Firstly, you should
+ * libxl__multidev_begin
+ * multidev->callback = ...
+ * Then zero or more times
+ * libxl__multidev_prepare
+ * libal__initiate_device_{remove/addition}.
+ * Finally, once
+ * libxl__multidev_prepared
+ * which will result (perhaps reentrantly) in one call to callback().
+ */
+
+/* Starts preparing to add/remove a bunch of devices. */
+_hidden void libxl__multidev_begin(libxl__ao *ao, libxl__ao_devices*);
+
+/* Prepares to add/remove one of many devices. Returns a libxl__ao_device
+ * which has had libxl__prepare_ao_device called, and which has also
+ * had ->callback set. The user should not mess with aodev->callback. */
+_hidden libxl__ao_device *libxl__multidev_prepare(libxl__ao_devices*);
+
+/* Notifies the multidev machinery that we have now finished preparing
+ * and initiating devices. multidev->callback may then be called as
+ * soon as there are no prepared but not completed operations
+ * outstanding, perhaps reentrantly. If rc!=0 (error should have been
+ * logged) multidev->callback will get a non-zero rc.
+ * callback may be set by the user at any point before prepared. */
+_hidden void libxl__multidev_prepared(libxl__egc*, libxl__ao_devices*, int rc);
+
typedef void libxl__devices_callback(libxl__egc*, libxl__ao_devices*, int rc);
struct libxl__ao_devices {
- libxl__ao_device *array;
- int size;
+ /* set by user: */
libxl__devices_callback *callback;
+ /* for private use by libxl__...ao_devices... machinery: */
+ libxl__ao *ao;
+ libxl__ao_device **array;
+ int used, allocd;
+ libxl__ao_device *preparation;
};
/*
@@ -2372,10 +2386,11 @@ _hidden void libxl__devices_destroy(libxl__egc *egc,
libxl__devices_remove_state *drs);
/* Helper function to add a bunch of disks. This should be used when
- * the caller is inside an async op. "devices" will NOT be prepared by this
- * function, so the caller must make sure to call _prepare before calling this
- * function. The start parameter contains the position inside the aodevs array
- * that should be used to store the state of this devices.
+ * the caller is inside an async op. "devices" will NOT be prepared by
+ * this function, so the caller must make sure to call
+ * libxl__multidev_begin before calling this function. The start
+ * parameter contains the position inside the aodevs array that should
+ * be used to store the state of this devices.
*
* The "callback" will be called for each device, and the user is responsible
* for calling libxl__ao_device_check_last on the callback.