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

[Xen-changelog] [xen master] libxl: move device specific functions out of libxl.c



commit 0529961c579df44b08e3267ade2d4991da1ba5a2
Author:     Juergen Gross <jgross@xxxxxxxx>
AuthorDate: Wed Feb 8 17:09:30 2017 +0100
Commit:     Wei Liu <wei.liu2@xxxxxxxxxx>
CommitDate: Mon Feb 13 10:59:19 2017 +0000

    libxl: move device specific functions out of libxl.c
    
    Move the few generic device specific functions left in libxl.c to
    libxl_device.c.
    
    Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
    Reviewed-by: Wei Liu <wei.liu2@xxxxxxxxxx>
    Acked-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
---
 tools/libxl/libxl.c        | 416 ---------------------------------------------
 tools/libxl/libxl_device.c | 414 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 414 insertions(+), 416 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 9f2e6b3..7bec353 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1527,50 +1527,6 @@ out:
 
 
/******************************************************************************/
 
-/* generic callback for devices that only need to set ao_complete */
-void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
-{
-    STATE_AO_GC(aodev->ao);
-
-    if (aodev->rc) {
-        if (aodev->dev) {
-            LOGD(ERROR, aodev->dev->domid, "Unable to %s %s with id %u",
-                        libxl__device_action_to_string(aodev->action),
-                        libxl__device_kind_to_string(aodev->dev->kind),
-                        aodev->dev->devid);
-        } else {
-            LOG(ERROR, "unable to %s device",
-                       libxl__device_action_to_string(aodev->action));
-        }
-        goto out;
-    }
-
-out:
-    libxl__ao_complete(egc, ao, aodev->rc);
-    return;
-}
-
-/* common function to get next device id */
-int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device)
-{
-    char *libxl_dom_path, **l;
-    unsigned int nb;
-    int nextid = -1;
-
-    if (!(libxl_dom_path = libxl__xs_libxl_path(gc, domid)))
-        return nextid;
-
-    l = libxl__xs_directory(gc, XBT_NULL,
-        GCSPRINTF("%s/device/%s", libxl_dom_path, device),
-                            &nb);
-    if (l == NULL || nb == 0)
-        nextid = 0;
-    else
-        nextid = strtoul(l[nb - 1], NULL, 10) + 1;
-
-    return nextid;
-}
-
 int libxl__resolve_domid(libxl__gc *gc, const char *name, uint32_t *domid)
 {
     if (!name)
@@ -1579,378 +1535,6 @@ int libxl__resolve_domid(libxl__gc *gc, const char 
*name, uint32_t *domid)
 }
 
 
/******************************************************************************/
-
-/*
- * Data structures used to track devices handled by driver domains
- */
-
-/*
- * Structure that describes a device handled by a driver domain
- */
-typedef struct libxl__ddomain_device {
-    libxl__device *dev;
-    LIBXL_SLIST_ENTRY(struct libxl__ddomain_device) next;
-} libxl__ddomain_device;
-
-/*
- * Structure that describes a domain and it's associated devices
- */
-typedef struct libxl__ddomain_guest {
-    uint32_t domid;
-    int num_vifs, num_vbds, num_qdisks;
-    LIBXL_SLIST_HEAD(, struct libxl__ddomain_device) devices;
-    LIBXL_SLIST_ENTRY(struct libxl__ddomain_guest) next;
-} libxl__ddomain_guest;
-
-/*
- * Main structure used by a driver domain to keep track of devices
- * currently in use
- */
-typedef struct {
-    libxl__ao *ao;
-    libxl__ev_xswatch watch;
-    LIBXL_SLIST_HEAD(, struct libxl__ddomain_guest) guests;
-} libxl__ddomain;
-
-static libxl__ddomain_guest *search_for_guest(libxl__ddomain *ddomain,
-                                               uint32_t domid)
-{
-    libxl__ddomain_guest *dguest;
-
-    LIBXL_SLIST_FOREACH(dguest, &ddomain->guests, next) {
-        if (dguest->domid == domid)
-            return dguest;
-    }
-    return NULL;
-}
-
-static libxl__ddomain_device *search_for_device(libxl__ddomain_guest *dguest,
-                                                libxl__device *dev)
-{
-    libxl__ddomain_device *ddev;
-
-    LIBXL_SLIST_FOREACH(ddev, &dguest->devices, next) {
-#define LIBXL_DEVICE_CMP(dev1, dev2, entry) (dev1->entry == dev2->entry)
-        if (LIBXL_DEVICE_CMP(ddev->dev, dev, backend_devid) &&
-            LIBXL_DEVICE_CMP(ddev->dev, dev, backend_domid) &&
-            LIBXL_DEVICE_CMP(ddev->dev, dev, devid) &&
-            LIBXL_DEVICE_CMP(ddev->dev, dev, domid) &&
-            LIBXL_DEVICE_CMP(ddev->dev, dev, backend_kind) &&
-            LIBXL_DEVICE_CMP(ddev->dev, dev, kind))
-            return ddev;
-#undef LIBXL_DEVICE_CMP
-    }
-
-    return NULL;
-}
-
-static void device_complete(libxl__egc *egc, libxl__ao_device *aodev)
-{
-    STATE_AO_GC(aodev->ao);
-
-    LOG(DEBUG, "device %s %s %s",
-               libxl__device_backend_path(gc, aodev->dev),
-               libxl__device_action_to_string(aodev->action),
-               aodev->rc ? "failed" : "succeed");
-
-    if (aodev->action == LIBXL__DEVICE_ACTION_REMOVE)
-        free(aodev->dev);
-
-    libxl__nested_ao_free(aodev->ao);
-}
-
-static void qdisk_spawn_outcome(libxl__egc *egc, libxl__dm_spawn_state *dmss,
-                                int rc)
-{
-    STATE_AO_GC(dmss->spawn.ao);
-
-    LOGD(DEBUG, dmss->guest_domid, "qdisk backend spawn %s",
-                rc ? "failed" : "succeed");
-
-    libxl__nested_ao_free(dmss->spawn.ao);
-}
-
-/*
- * The following comment applies to both add_device and remove_device.
- *
- * If the return value is greater than 0, it means there's no ao dispatched,
- * so the free of the nested ao should be done by the parent when it has
- * finished.
- */
-static int add_device(libxl__egc *egc, libxl__ao *ao,
-                      libxl__ddomain_guest *dguest,
-                      libxl__ddomain_device *ddev)
-{
-    AO_GC;
-    libxl__device *dev = ddev->dev;
-    libxl__ao_device *aodev;
-    libxl__dm_spawn_state *dmss;
-    int rc = 0;
-
-    switch(dev->backend_kind) {
-    case LIBXL__DEVICE_KIND_VBD:
-    case LIBXL__DEVICE_KIND_VIF:
-        if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds++;
-        if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs++;
-
-        GCNEW(aodev);
-        libxl__prepare_ao_device(ao, aodev);
-        aodev->dev = dev;
-        aodev->action = LIBXL__DEVICE_ACTION_ADD;
-        aodev->callback = device_complete;
-        libxl__wait_device_connection(egc, aodev);
-
-        break;
-    case LIBXL__DEVICE_KIND_QDISK:
-        if (dguest->num_qdisks == 0) {
-            GCNEW(dmss);
-            dmss->guest_domid = dev->domid;
-            dmss->spawn.ao = ao;
-            dmss->callback = qdisk_spawn_outcome;
-
-            libxl__spawn_qdisk_backend(egc, dmss);
-        }
-        dguest->num_qdisks++;
-
-        break;
-    default:
-        rc = 1;
-        break;
-    }
-
-    return rc;
-}
-
-static int remove_device(libxl__egc *egc, libxl__ao *ao,
-                         libxl__ddomain_guest *dguest,
-                         libxl__ddomain_device *ddev)
-{
-    AO_GC;
-    libxl__device *dev = ddev->dev;
-    libxl__ao_device *aodev;
-    int rc = 0;
-
-    switch(ddev->dev->backend_kind) {
-    case LIBXL__DEVICE_KIND_VBD:
-    case LIBXL__DEVICE_KIND_VIF:
-        if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds--;
-        if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs--;
-
-        GCNEW(aodev);
-        libxl__prepare_ao_device(ao, aodev);
-        aodev->dev = dev;
-        aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
-        aodev->callback = device_complete;
-        libxl__initiate_device_generic_remove(egc, aodev);
-        break;
-    case LIBXL__DEVICE_KIND_QDISK:
-        if (--dguest->num_qdisks == 0) {
-            rc = libxl__destroy_qdisk_backend(gc, dev->domid);
-            if (rc)
-                goto out;
-        }
-        libxl__device_destroy(gc, dev);
-        free(dev);
-        /* Fall through to return > 0, no ao has been dispatched */
-    default:
-        rc = 1;
-        break;
-    }
-
-out:
-    return rc;
-}
-
-static void backend_watch_callback(libxl__egc *egc, libxl__ev_xswatch *watch,
-                                   const char *watch_path,
-                                   const char *event_path)
-{
-    libxl__ddomain *ddomain = CONTAINER_OF(watch, *ddomain, watch);
-    libxl__ao *nested_ao = libxl__nested_ao_create(ddomain->ao);
-    STATE_AO_GC(nested_ao);
-    char *p, *path;
-    const char *sstate, *sonline;
-    int state, online, rc, num_devs;
-    libxl__device *dev = NULL;
-    libxl__ddomain_device *ddev = NULL;
-    libxl__ddomain_guest *dguest = NULL;
-    bool free_ao = false;
-
-    /* Check if event_path ends with "state" or "online" and truncate it. */
-    path = libxl__strdup(gc, event_path);
-    p = strrchr(path, '/');
-    if (p == NULL)
-        goto skip;
-    if (strcmp(p, "/state") != 0 && strcmp(p, "/online") != 0)
-        goto skip;
-    /* Truncate the string so it points to the backend directory. */
-    *p = '\0';
-
-    /* Fetch the value of the state and online nodes. */
-    rc = libxl__xs_read_checked(gc, XBT_NULL, GCSPRINTF("%s/state", path),
-                                &sstate);
-    if (rc || !sstate)
-        goto skip;
-    state = atoi(sstate);
-
-    rc = libxl__xs_read_checked(gc, XBT_NULL, GCSPRINTF("%s/online", path),
-                                &sonline);
-    if (rc || !sonline)
-        goto skip;
-    online = atoi(sonline);
-
-    dev = libxl__zalloc(NOGC, sizeof(*dev));
-    rc = libxl__parse_backend_path(gc, path, dev);
-    if (rc)
-        goto skip;
-
-    dguest = search_for_guest(ddomain, dev->domid);
-    if (dguest == NULL && state == XenbusStateClosed) {
-        /*
-         * Spurious state change, device has already been disconnected
-         * or never attached.
-         */
-        goto skip;
-    }
-    if (dguest == NULL) {
-        /* Create a new guest struct and initialize it */
-        dguest = libxl__zalloc(NOGC, sizeof(*dguest));
-        dguest->domid = dev->domid;
-        LIBXL_SLIST_INIT(&dguest->devices);
-        LIBXL_SLIST_INSERT_HEAD(&ddomain->guests, dguest, next);
-        LOGD(DEBUG, dguest->domid, "Added domain to the list of active 
guests");
-    }
-    ddev = search_for_device(dguest, dev);
-    if (ddev == NULL && state == XenbusStateClosed) {
-        /*
-         * Spurious state change, device has already been disconnected
-         * or never attached.
-         */
-        goto skip;
-    } else if (ddev == NULL) {
-        /*
-         * New device addition, allocate a struct to hold it and add it
-         * to the list of active devices for a given guest.
-         */
-        ddev = libxl__zalloc(NOGC, sizeof(*ddev));
-        ddev->dev = dev;
-        LIBXL_SLIST_INSERT_HEAD(&dguest->devices, ddev, next);
-        LOGD(DEBUG, dev->domid, "Added device %s to the list of active 
devices",
-             path);
-        rc = add_device(egc, nested_ao, dguest, ddev);
-        if (rc > 0)
-            free_ao = true;
-    } else if (state == XenbusStateClosed && online == 0) {
-        /*
-         * Removal of an active device, remove it from the list and
-         * free it's data structures if they are no longer needed.
-         *
-         * The free of the associated libxl__device is left to the
-         * helper remove_device function.
-         */
-        LIBXL_SLIST_REMOVE(&dguest->devices, ddev, libxl__ddomain_device,
-                           next);
-        LOGD(DEBUG, dev->domid, "Removed device %s from the list of active 
devices",
-             path);
-        rc = remove_device(egc, nested_ao, dguest, ddev);
-        if (rc > 0)
-            free_ao = true;
-
-        free(ddev);
-        /* If this was the last device in the domain, remove it from the list 
*/
-        num_devs = dguest->num_vifs + dguest->num_vbds + dguest->num_qdisks;
-        if (num_devs == 0) {
-            LIBXL_SLIST_REMOVE(&ddomain->guests, dguest, libxl__ddomain_guest,
-                               next);
-            LOGD(DEBUG, dguest->domid, "Removed domain from the list of active 
guests");
-            /* Clear any leftovers in libxl/<domid> */
-            libxl__xs_rm_checked(gc, XBT_NULL,
-                                 GCSPRINTF("libxl/%u", dguest->domid));
-            free(dguest);
-        }
-    }
-
-    if (free_ao)
-        libxl__nested_ao_free(nested_ao);
-
-    return;
-
-skip:
-    libxl__nested_ao_free(nested_ao);
-    free(dev);
-    free(ddev);
-    free(dguest);
-    return;
-}
-
-/* Handler of events for device driver domains */
-int libxl_device_events_handler(libxl_ctx *ctx,
-                                const libxl_asyncop_how *ao_how)
-{
-    AO_CREATE(ctx, 0, ao_how);
-    int rc;
-    uint32_t domid;
-    libxl__ddomain ddomain;
-    char *be_path;
-    char **kinds = NULL, **domains = NULL, **devs = NULL;
-    const char *sstate;
-    char *state_path;
-    int state;
-    unsigned int nkinds, ndomains, ndevs;
-    int i, j, k;
-
-    ddomain.ao = ao;
-    LIBXL_SLIST_INIT(&ddomain.guests);
-
-    rc = libxl__get_domid(gc, &domid);
-    if (rc) {
-        LOG(ERROR, "unable to get domain id");
-        goto out;
-    }
-
-    /*
-     * We use absolute paths because we want xswatch to also return
-     * absolute paths that can be parsed by libxl__parse_backend_path.
-     */
-    be_path = GCSPRINTF("/local/domain/%u/backend", domid);
-    rc = libxl__ev_xswatch_register(gc, &ddomain.watch, backend_watch_callback,
-                                    be_path);
-    if (rc) goto out;
-
-    kinds = libxl__xs_directory(gc, XBT_NULL, be_path, &nkinds);
-    if (kinds) {
-        for (i = 0; i < nkinds; i++) {
-            domains = libxl__xs_directory(gc, XBT_NULL,
-                    GCSPRINTF("%s/%s", be_path, kinds[i]), &ndomains);
-            if (!domains)
-                continue;
-            for (j = 0; j < ndomains; j++) {
-                devs = libxl__xs_directory(gc, XBT_NULL,
-                        GCSPRINTF("%s/%s/%s", be_path, kinds[i], domains[j]), 
&ndevs);
-                if (!devs)
-                    continue;
-                for (k = 0; k < ndevs; k++) {
-                    state_path = GCSPRINTF("%s/%s/%s/%s/state",
-                            be_path, kinds[i], domains[j], devs[k]);
-                    rc = libxl__xs_read_checked(gc, XBT_NULL, state_path, 
&sstate);
-                    if (rc || !sstate)
-                        continue;
-                    state = atoi(sstate);
-                    if (state == XenbusStateInitWait)
-                        backend_watch_callback(egc, &ddomain.watch,
-                                               be_path, state_path);
-                }
-            }
-        }
-    }
-
-    return AO_INPROGRESS;
-
-out:
-    return AO_CREATE_FAIL(rc);
-}
-
-/******************************************************************************/
 int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
 {
     xc_physinfo_t xcphysinfo = { 0 };
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index b2aeefc..c72a2b8 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -1362,6 +1362,420 @@ int libxl__wait_for_backend(libxl__gc *gc, const char 
*be_path,
     return ERROR_FAIL;
 }
 
+/* generic callback for devices that only need to set ao_complete */
+void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+
+    if (aodev->rc) {
+        if (aodev->dev) {
+            LOGD(ERROR, aodev->dev->domid, "Unable to %s %s with id %u",
+                        libxl__device_action_to_string(aodev->action),
+                        libxl__device_kind_to_string(aodev->dev->kind),
+                        aodev->dev->devid);
+        } else {
+            LOG(ERROR, "unable to %s device",
+                       libxl__device_action_to_string(aodev->action));
+        }
+        goto out;
+    }
+
+out:
+    libxl__ao_complete(egc, ao, aodev->rc);
+    return;
+}
+
+/* common function to get next device id */
+int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device)
+{
+    char *libxl_dom_path, **l;
+    unsigned int nb;
+    int nextid = -1;
+
+    if (!(libxl_dom_path = libxl__xs_libxl_path(gc, domid)))
+        return nextid;
+
+    l = libxl__xs_directory(gc, XBT_NULL,
+        GCSPRINTF("%s/device/%s", libxl_dom_path, device),
+                            &nb);
+    if (l == NULL || nb == 0)
+        nextid = 0;
+    else
+        nextid = strtoul(l[nb - 1], NULL, 10) + 1;
+
+    return nextid;
+}
+
+static void device_complete(libxl__egc *egc, libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+
+    LOG(DEBUG, "device %s %s %s",
+               libxl__device_backend_path(gc, aodev->dev),
+               libxl__device_action_to_string(aodev->action),
+               aodev->rc ? "failed" : "succeed");
+
+    if (aodev->action == LIBXL__DEVICE_ACTION_REMOVE)
+        free(aodev->dev);
+
+    libxl__nested_ao_free(aodev->ao);
+}
+
+static void qdisk_spawn_outcome(libxl__egc *egc, libxl__dm_spawn_state *dmss,
+                                int rc)
+{
+    STATE_AO_GC(dmss->spawn.ao);
+
+    LOGD(DEBUG, dmss->guest_domid, "qdisk backend spawn %s",
+                rc ? "failed" : "succeed");
+
+    libxl__nested_ao_free(dmss->spawn.ao);
+}
+
+/*
+ * Data structures used to track devices handled by driver domains
+ */
+
+/*
+ * Structure that describes a device handled by a driver domain
+ */
+typedef struct libxl__ddomain_device {
+    libxl__device *dev;
+    LIBXL_SLIST_ENTRY(struct libxl__ddomain_device) next;
+} libxl__ddomain_device;
+
+/*
+ * Structure that describes a domain and it's associated devices
+ */
+typedef struct libxl__ddomain_guest {
+    uint32_t domid;
+    int num_vifs, num_vbds, num_qdisks;
+    LIBXL_SLIST_HEAD(, struct libxl__ddomain_device) devices;
+    LIBXL_SLIST_ENTRY(struct libxl__ddomain_guest) next;
+} libxl__ddomain_guest;
+
+/*
+ * Main structure used by a driver domain to keep track of devices
+ * currently in use
+ */
+typedef struct {
+    libxl__ao *ao;
+    libxl__ev_xswatch watch;
+    LIBXL_SLIST_HEAD(, struct libxl__ddomain_guest) guests;
+} libxl__ddomain;
+
+static libxl__ddomain_guest *search_for_guest(libxl__ddomain *ddomain,
+                                               uint32_t domid)
+{
+    libxl__ddomain_guest *dguest;
+
+    LIBXL_SLIST_FOREACH(dguest, &ddomain->guests, next) {
+        if (dguest->domid == domid)
+            return dguest;
+    }
+    return NULL;
+}
+
+static libxl__ddomain_device *search_for_device(libxl__ddomain_guest *dguest,
+                                                libxl__device *dev)
+{
+    libxl__ddomain_device *ddev;
+
+    LIBXL_SLIST_FOREACH(ddev, &dguest->devices, next) {
+#define LIBXL_DEVICE_CMP(dev1, dev2, entry) (dev1->entry == dev2->entry)
+        if (LIBXL_DEVICE_CMP(ddev->dev, dev, backend_devid) &&
+            LIBXL_DEVICE_CMP(ddev->dev, dev, backend_domid) &&
+            LIBXL_DEVICE_CMP(ddev->dev, dev, devid) &&
+            LIBXL_DEVICE_CMP(ddev->dev, dev, domid) &&
+            LIBXL_DEVICE_CMP(ddev->dev, dev, backend_kind) &&
+            LIBXL_DEVICE_CMP(ddev->dev, dev, kind))
+            return ddev;
+#undef LIBXL_DEVICE_CMP
+    }
+
+    return NULL;
+}
+
+/*
+ * The following comment applies to both add_device and remove_device.
+ *
+ * If the return value is greater than 0, it means there's no ao dispatched,
+ * so the free of the nested ao should be done by the parent when it has
+ * finished.
+ */
+static int add_device(libxl__egc *egc, libxl__ao *ao,
+                      libxl__ddomain_guest *dguest,
+                      libxl__ddomain_device *ddev)
+{
+    AO_GC;
+    libxl__device *dev = ddev->dev;
+    libxl__ao_device *aodev;
+    libxl__dm_spawn_state *dmss;
+    int rc = 0;
+
+    switch(dev->backend_kind) {
+    case LIBXL__DEVICE_KIND_VBD:
+    case LIBXL__DEVICE_KIND_VIF:
+        if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds++;
+        if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs++;
+
+        GCNEW(aodev);
+        libxl__prepare_ao_device(ao, aodev);
+        aodev->dev = dev;
+        aodev->action = LIBXL__DEVICE_ACTION_ADD;
+        aodev->callback = device_complete;
+        libxl__wait_device_connection(egc, aodev);
+
+        break;
+    case LIBXL__DEVICE_KIND_QDISK:
+        if (dguest->num_qdisks == 0) {
+            GCNEW(dmss);
+            dmss->guest_domid = dev->domid;
+            dmss->spawn.ao = ao;
+            dmss->callback = qdisk_spawn_outcome;
+
+            libxl__spawn_qdisk_backend(egc, dmss);
+        }
+        dguest->num_qdisks++;
+
+        break;
+    default:
+        rc = 1;
+        break;
+    }
+
+    return rc;
+}
+
+static int remove_device(libxl__egc *egc, libxl__ao *ao,
+                         libxl__ddomain_guest *dguest,
+                         libxl__ddomain_device *ddev)
+{
+    AO_GC;
+    libxl__device *dev = ddev->dev;
+    libxl__ao_device *aodev;
+    int rc = 0;
+
+    switch(ddev->dev->backend_kind) {
+    case LIBXL__DEVICE_KIND_VBD:
+    case LIBXL__DEVICE_KIND_VIF:
+        if (dev->backend_kind == LIBXL__DEVICE_KIND_VBD) dguest->num_vbds--;
+        if (dev->backend_kind == LIBXL__DEVICE_KIND_VIF) dguest->num_vifs--;
+
+        GCNEW(aodev);
+        libxl__prepare_ao_device(ao, aodev);
+        aodev->dev = dev;
+        aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
+        aodev->callback = device_complete;
+        libxl__initiate_device_generic_remove(egc, aodev);
+        break;
+    case LIBXL__DEVICE_KIND_QDISK:
+        if (--dguest->num_qdisks == 0) {
+            rc = libxl__destroy_qdisk_backend(gc, dev->domid);
+            if (rc)
+                goto out;
+        }
+        libxl__device_destroy(gc, dev);
+        free(dev);
+        /* Fall through to return > 0, no ao has been dispatched */
+    default:
+        rc = 1;
+        break;
+    }
+
+out:
+    return rc;
+}
+
+static void backend_watch_callback(libxl__egc *egc, libxl__ev_xswatch *watch,
+                                   const char *watch_path,
+                                   const char *event_path)
+{
+    libxl__ddomain *ddomain = CONTAINER_OF(watch, *ddomain, watch);
+    libxl__ao *nested_ao = libxl__nested_ao_create(ddomain->ao);
+    STATE_AO_GC(nested_ao);
+    char *p, *path;
+    const char *sstate, *sonline;
+    int state, online, rc, num_devs;
+    libxl__device *dev = NULL;
+    libxl__ddomain_device *ddev = NULL;
+    libxl__ddomain_guest *dguest = NULL;
+    bool free_ao = false;
+
+    /* Check if event_path ends with "state" or "online" and truncate it. */
+    path = libxl__strdup(gc, event_path);
+    p = strrchr(path, '/');
+    if (p == NULL)
+        goto skip;
+    if (strcmp(p, "/state") != 0 && strcmp(p, "/online") != 0)
+        goto skip;
+    /* Truncate the string so it points to the backend directory. */
+    *p = '\0';
+
+    /* Fetch the value of the state and online nodes. */
+    rc = libxl__xs_read_checked(gc, XBT_NULL, GCSPRINTF("%s/state", path),
+                                &sstate);
+    if (rc || !sstate)
+        goto skip;
+    state = atoi(sstate);
+
+    rc = libxl__xs_read_checked(gc, XBT_NULL, GCSPRINTF("%s/online", path),
+                                &sonline);
+    if (rc || !sonline)
+        goto skip;
+    online = atoi(sonline);
+
+    dev = libxl__zalloc(NOGC, sizeof(*dev));
+    rc = libxl__parse_backend_path(gc, path, dev);
+    if (rc)
+        goto skip;
+
+    dguest = search_for_guest(ddomain, dev->domid);
+    if (dguest == NULL && state == XenbusStateClosed) {
+        /*
+         * Spurious state change, device has already been disconnected
+         * or never attached.
+         */
+        goto skip;
+    }
+    if (dguest == NULL) {
+        /* Create a new guest struct and initialize it */
+        dguest = libxl__zalloc(NOGC, sizeof(*dguest));
+        dguest->domid = dev->domid;
+        LIBXL_SLIST_INIT(&dguest->devices);
+        LIBXL_SLIST_INSERT_HEAD(&ddomain->guests, dguest, next);
+        LOGD(DEBUG, dguest->domid, "Added domain to the list of active 
guests");
+    }
+    ddev = search_for_device(dguest, dev);
+    if (ddev == NULL && state == XenbusStateClosed) {
+        /*
+         * Spurious state change, device has already been disconnected
+         * or never attached.
+         */
+        goto skip;
+    } else if (ddev == NULL) {
+        /*
+         * New device addition, allocate a struct to hold it and add it
+         * to the list of active devices for a given guest.
+         */
+        ddev = libxl__zalloc(NOGC, sizeof(*ddev));
+        ddev->dev = dev;
+        LIBXL_SLIST_INSERT_HEAD(&dguest->devices, ddev, next);
+        LOGD(DEBUG, dev->domid, "Added device %s to the list of active 
devices",
+             path);
+        rc = add_device(egc, nested_ao, dguest, ddev);
+        if (rc > 0)
+            free_ao = true;
+    } else if (state == XenbusStateClosed && online == 0) {
+        /*
+         * Removal of an active device, remove it from the list and
+         * free it's data structures if they are no longer needed.
+         *
+         * The free of the associated libxl__device is left to the
+         * helper remove_device function.
+         */
+        LIBXL_SLIST_REMOVE(&dguest->devices, ddev, libxl__ddomain_device,
+                           next);
+        LOGD(DEBUG, dev->domid, "Removed device %s from the list of active 
devices",
+             path);
+        rc = remove_device(egc, nested_ao, dguest, ddev);
+        if (rc > 0)
+            free_ao = true;
+
+        free(ddev);
+        /* If this was the last device in the domain, remove it from the list 
*/
+        num_devs = dguest->num_vifs + dguest->num_vbds + dguest->num_qdisks;
+        if (num_devs == 0) {
+            LIBXL_SLIST_REMOVE(&ddomain->guests, dguest, libxl__ddomain_guest,
+                               next);
+            LOGD(DEBUG, dguest->domid, "Removed domain from the list of active 
guests");
+            /* Clear any leftovers in libxl/<domid> */
+            libxl__xs_rm_checked(gc, XBT_NULL,
+                                 GCSPRINTF("libxl/%u", dguest->domid));
+            free(dguest);
+        }
+    }
+
+    if (free_ao)
+        libxl__nested_ao_free(nested_ao);
+
+    return;
+
+skip:
+    libxl__nested_ao_free(nested_ao);
+    free(dev);
+    free(ddev);
+    free(dguest);
+    return;
+}
+
+/* Handler of events for device driver domains */
+int libxl_device_events_handler(libxl_ctx *ctx,
+                                const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, 0, ao_how);
+    int rc;
+    uint32_t domid;
+    libxl__ddomain ddomain;
+    char *be_path;
+    char **kinds = NULL, **domains = NULL, **devs = NULL;
+    const char *sstate;
+    char *state_path;
+    int state;
+    unsigned int nkinds, ndomains, ndevs;
+    int i, j, k;
+
+    ddomain.ao = ao;
+    LIBXL_SLIST_INIT(&ddomain.guests);
+
+    rc = libxl__get_domid(gc, &domid);
+    if (rc) {
+        LOG(ERROR, "unable to get domain id");
+        goto out;
+    }
+
+    /*
+     * We use absolute paths because we want xswatch to also return
+     * absolute paths that can be parsed by libxl__parse_backend_path.
+     */
+    be_path = GCSPRINTF("/local/domain/%u/backend", domid);
+    rc = libxl__ev_xswatch_register(gc, &ddomain.watch, backend_watch_callback,
+                                    be_path);
+    if (rc) goto out;
+
+    kinds = libxl__xs_directory(gc, XBT_NULL, be_path, &nkinds);
+    if (kinds) {
+        for (i = 0; i < nkinds; i++) {
+            domains = libxl__xs_directory(gc, XBT_NULL,
+                    GCSPRINTF("%s/%s", be_path, kinds[i]), &ndomains);
+            if (!domains)
+                continue;
+            for (j = 0; j < ndomains; j++) {
+                devs = libxl__xs_directory(gc, XBT_NULL,
+                        GCSPRINTF("%s/%s/%s", be_path, kinds[i], domains[j]), 
&ndevs);
+                if (!devs)
+                    continue;
+                for (k = 0; k < ndevs; k++) {
+                    state_path = GCSPRINTF("%s/%s/%s/%s/state",
+                            be_path, kinds[i], domains[j], devs[k]);
+                    rc = libxl__xs_read_checked(gc, XBT_NULL, state_path, 
&sstate);
+                    if (rc || !sstate)
+                        continue;
+                    state = atoi(sstate);
+                    if (state == XenbusStateInitWait)
+                        backend_watch_callback(egc, &ddomain.watch,
+                                               be_path, state_path);
+                }
+            }
+        }
+    }
+
+    return AO_INPROGRESS;
+
+out:
+    return AO_CREATE_FAIL(rc);
+}
+
 /*
  * Local variables:
  * mode: C
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

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