[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 1/2] libxl: fix 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. Also change the
console destroy path to a switch instead of an if.

Signed-off-by: Roger Pau Monne <roger.pau@xxxxxxxxxx>
Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Cc: Ian Campbell <ian.campbell@xxxxxxxxxxxxx>
---
 tools/libxl/libxl_device.c   |  123 ++++++++++++++++++------------------------
 tools/libxl/libxl_internal.h |   10 +++-
 2 files changed, 62 insertions(+), 71 deletions(-)

diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index da0c3ea..4667261 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -58,50 +58,6 @@ int libxl__parse_backend_path(libxl__gc *gc,
     return libxl__device_kind_from_string(strkind, &dev->backend_kind);
 }
 
-static int libxl__num_devices(libxl__gc *gc, uint32_t domid)
-{
-    char *path;
-    unsigned int num_kinds, num_devs;
-    char **kinds = NULL, **devs = NULL;
-    int i, j, rc = 0;
-    libxl__device dev;
-    libxl__device_kind kind;
-    int numdevs = 0;
-
-    path = GCSPRINTF("/local/domain/%d/device", domid);
-    kinds = libxl__xs_directory(gc, XBT_NULL, path, &num_kinds);
-    if (!kinds) {
-        if (errno != ENOENT) {
-            LOGE(ERROR, "unable to get xenstore device listing %s", path);
-            rc = ERROR_FAIL;
-            goto out;
-        }
-        num_kinds = 0;
-    }
-    for (i = 0; i < num_kinds; i++) {
-        if (libxl__device_kind_from_string(kinds[i], &kind))
-            continue;
-        if (kind == LIBXL__DEVICE_KIND_CONSOLE)
-            continue;
-
-        path = GCSPRINTF("/local/domain/%d/device/%s", domid, kinds[i]);
-        devs = libxl__xs_directory(gc, XBT_NULL, path, &num_devs);
-        if (!devs)
-            continue;
-        for (j = 0; j < num_devs; j++) {
-            path = GCSPRINTF("/local/domain/%d/device/%s/%s/backend",
-                             domid, kinds[i], devs[j]);
-            path = libxl__xs_read(gc, XBT_NULL, path);
-            if (path && libxl__parse_backend_path(gc, path, &dev) == 0) {
-                numdevs++;
-            }
-        }
-    }
-out:
-    if (rc) return rc;
-    return numdevs;
-}
-
 int libxl__nic_type(libxl__gc *gc, libxl__device *dev, libxl_nic_type *nictype)
 {
     char *snictype, *be_path;
@@ -451,9 +407,15 @@ void libxl__prepare_ao_devices(libxl__ao *ao, 
libxl__ao_devices *aodevs)
 
     GCNEW_ARRAY(aodevs->array, aodevs->size);
     for (int i = 0; i < aodevs->size; i++) {
-        aodevs->array[i].aodevs = aodevs;
-        libxl__prepare_ao_device(ao, &aodevs->array[i]);
+        GCNEW(aodevs->array[i]);
+        aodevs->array[i]->aodevs = aodevs;
+        libxl__prepare_ao_device(ao, aodevs->array[i]);
     }
+    /*
+     * Since we have already added all the aodevs, and marked them
+     * as active, we can mark the addition operation as finished.
+     */
+    aodevs->in_addition = 0;
 }
 
 void libxl__ao_devices_callback(libxl__egc *egc, libxl__ao_device *aodev)
@@ -463,12 +425,15 @@ void libxl__ao_devices_callback(libxl__egc *egc, 
libxl__ao_device *aodev)
     int i, error = 0;
 
     aodev->active = 0;
+    if (aodevs->in_addition)
+        return;
+
     for (i = 0; i < aodevs->size; i++) {
-        if (aodevs->array[i].active)
+        if (aodevs->array[i]->active)
             return;
 
-        if (aodevs->array[i].rc)
-            error = aodevs->array[i].rc;
+        if (aodevs->array[i]->rc)
+            error = aodevs->array[i]->rc;
     }
 
     aodevs->callback(egc, aodevs, error);
@@ -495,9 +460,9 @@ void libxl__ao_devices_callback(libxl__egc *egc, 
libxl__ao_device *aodev)
         int i;                                                                 
\
         int end = start + d_config->num_##type##s;                             
\
         for (i = start; i < end; i++) {                                        
\
-            aodevs->array[i].callback = libxl__ao_devices_callback;            
\
+            aodevs->array[i]->callback = libxl__ao_devices_callback;           
\
             libxl__device_##type##_add(egc, domid, 
&d_config->type##s[i-start],\
-                                       &aodevs->array[i]);                     
\
+                                       aodevs->array[i]);                      
\
         }                                                                      
\
     }
 
@@ -545,20 +510,20 @@ void libxl__devices_destroy(libxl__egc *egc, 
libxl__devices_remove_state *drs)
     char *path;
     unsigned int num_kinds, num_dev_xsentries;
     char **kinds = NULL, **devs = NULL;
-    int i, j, numdev = 0, rc = 0;
+    int i, j, rc = 0;
     libxl__device *dev;
     libxl__ao_devices *aodevs = &drs->aodevs;
     libxl__ao_device *aodev;
     libxl__device_kind kind;
 
-    aodevs->size = libxl__num_devices(gc, drs->domid);
-    if (aodevs->size < 0) {
-        LOG(ERROR, "unable to get number of devices for domain %u", 
drs->domid);
-        rc = aodevs->size;
-        goto out;
-    }
-
-    libxl__prepare_ao_devices(drs->ao, aodevs);
+    /*
+     * Initialize values of the aodevs structure manually,
+     * since we don't know the number of devices we are going
+     * to unplug yet.
+     */
+    aodevs->in_addition = 1;
+    aodevs->size = 0;
+    aodevs->array = NULL;
     aodevs->callback = devices_remove_callback;
 
     path = libxl__sprintf(gc, "/local/domain/%d/device", domid);
@@ -588,21 +553,28 @@ void libxl__devices_destroy(libxl__egc *egc, 
libxl__devices_remove_state *drs)
                 dev->domid = domid;
                 dev->kind = kind;
                 dev->devid = atoi(devs[j]);
-                if (dev->backend_kind == LIBXL__DEVICE_KIND_CONSOLE) {
+                switch (dev->backend_kind) {
+                case LIBXL__DEVICE_KIND_CONSOLE:
                     /* Currently console devices can be destroyed
                      * synchronously by just removing xenstore entries,
                      * this is what libxl__device_destroy does.
                      */
                     libxl__device_destroy(gc, dev);
-                    continue;
+                    break;
+                default:
+                    GCREALLOC_ARRAY(aodevs->array, aodevs->size + 1);
+                    GCNEW(aodev);
+                    aodevs->array[aodevs->size] = aodev;
+                    libxl__prepare_ao_device(ao, aodev);
+                    aodev->aodevs = aodevs;
+                    aodev->action = DEVICE_DISCONNECT;
+                    aodev->dev = dev;
+                    aodev->callback = libxl__ao_devices_callback;
+                    aodev->force = drs->force;
+                    libxl__initiate_device_remove(egc, aodev);
+                    aodevs->size++;
+                    break;
                 }
-                aodev = &aodevs->array[numdev];
-                aodev->action = DEVICE_DISCONNECT;
-                aodev->dev = dev;
-                aodev->callback = libxl__ao_devices_callback;
-                aodev->force = drs->force;
-                libxl__initiate_device_remove(egc, aodev);
-                numdev++;
             }
         }
     }
@@ -624,7 +596,18 @@ void libxl__devices_destroy(libxl__egc *egc, 
libxl__devices_remove_state *drs)
     }
 
 out:
-    if (!numdev) drs->callback(egc, drs, rc);
+    if (!aodevs->size) drs->callback(egc, drs, rc);
+    else {
+        /*
+         * Create a dummy aodev to check if all the other aodevs are finished,
+         * and call the callback.
+         */
+        GCNEW(aodev);
+        libxl__prepare_ao_device(ao, aodev);
+        aodev->aodevs = aodevs;
+        aodevs->in_addition = 0;
+        libxl__ao_devices_callback(egc, aodev);
+    }
     return;
 }
 
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 3e91529..3ee3a09 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1808,6 +1808,8 @@ _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.
+ * Once this function is called, the aodevs->size value cannot be changed,
+ * and no further aodevs can be added to the array.
  */
 _hidden void libxl__prepare_ao_devices(libxl__ao *ao,
                                        libxl__ao_devices *aodevs);
@@ -1849,9 +1851,15 @@ struct libxl__ao_device {
  */
 typedef void libxl__devices_callback(libxl__egc*, libxl__ao_devices*, int rc);
 struct libxl__ao_devices {
-    libxl__ao_device *array;
+    libxl__ao_device **array;
     int size;
     libxl__devices_callback *callback;
+    /*
+     * if in_addition == 1 means we are currently adding devices
+     * to the array, if in_addition == 0, means we have added all
+     * the devices.
+     */
+    int in_addition;
 };
 
 /*
-- 
1.7.7.5 (Apple Git-26)


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.