[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 |