|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |