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

[Xen-devel] [PATCH 04 of 15 v4] blktap3/libblktapctl: Introduce listing running tapdisks functionality



This patch introduces tap-ctl-list.c, the file where listing tapdisks
functionality is implemented. It is based on the existing blktap2 file with
most changes coming from blktap2 living in github. I have not examined the
changes in detail but it seems they are minor.

Function tap_ctl_list needs to be amended because minors are not retrieved
from sysfs (there's no sysfs blktap directory any more).

Signed-off-by: Thanos Makatos <thanos.makatos@xxxxxxxxxx>

diff --git a/tools/blktap2/control/tap-ctl-list.c 
b/tools/blktap3/control/tap-ctl-list.c
copy from tools/blktap2/control/tap-ctl-list.c
copy to tools/blktap3/control/tap-ctl-list.c
--- a/tools/blktap2/control/tap-ctl-list.c
+++ b/tools/blktap3/control/tap-ctl-list.c
@@ -34,23 +34,47 @@
 #include <glob.h>
 
 #include "tap-ctl.h"
-#include "blktap2.h"
-#include "list.h"
+#include "blktap3.h"
+
+/**
+ * Allocates and initializes a tap_list_t.
+ */
+static tap_list_t *
+_tap_list_alloc(void)
+{
+       const size_t sz = sizeof(tap_list_t);
+       tap_list_t *tl;
+
+       tl = malloc(sz);
+       if (!tl)
+               return NULL;
+
+       tl->pid = -1;
+       tl->minor = -1;
+       tl->state = -1;
+       tl->type = NULL;
+       tl->path = NULL;
+
+       return tl;
+}
 
 static void
-free_list(tap_list_t *entry)
+_tap_list_free(tap_list_t * tl, struct tqh_tap_list *list)
 {
-       if (entry->type) {
-               free(entry->type);
-               entry->type = NULL;
+       if (tl->type) {
+               free(tl->type);
+               tl->type = NULL;
        }
 
-       if (entry->path) {
-               free(entry->path);
-               entry->path = NULL;
+       if (tl->path) {
+               free(tl->path);
+               tl->path = NULL;
        }
 
-       free(entry);
+       if (list)
+               TAILQ_REMOVE(list, tl, entry);
+
+       free(tl);
 }
 
 int
@@ -66,7 +90,7 @@ int
        len = ptr - params;
 
        *type = strndup(params, len);
-       *path =  strdup(params + len + 1);
+       *path = strdup(params + len + 1);
 
        if (!*type || !*path) {
                free(*type);
@@ -81,102 +105,26 @@ int
        return 0;
 }
 
-static int
-init_list(tap_list_t *entry,
-         int tap_id, pid_t tap_pid, int vbd_minor, int vbd_state,
-         const char *params)
+void
+tap_ctl_list_free(struct tqh_tap_list *list)
 {
-       int err = 0;
+       tap_list_t *tl, *n;
 
-       entry->id     = tap_id;
-       entry->pid    = tap_pid;
-       entry->minor  = vbd_minor;
-       entry->state  = vbd_state;
-
-       if (params)
-               err = _parse_params(params, &entry->type, &entry->path);
-
-       return err;
-}
-
-void
-tap_ctl_free_list(tap_list_t **list)
-{
-       tap_list_t **_entry;
-
-       for (_entry = list; *_entry != NULL; ++_entry)
-               free_list(*_entry);
-
-       free(list);
-}
-
-static tap_list_t**
-tap_ctl_alloc_list(int n)
-{
-       tap_list_t **list, *entry;
-       size_t size;
-       int i;
-
-       size = sizeof(tap_list_t*) * (n+1);
-       list = malloc(size);
-       if (!list)
-               goto fail;
-
-       memset(list, 0, size);
-
-       for (i = 0; i < n; ++i) {
-               tap_list_t *entry;
-
-               entry = malloc(sizeof(tap_list_t));
-               if (!entry)
-                       goto fail;
-
-               memset(entry, 0, sizeof(tap_list_t));
-
-               list[i] = entry;
-       }
-
-       return list;
-
-fail:
-       if (list)
-               tap_ctl_free_list(list);
-
-       return NULL;
-}
-
-static int
-tap_ctl_list_length(const tap_list_t **list)
-{
-       const tap_list_t **_entry;
-       int n;
-
-       n = 0;
-       for (_entry = list; *_entry != NULL; ++_entry)
-               n++;
-
-       return n;
-}
-
-static int
-_tap_minor_cmp(const void *a, const void *b)
-{
-       return *(int*)a - *(int*)b;
+       tap_list_for_each_entry_safe(tl, n, list)
+               _tap_list_free(tl, list);
 }
 
 int
-_tap_ctl_find_minors(int **_minorv)
+_tap_ctl_find_tapdisks(struct tqh_tap_list *list)
 {
-       glob_t glbuf = { 0 };
+       glob_t glbuf = { 0 };   
        const char *pattern, *format;
-       int *minorv = NULL, n_minors = 0;
-       int err, i;
+       int err, i, n_taps = 0;
 
-       pattern = BLKTAP2_SYSFS_DIR"/blktap*";
-       format  = BLKTAP2_SYSFS_DIR"/blktap%d";
+       pattern = BLKTAP3_CONTROL_DIR "/" BLKTAP3_CONTROL_SOCKET "*";
+       format = BLKTAP3_CONTROL_DIR "/" BLKTAP3_CONTROL_SOCKET "%d";
 
-       n_minors = 0;
-       minorv   = NULL;
+       TAILQ_INIT(list);
 
        err = glob(pattern, 0, NULL, &glbuf);
        switch (err) {
@@ -186,337 +134,231 @@ int
        case GLOB_ABORTED:
        case GLOB_NOSPACE:
                err = -errno;
-               EPRINTF("%s: glob failed, err %d", pattern, err);
-               goto fail;
-       }
-
-       minorv = malloc(sizeof(int) * glbuf.gl_pathc);
-       if (!minorv) {
-               err = -errno;
+               EPRINTF("%s: glob failed: %s", pattern, strerror(err));
                goto fail;
        }
 
        for (i = 0; i < glbuf.gl_pathc; ++i) {
+               tap_list_t *tl;
                int n;
 
-               n = sscanf(glbuf.gl_pathv[i], format, &minorv[n_minors]);
+               tl = _tap_list_alloc();
+               if (!tl) {
+                       err = -ENOMEM;
+                       goto fail;
+               }
+
+               n = sscanf(glbuf.gl_pathv[i], format, &tl->pid);
                if (n != 1)
-                       continue;
+                       goto skip;
 
-               n_minors++;
+               tl->pid = tap_ctl_get_pid(tl->pid);
+               if (tl->pid < 0)
+                       goto skip;
+
+               TAILQ_INSERT_TAIL(list, tl, entry);
+               n_taps++;
+               continue;
+
+         skip:
+               _tap_list_free(tl, NULL);
        }
 
-       qsort(minorv, n_minors, sizeof(int), _tap_minor_cmp);
-
-done:
-       *_minorv = minorv;
+  done:
        err = 0;
-
-out:
-       if (glbuf.gl_pathv)
-               globfree(&glbuf);
-
-       return err ? : n_minors;
-
-fail:
-       if (minorv)
-               free(minorv);
-
-       goto out;
-}
-
-struct tapdisk {
-       int    id;
-       pid_t  pid;
-       struct list_head list;
-};
-
-static int
-_tap_tapdisk_cmp(const void *a, const void *b)
-{
-       return ((struct tapdisk*)a)->id - ((struct tapdisk*)b)->id;
-}
-
-int
-_tap_ctl_find_tapdisks(struct tapdisk **_tapv)
-{
-       glob_t glbuf = { 0 };
-       const char *pattern, *format;
-       struct tapdisk *tapv = NULL;
-       int err, i, n_taps = 0;
-
-       pattern = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"*";
-       format  = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"%d";
-
-       n_taps = 0;
-       tapv   = NULL;
-
-       err = glob(pattern, 0, NULL, &glbuf);
-       switch (err) {
-       case GLOB_NOMATCH:
-               goto done;
-
-       case GLOB_ABORTED:
-       case GLOB_NOSPACE:
-               err = -errno;
-               EPRINTF("%s: glob failed, err %d", pattern, err);
-               goto fail;
-       }
-
-       tapv = malloc(sizeof(struct tapdisk) * glbuf.gl_pathc);
-       if (!tapv) {
-               err = -errno;
-               goto fail;
-       }
-
-       for (i = 0; i < glbuf.gl_pathc; ++i) {
-               struct tapdisk *tap;
-               int n;
-
-               tap = &tapv[n_taps];
-
-               err = sscanf(glbuf.gl_pathv[i], format, &tap->id);
-               if (err != 1)
-                       continue;
-
-               tap->pid = tap_ctl_get_pid(tap->id);
-               if (tap->pid < 0)
-                       continue;
-
-               n_taps++;
-       }
-
-       qsort(tapv, n_taps, sizeof(struct tapdisk), _tap_tapdisk_cmp);
-
-       for (i = 0; i < n_taps; ++i)
-               INIT_LIST_HEAD(&tapv[i].list);
-
-done:
-       *_tapv = tapv;
-       err = 0;
-
-out:
+  out:
        if (glbuf.gl_pathv)
                globfree(&glbuf);
 
        return err ? : n_taps;
 
-fail:
-       if (tapv)
-               free(tapv);
-
+  fail:
+       tap_ctl_list_free(list);
        goto out;
 }
 
-struct tapdisk_list {
-       int  minor;
-       int  state;
-       char *params;
-       struct list_head entry;
-};
-
-int
-_tap_ctl_list_tapdisk(int id, struct list_head *_list)
+/**
+ * Retrieves all the VBDs a tapdisk is serving.
+ *
+ * @param pid the process ID of the tapdisk whose VBDs should be retrieved
+ * @param list output parameter that receives the list of VBD
+ * @returns 0 on success, an error code otherwise
+ */
+static int
+_tap_ctl_list_tapdisk(pid_t pid, struct tqh_tap_list *list)
 {
+       struct timeval timeout = {.tv_sec = 10,.tv_usec = 0 };
        tapdisk_message_t message;
-       struct list_head list;
-       struct tapdisk_list *tl, *next;
+       tap_list_t *tl;
        int err, sfd;
 
-       err = tap_ctl_connect_id(id, &sfd);
+       err = tap_ctl_connect_id(pid, &sfd);
        if (err)
                return err;
 
        memset(&message, 0, sizeof(message));
-       message.type   = TAPDISK_MESSAGE_LIST;
+       message.type = TAPDISK_MESSAGE_LIST;
        message.cookie = -1;
 
-       err = tap_ctl_write_message(sfd, &message, 2);
+       err = tap_ctl_write_message(sfd, &message, &timeout);
        if (err)
                return err;
 
-       INIT_LIST_HEAD(&list);
+       TAILQ_INIT(list);
+
        do {
-               err = tap_ctl_read_message(sfd, &message, 2);
+               err = tap_ctl_read_message(sfd, &message, &timeout);
                if (err) {
                        err = -EPROTO;
-                       break;
+                       goto fail;
                }
 
                if (message.u.list.count == 0)
                        break;
 
-               tl = malloc(sizeof(struct tapdisk_list));
+               tl = _tap_list_alloc();
                if (!tl) {
                        err = -ENOMEM;
-                       break;
+                       goto fail;
                }
 
-               tl->minor  = message.u.list.minor;
-               tl->state  = message.u.list.state;
+               tl->pid = pid;
+               tl->minor = message.u.list.minor;
+               tl->state = message.u.list.state;
+
                if (message.u.list.path[0] != 0) {
-                       tl->params = strndup(message.u.list.path,
-                                            sizeof(message.u.list.path));
-                       if (!tl->params) {
-                               err = -errno;
-                               break;
+                       err = _parse_params(message.u.list.path, &tl->type, 
&tl->path);
+                       if (err) {
+                               _tap_list_free(tl, NULL);
+                               goto fail;
                        }
-               } else
-                       tl->params = NULL;
+               }
 
-               list_add(&tl->entry, &list);
+               TAILQ_INSERT_HEAD(list, tl, entry);
        } while (1);
 
-       if (err)
-               list_for_each_entry_safe(tl, next, &list, entry) {
-                       list_del(&tl->entry);
-                       free(tl->params);
-                       free(tl);
-               }
+       err = 0;
+  out:
+       close(sfd);
+       return 0;
 
-       close(sfd);
-       list_splice(&list, _list);
-       return err;
-}
-
-void
-_tap_ctl_free_tapdisks(struct tapdisk *tapv, int n_taps)
-{
-       struct tapdisk *tap;
-
-       for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
-               struct tapdisk_list *tl, *next;
-
-               list_for_each_entry_safe(tl, next, &tap->list, entry) {
-                       free(tl->params);
-                       free(tl);
-               }
-       }
-
-       free(tapv);
+  fail:
+       tap_ctl_list_free(list);
+       goto out;
 }
 
 int
-_tap_list_join3(int n_minors, int *minorv, int n_taps, struct tapdisk *tapv,
-               tap_list_t ***_list)
+tap_ctl_list(struct tqh_tap_list *list)
 {
-       tap_list_t **list, **_entry, *entry;
-       int i, _m, err;
+       struct tqh_tap_list minors, tapdisks, vbds;
+       tap_list_t *t, *next_t, *v, *next_v, *m, *next_m;
+       int err;
 
-       list = tap_ctl_alloc_list(n_minors + n_taps);
-       if (!list) {
-               err = -ENOMEM;
+       /*
+        * Find all minors, find all tapdisks, then list all minors
+        * they attached to. Output is a 3-way outer join.
+        */
+       TAILQ_INIT(&minors);
+
+       /*
+        * TODO There's no blktap sysfs entry anymore, get rid of minors and
+        * rationalise the rest of this function.
+        */
+#if 0
+       err = _tap_ctl_find_minors(&minors);
+       if (err < 0) {
+               EPRINTF("error finding minors: %s\n", strerror(err));
+               goto fail;
+       }
+#endif
+
+       err = _tap_ctl_find_tapdisks(&tapdisks);
+       if (err < 0) {
+               EPRINTF("error finding tapdisks: %s\n", strerror(err));
                goto fail;
        }
 
-       _entry = list;
+       TAILQ_INIT(list);
 
-       for (i = 0; i < n_taps; ++i) {
-               struct tapdisk *tap = &tapv[i];
-               struct tapdisk_list *tl;
+       tap_list_for_each_entry_safe(t, next_t, &tapdisks) {
 
-               /* orphaned tapdisk */
-               if (list_empty(&tap->list)) {
-                       err = init_list(*_entry++, tap->id, tap->pid, -1, -1, 
NULL);
-                       if (err)
-                               goto fail;
+               err = _tap_ctl_list_tapdisk(t->pid, &vbds);
+
+               /*
+                * TODO Don't just swallow the error, print a warning, at least.
+                */
+               if (err || TAILQ_EMPTY(&vbds)) {
+                       TAILQ_MOVE_TAIL(t, &tapdisks, list, entry);
                        continue;
                }
 
-               list_for_each_entry(tl, &tap->list, entry) {
+               tap_list_for_each_entry_safe(v, next_v, &vbds) {
 
-                       err = init_list(*_entry++,
-                                       tap->id, tap->pid,
-                                       tl->minor, tl->state, tl->params);
-                       if (err)
-                               goto fail;
+                       tap_list_for_each_entry_safe(m, next_m, &minors)
+                               if (m->minor == v->minor) {
+                               _tap_list_free(m, &minors);
+                               break;
+                       }
 
-                       if (tl->minor >= 0) {
-                               /* clear minor */
-                               for (_m = 0; _m < n_minors; ++_m) {
-                                       if (minorv[_m] == tl->minor) {
-                                               minorv[_m] = -1;
-                                               break;
-                                       }
-                               }
-                       }
+                       TAILQ_MOVE_TAIL(v, &vbds, list, entry);
                }
+
+               _tap_list_free(t, &tapdisks);
        }
 
        /* orphaned minors */
-       for (_m = 0; _m < n_minors; ++_m) {
-               int minor = minorv[_m];
-               if (minor >= 0) {
-                       err = init_list(*_entry++, -1, -1, minor, -1, NULL);
-                       if (err)
-                               goto fail;
-               }
-       }
-
-       /* free extraneous list entries */
-       for (; *_entry != NULL; ++entry) {
-               free_list(*_entry);
-               *_entry = NULL;
-       }
-
-       *_list = list;
+       TAILQ_CONCAT(list, &minors, entry);
 
        return 0;
 
 fail:
-       if (list)
-               tap_ctl_free_list(list);
+       tap_ctl_list_free(list);
+
+       tap_ctl_list_free(&vbds);
+       tap_ctl_list_free(&tapdisks);
+       tap_ctl_list_free(&minors);
 
        return err;
 }
 
 int
-tap_ctl_list(tap_list_t ***list)
+tap_ctl_list_pid(pid_t pid, struct tqh_tap_list *list)
 {
-       int n_taps, n_minors, err, *minorv;
-       struct tapdisk *tapv, *tap;
+       tap_list_t *t;
+       int err;
 
-       n_taps   = -1;
-       n_minors = -1;
+       t = _tap_list_alloc();
+       if (!t)
+               return -ENOMEM;
 
-       err = n_minors = _tap_ctl_find_minors(&minorv);
-       if (err < 0)
-               goto out;
-
-       err = n_taps = _tap_ctl_find_tapdisks(&tapv);
-       if (err < 0)
-               goto out;
-
-       for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
-               err = _tap_ctl_list_tapdisk(tap->id, &tap->list);
-               if (err)
-                       goto out;
+       t->pid = tap_ctl_get_pid(pid);
+       if (t->pid < 0) {
+               _tap_list_free(t, NULL);
+               return 0;
        }
 
-       err = _tap_list_join3(n_minors, minorv, n_taps, tapv, list);
+       err = _tap_ctl_list_tapdisk(t->pid, list);
 
-out:
-       if (n_taps > 0)
-               _tap_ctl_free_tapdisks(tapv, n_taps);
+       if (err || TAILQ_EMPTY(list))
+               TAILQ_INSERT_TAIL(list, t, entry);
 
-       if (n_minors > 0)
-               free(minorv);
-
-       return err;
+       return 0;
 }
 
 int
-tap_ctl_find(const char *type, const char *path, tap_list_t *tap)
+tap_ctl_find_minor(const char *type, const char *path)
 {
-       tap_list_t **list, **_entry;
-       int ret = -ENOENT, err;
+       struct tqh_tap_list list = TAILQ_HEAD_INITIALIZER(list);
+       tap_list_t *entry;
+       int minor, err;
 
        err = tap_ctl_list(&list);
        if (err)
                return err;
 
-       for (_entry = list; *_entry != NULL; ++_entry) {
-               tap_list_t *entry  = *_entry;
+       minor = -1;
+
+       tap_list_for_each_entry(entry, &list) {
 
                if (type && (!entry->type || strcmp(entry->type, type)))
                        continue;
@@ -524,13 +366,11 @@ tap_ctl_find(const char *type, const cha
                if (path && (!entry->path || strcmp(entry->path, path)))
                        continue;
 
-               *tap = *entry;
-               tap->type = tap->path = NULL;
-               ret = 0;
+               minor = entry->minor;
                break;
        }
 
-       tap_ctl_free_list(list);
+       tap_ctl_list_free(&list);
 
-       return ret;
+       return minor >= 0 ? minor : -ENOENT;
 }

_______________________________________________
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®.