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

[Xen-devel] [PATCH 12 of 21 RESEND] blktap3/drivers: Introduce back-end image abstraction layer



This patch copies from blktap2 the functionality that allows back-end drivers
to be used transparently, with most changes coming from blkta2.5. Also, the
parent minor number is replaced with the parent /path/to/file in functions
__tapdisk_image_open_chain and tapdisk_image_open_chain, as there is no minor
number in blktap3.

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

diff --git a/tools/blktap2/drivers/tapdisk-image.c 
b/tools/blktap3/drivers/tapdisk-image.c
copy from tools/blktap2/drivers/tapdisk-image.c
copy to tools/blktap3/drivers/tapdisk-image.c
--- a/tools/blktap2/drivers/tapdisk-image.c
+++ b/tools/blktap3/drivers/tapdisk-image.c
@@ -25,22 +25,39 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
+
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
-#ifdef MEMSHR
-#include <memshr.h>
-#endif
+#include <stdio.h>
+#include <limits.h>
+#include <regex.h>
+#include <inttypes.h>
 
 #include "tapdisk-image.h"
 #include "tapdisk-driver.h"
 #include "tapdisk-server.h"
+#include "tapdisk-stats.h"
+#include "tapdisk-interface.h"
+#include "tapdisk-disktype.h"
+#include "tapdisk-storage.h"
 
+/* TODO already defined in tapdisk.h/tapdisk-log.h */
+#define DBG(_f, _a...)       tlog_syslog(TLOG_DBG, _f, ##_a)
+#define INFO(_f, _a...)      tlog_syslog(TLOG_INFO, _f, ##_a)
 #define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a)
 
-td_image_t *
-tapdisk_image_allocate(const char *file, int type, int storage,
-                      td_flag_t flags, void *private)
+#define BUG() td_panic()
+
+#define BUG_ON(_cond)                                          \
+       if (unlikely(_cond)) {                                  \
+               ERR(-EINVAL, "(%s) = %d", #_cond, _cond);       \
+               BUG();                                          \
+       }
+
+td_image_t *tapdisk_image_allocate(const char *file, const int type,
+                                   const td_flag_t flags)
 {
        int err;
        td_image_t *image;
@@ -57,27 +74,19 @@ tapdisk_image_allocate(const char *file,
 
        image->type      = type;
        image->flags     = flags;
-       image->storage   = storage;
-       image->private   = private;
-#ifdef MEMSHR
-       image->memshr_id = memshr_vbd_image_get(file);
-#endif
-       INIT_LIST_HEAD(&image->next);
 
        return image;
 }
 
 void
-tapdisk_image_free(td_image_t *image)
+tapdisk_image_free(td_image_t * image, struct tqh_td_image_handle *head)
 {
        if (!image)
                return;
 
-       list_del(&image->next);
+    if (head)
+        TAILQ_REMOVE(head, image, entry);
 
-#ifdef MEMSHR
-       memshr_vbd_image_put(image->memshr_id);
-#endif
        free(image->name);
        tapdisk_driver_free(image->driver);
        free(image);
@@ -86,9 +95,42 @@ tapdisk_image_free(td_image_t *image)
 int
 tapdisk_image_check_td_request(td_image_t *image, td_request_t treq)
 {
-       int rdonly;
+    int rdonly, err;
+       td_disk_info_t *info;
+
+    err = -EINVAL;
+
+    info = &image->info;
+       rdonly = td_flag_test(image->flags, TD_OPEN_RDONLY);
+
+       if (treq.op != TD_OP_READ && treq.op != TD_OP_WRITE)
+               goto fail;
+
+       if (treq.op == TD_OP_WRITE && rdonly)
+       {
+        err = -EPERM;
+               goto fail;
+    }
+
+       if (treq.secs <= 0 || treq.sec + treq.secs > info->size)
+               goto fail;
+
+       return 0;
+
+fail:
+       ERR(err, "bad td request on %s (%s, %" PRIu64 "): %d at %" PRIu64,
+           image->name, (rdonly ? "ro" : "rw"), info->size, treq.op,
+           treq.sec + treq.secs);
+       return err;
+
+}
+
+int
+tapdisk_image_check_request(td_image_t * image, td_vbd_request_t * vreq)
+{
        td_driver_t *driver;
        td_disk_info_t *info;
+    int i, rdonly, secs, err;
 
        driver = image->driver;
        if (!driver)
@@ -97,73 +139,442 @@ tapdisk_image_check_td_request(td_image_
        info   = &driver->info;
        rdonly = td_flag_test(image->flags, TD_OPEN_RDONLY);
 
-       if (treq.op != TD_OP_READ && treq.op != TD_OP_WRITE)
+    secs = 0;
+
+    if (vreq->iovcnt < 0) {
+        err = -EINVAL;
+        goto fail;
+    }
+
+    for (i = 0; i < vreq->iovcnt; i++)
+        secs += vreq->iov[i].secs;
+
+    switch (vreq->op) {
+    case TD_OP_WRITE:
+        if (rdonly) {
+            err = -EPERM;
+            goto fail;
+        }
+        /* continue */
+    case TD_OP_READ:
+        if (vreq->sec + secs > info->size) {
+            err = -EINVAL;
+            goto fail;
+        }
+        break;
+    default:
+        err = -EOPNOTSUPP;
+        goto fail;
+    }
+
+    return 0;
+
+  fail:
+    ERR(err,
+        "bad request on %s (%s, %" PRIu64 "): req %s op %d at %" PRIu64,
+        image->name, (rdonly ? "ro" : "rw"), info->size, vreq->name,
+        vreq->op, vreq->sec + secs);
+
+    return err;
+}
+
+void
+tapdisk_image_close(td_image_t * image, struct tqh_td_image_handle *head)
+{
+    td_close(image);
+    tapdisk_image_free(image, head);
+}
+
+int
+tapdisk_image_open(const int type, const char *name, const int flags,
+                   td_image_t ** _image)
+{
+    td_image_t *image;
+    int err;
+
+    image = tapdisk_image_allocate(name, type, flags);
+    if (!image) {
+        err = -ENOMEM;
+               goto fail;
+    }
+
+    err = td_load(image);
+    if (!err)
+        goto done;
+
+    image->driver = tapdisk_driver_allocate(image->type,
+                                            image->name, image->flags);
+    if (!image->driver) {
+        err = -ENOMEM;
+               goto fail;
+    }
+
+    err = td_open(image);
+    if (err) {
+        EPRINTF("failed to open image \'%s\': %s\n", image->name,
+                strerror(-err));
+               goto fail;
+    }
+
+done:
+    *_image = image;
+    return 0;
+
+fail:
+    if (image)
+        tapdisk_image_close(image, NULL);
+    return err;
+}
+
+/**
+ * Opens the parent of the image.
+ *
+ * @param image the image to open
+ * @param _parent output parameter that receives the parent
+ * @returns 0 on success
+ */
+static int
+tapdisk_image_open_parent(td_image_t * image, td_image_t ** _parent)
+{
+    td_image_t *parent = NULL;
+    td_disk_id_t id;
+    int err;
+
+    memset(&id, 0, sizeof(id));
+    id.flags = image->flags;
+
+    err = td_get_parent_id(image, &id);
+    if (err == TD_NO_PARENT) {
+        err = 0;
+        goto out;
+    }
+    if (err)
+        return err;
+               
+    err = tapdisk_image_open(id.type, id.name, id.flags, &parent);
+    if (err)
+        return err;
+
+  out:
+    *_parent = parent;
+    return 0;
+}
+
+/**
+ * Opens all parents of the image, adding them to the parent list (first is
+ * youngest).
+ *
+ * @param image the image whose parents to open
+ * @returns 0 on success
+ */
+static int
+tapdisk_image_open_parents(td_image_t * image,
+                           struct tqh_td_image_handle *head)
+{
+    td_image_t *parent;
+    int err;
+
+    do {
+        err = tapdisk_image_open_parent(image, &parent);
+        if (err)
+            break;
+
+        if (parent) {
+            TAILQ_INSERT_AFTER(head, image, parent, entry);
+            image = parent;
+        }
+    } while (parent);
+
+    return err;
+}
+
+void tapdisk_image_close_chain(struct tqh_td_image_handle *list)
+{
+    td_image_t *image, *next;
+
+    tapdisk_for_each_image_safe(image, next, list)
+        tapdisk_image_close(image, list);
+}
+
+/**
+ * Opens the image and all of its parents.
+ *
+ * @param type DISK_TYPE_* (see tapdisk-disktype.h)
+ * @param name /path/to/file
+ * @param flags
+ * @param _head
+ * @param prt_params parent type:/path/to/file (optional)
+ * @returns
+ */
+static int
+__tapdisk_image_open_chain(int type, const char *name, int flags,
+        struct tqh_td_image_handle *_head, const char *prt_path)
+{
+    struct tqh_td_image_handle head = TAILQ_HEAD_INITIALIZER(head);
+    td_image_t *image;
+    int err;
+
+    err = tapdisk_image_open(type, name, flags, &image);
+    if (err)
+        goto fail;
+
+    TAILQ_INSERT_TAIL(&head, image, entry);
+
+    if (unlikely(prt_path)) {
+        err = tapdisk_image_open(DISK_TYPE_AIO, prt_path,
+                flags | TD_OPEN_RDONLY, &image);
+        if (err)
+            goto fail;
+
+        TAILQ_INSERT_TAIL(&head, image, entry);
+        goto done;
+       }
+
+    err = tapdisk_image_open_parents(image, &head);
+    if (err)
                goto fail;
 
-       if (treq.op == TD_OP_WRITE && rdonly)
-               goto fail;
-
-       if (treq.secs <= 0 || treq.sec + treq.secs > info->size)
-               goto fail;
-
+done:
+    TAILQ_CONCAT(_head, &head, entry);
        return 0;
 
 fail:
-       ERR(-EINVAL, "bad td request on %s (%s, %"PRIu64"): %d at %"PRIu64,
-           image->name, (rdonly ? "ro" : "rw"), info->size, treq.op,
-           treq.sec + treq.secs);
+    tapdisk_image_close_chain(&head);
+    return err;
+}
+
+static int tapdisk_image_parse_flags(char *args, unsigned long *_flags)
+{
+    unsigned long flags = 0;
+    char *token;
+
+    BUG_ON(!args);
+
+    do {
+        token = strtok(args, ",");
+        if (!token)
+            break;
+
+        switch (token[0]) {
+        case 'r':
+            if (!strcmp(token, "ro")) {
+                flags |= TD_OPEN_RDONLY;
+                break;
+            }
+            goto fail;
+
+        default:
+            goto fail;
+        }
+
+        args = NULL;
+    } while (1);
+
+    *_flags |= flags;
+
+    return 0;
+
+  fail:
+    ERR(-EINVAL, "Invalid token '%s'", token);
        return -EINVAL;
+}
 
+/**
+ * TODO opens the image chain?
+ */
+static int
+tapdisk_image_open_x_chain(const char *path,
+                           struct tqh_td_image_handle *_head)
+{
+    struct tqh_td_image_handle head = TAILQ_HEAD_INITIALIZER(head);
+    td_image_t *image = NULL, *next;
+    regex_t _im, *im = NULL, _ws, *ws = NULL;
+    FILE *s;
+    int err;
+
+    s = fopen(path, "r");
+    if (!s) {
+        err = -errno;
+        goto fail;
+    }
+
+    err = regcomp(&_ws, "^[:space:]*$", REG_NOSUB);
+    if (err)
+        goto fail;
+    ws = &_ws;
+
+    err = regcomp(&_im,
+                  "^([^:]+):([^ \t]+)([ \t]+([a-z,]+))?",
+                  REG_EXTENDED | REG_NEWLINE);
+    if (err)
+        goto fail;
+    im = &_im;
+
+    do {
+        char line[512], *l;
+        regmatch_t match[5];
+        char *typename, *path, *args = NULL;
+        unsigned long flags;
+        int type;
+
+        l = fgets(line, sizeof(line), s);
+        if (!l)
+            break;
+
+        err = regexec(im, line, ARRAY_SIZE(match), match, 0);
+        if (err) {
+            err = regexec(ws, line, ARRAY_SIZE(match), match, 0);
+            if (!err)
+                continue;
+            err = -EINVAL;
+            goto fail;
+        }
+
+        line[match[1].rm_eo] = 0;
+        typename = line + match[1].rm_so;
+
+        line[match[2].rm_eo] = 0;
+        path = line + match[2].rm_so;
+
+        if (match[4].rm_so >= 0) {
+            line[match[4].rm_eo] = 0;
+            args = line + match[4].rm_so;
+        }
+
+        type = tapdisk_disktype_find(typename);
+        if (type < 0) {
+            err = type;
+            goto fail;
+        }
+
+        flags = 0;
+
+        if (args) {
+            err = tapdisk_image_parse_flags(args, &flags);
+            if (err)
+                goto fail;
+        }
+
+        err = tapdisk_image_open(type, path, flags, &image);
+        if (err)
+            goto fail;
+
+        TAILQ_INSERT_TAIL(&head, image, entry);
+    } while (1);
+
+    if (!image) {
+        err = -EINVAL;
+        goto fail;
+    }
+
+    err = tapdisk_image_open_parents(image, &head);
+    if (err)
+        goto fail;
+
+    TAILQ_CONCAT(&head, _head, entry);
+  out:
+    if (im)
+        regfree(im);
+    if (ws)
+        regfree(ws);
+    if (s)
+        fclose(s);
+
+    return err;
+
+  fail:
+    tapdisk_for_each_image_safe(image, next, &head)
+        tapdisk_image_free(image, &head);
+
+    goto out;
 }
 
 int
-tapdisk_image_check_ring_request(td_image_t *image, blkif_request_t *req)
+tapdisk_image_open_chain(const char *params, int flags, const char * prt_path,
+        struct tqh_td_image_handle *head)
 {
-       td_driver_t *driver;
-       td_disk_info_t *info;
-       int i, psize, rdonly;
-       uint64_t nsects, total;
+    const char *name;
+    int type, err;
 
-       driver = image->driver;
-       if (!driver)
-               return -ENODEV;
+    type = tapdisk_disktype_parse_params(params, &name);
+    if (type >= 0) {
+        err = __tapdisk_image_open_chain(type, name, flags, head, prt_path);
+        BUG_ON(TAILQ_EMPTY(head));
+        return err;
+    }
 
-       nsects = 0;
-       total  = 0;
-       info   = &driver->info;
+    err = type;
 
-       rdonly = td_flag_test(image->flags, TD_OPEN_RDONLY);
+    if (err == -ENOENT && strlen(params) >= 3) {
+        switch (params[2]) {
+        case 'c':
+            if (!strncmp(params, "x-chain", strlen("x-chain")))
+                err = tapdisk_image_open_x_chain(name, head);
+            break;
+        }
+    }
 
-       if (req->operation != BLKIF_OP_READ &&
-           req->operation != BLKIF_OP_WRITE)
-               goto fail;
+    return err;
+}
 
-       if (req->operation == BLKIF_OP_WRITE && rdonly)
-               goto fail;
+int tapdisk_image_validate_chain(struct tqh_td_image_handle *head)
+{
+    td_image_t *image, *parent;
+    int flags, err;
 
-       if (!req->nr_segments || req->nr_segments > MAX_SEGMENTS_PER_REQ)
-               goto fail;
+    INFO("VBD CHAIN:\n");
 
-       total = 0;
-       psize = getpagesize();
+    tapdisk_for_each_image_reverse(parent, head) {
+        image = TAILQ_PREV(parent, tqh_td_image_handle, entry);
 
-       for (i = 0; i < req->nr_segments; i++) {
-               nsects = req->seg[i].last_sect - req->seg[i].first_sect + 1;
-               
-               if (req->seg[i].last_sect >= psize >> 9 || nsects <= 0)
-                       goto fail;
+        /*
+         * FIXME this was: image == TAILQ_FIRST(head), not sure if the new
+         * check is correct
+         */
+        if (image == NULL)
+            break;
 
-               total += nsects;
-       }
+        err = td_validate_parent(image, parent);
+        if (err)
+            return err;
 
-       if (req->sector_number + nsects > info->size)
-               goto fail;
+        flags = tapdisk_disk_types[image->type]->flags;
+        if (flags & DISK_TYPE_FILTER) {
+            image->driver->info = parent->driver->info;
+            image->info = parent->info;
+        }
+    }
 
-       return 0;
+    tapdisk_for_each_image(image, head) {
+        INFO("%s: type:%s(%d) storage:%s(%d)\n",
+             image->name,
+             tapdisk_disk_types[image->type]->name,
+             image->type,
+             tapdisk_storage_name(image->driver->storage),
+             image->driver->storage);
+    }
 
-fail:
-       ERR(-EINVAL, "bad request on %s (%s, %"PRIu64"): id: %"PRIu64": %d at 
%"PRIu64,
-           image->name, (rdonly ? "ro" : "rw"), info->size, req->id,
-           req->operation, req->sector_number + total);
-       return -EINVAL;
+    return 0;
 }
+
+void tapdisk_image_stats(td_image_t * image, td_stats_t * st)
+{
+    tapdisk_stats_enter(st, '{');
+    tapdisk_stats_field(st, "name", "s", image->name);
+
+    tapdisk_stats_field(st, "hits", "[");
+    tapdisk_stats_val(st, "llu", image->stats.hits.rd);
+    tapdisk_stats_val(st, "llu", image->stats.hits.wr);
+    tapdisk_stats_leave(st, ']');
+
+    tapdisk_stats_field(st, "fail", "[");
+    tapdisk_stats_val(st, "llu", image->stats.fail.rd);
+    tapdisk_stats_val(st, "llu", image->stats.fail.wr);
+    tapdisk_stats_leave(st, ']');
+
+    tapdisk_stats_field(st, "driver", "{");
+    tapdisk_driver_stats(image->driver, st);
+    tapdisk_stats_leave(st, '}');
+
+    tapdisk_stats_leave(st, '}');
+}
diff --git a/tools/blktap2/drivers/tapdisk-interface.c 
b/tools/blktap3/drivers/tapdisk-interface.c
copy from tools/blktap2/drivers/tapdisk-interface.c
copy to tools/blktap3/drivers/tapdisk-interface.c
--- a/tools/blktap2/drivers/tapdisk-interface.c
+++ b/tools/blktap3/drivers/tapdisk-interface.c
@@ -25,6 +25,9 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
+#include <signal.h>
+#include <unistd.h>
 #include <errno.h>
 
 #include "tapdisk.h"
@@ -33,11 +36,11 @@
 #include "tapdisk-driver.h"
 #include "tapdisk-server.h"
 #include "tapdisk-interface.h"
+#include "tapdisk-log.h"
 
 int
 td_load(td_image_t *image)
 {
-       int err;
        td_image_t *shared;
        td_driver_t *driver;
 
@@ -68,8 +71,7 @@ int
        if (!driver) {
                driver = tapdisk_driver_allocate(image->type,
                                                 image->name,
-                                                image->flags,
-                                                image->storage);
+                                                image->flags);
                if (!driver)
                        return -ENOMEM;
 
@@ -86,9 +88,10 @@ int
                }
 
                td_flag_set(driver->state, TD_DRIVER_OPEN);
-               DPRINTF("opened image %s (%d users, state: 0x%08x, type: %d)\n",
-                       driver->name, driver->refcnt + 1,
-                       driver->state, driver->type);
+               DPRINTF("opened image %s (%d users, state: 0x%08x, type: %d, 
%s)\n",
+               driver->name, driver->refcnt + 1,
+               driver->state, driver->type,
+             td_flag_test(image->flags, TD_OPEN_RDONLY) ? "ro" : "rw");
        }
 
        image->driver = driver;
@@ -104,7 +107,7 @@ td_open(td_image_t *image)
 }
 
 int
-td_close(td_image_t *image)
+td_close(td_image_t * image)
 {
        td_driver_t *driver;
 
@@ -153,6 +156,7 @@ td_validate_parent(td_image_t *image, td
            !td_flag_test(pdriver->state, TD_DRIVER_OPEN))
                return -EBADF;
 
+    /* TODO wtf? */
        return 0;
        return driver->ops->td_validate_parent(driver, pdriver, 0);
 }
@@ -174,6 +178,11 @@ td_queue_write(td_image_t *image, td_req
                goto fail;
        }
 
+    if (!driver->ops->td_queue_write) {
+        err = -EOPNOTSUPP;
+        goto fail;
+    }
+
        err = tapdisk_image_check_td_request(image, treq);
        if (err)
                goto fail;
@@ -202,6 +211,11 @@ td_queue_read(td_image_t *image, td_requ
                goto fail;
        }
 
+    if (!driver->ops->td_queue_read) {
+        err = -EOPNOTSUPP;
+        goto fail;
+    }
+
        err = tapdisk_image_check_td_request(image, treq);
        if (err)
                goto fail;
@@ -222,7 +236,7 @@ td_forward_request(td_request_t treq)
 void
 td_complete_request(td_request_t treq, int res)
 {
-       ((td_callback_t)treq.cb)(treq, res);
+    treq.cb(treq, res);
 }
 
 void
@@ -257,3 +271,13 @@ td_debug(td_image_t *image)
 
        tapdisk_driver_debug(driver);
 }
+
+__attribute__ ((noreturn))
+void td_panic(void)
+{
+    tlog_precious();
+    raise(SIGABRT);
+
+    /* TODO delete? */
+    _exit(-1);                  /* not reached */
+}
diff --git a/tools/blktap2/drivers/tapdisk-interface.h 
b/tools/blktap3/drivers/tapdisk-interface.h
copy from tools/blktap2/drivers/tapdisk-interface.h
copy to tools/blktap3/drivers/tapdisk-interface.h
--- a/tools/blktap2/drivers/tapdisk-interface.h
+++ b/tools/blktap3/drivers/tapdisk-interface.h
@@ -50,5 +50,6 @@ void td_prep_read(struct tiocb *, int, c
                  long long, td_queue_callback_t, void *);
 void td_prep_write(struct tiocb *, int, char *, size_t,
                   long long, td_queue_callback_t, void *);
+void td_panic(void) __attribute__ ((noreturn));
 
 #endif

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