[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] blktap2: configurable driver chains
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1257795614 0 # Node ID 94c3f3d4b864bf74801bffb384d7354142850709 # Parent f6091947ffed5707b60120fe44d3d038a3307591 blktap2: configurable driver chains Blktap2 allows block device drivers to be layered to create more advanced virtual block devices. However, composing a layered driver is not exposed to the user. This patch fixes this, and allows the user to explicitly specify a driver chain when starting a tapdisk process, using the pipe character ('|') to explicitly seperate layers in a blktap2 configuration string. for example, the command: ~$ tapdisk2 -n "log:|aio:/path/to/file.img" will create a blktap2 device where read and write requests are passed to the 'log' driver, then forwarded to the 'aio' driver. Signed-off-by: Ryan O'Connor <rjo@xxxxxxxxx> --- tools/blktap2/drivers/tapdisk-vbd.c | 248 +++++++++++++++++++++++++++++------- tools/blktap2/drivers/tapdisk-vbd.h | 10 + tools/blktap2/drivers/tapdisk2.c | 7 + tools/blktap2/include/list.h | 20 ++ 4 files changed, 238 insertions(+), 47 deletions(-) diff -r f6091947ffed -r 94c3f3d4b864 tools/blktap2/drivers/tapdisk-vbd.c --- a/tools/blktap2/drivers/tapdisk-vbd.c Mon Nov 09 19:19:27 2009 +0000 +++ b/tools/blktap2/drivers/tapdisk-vbd.c Mon Nov 09 19:40:14 2009 +0000 @@ -106,6 +106,7 @@ tapdisk_vbd_initialize(int rfd, int wfd, vbd->callback = tapdisk_vbd_callback; vbd->argument = vbd; + INIT_LIST_HEAD(&vbd->driver_stack); INIT_LIST_HEAD(&vbd->images); INIT_LIST_HEAD(&vbd->new_requests); INIT_LIST_HEAD(&vbd->pending_requests); @@ -541,6 +542,105 @@ regerr: goto out; } +/* TODO: ugh, lets not call it parent info... */ +static struct list_head * +tapdisk_vbd_open_level(td_vbd_t *vbd, char* params, int driver_type, td_disk_info_t *parent_info, td_flag_t flags) +{ + char *name; + int type, err; + td_image_t *image; + td_disk_id_t id; + struct list_head *images; + td_driver_t *driver; + + images = calloc(1, sizeof(struct list_head)); + INIT_LIST_HEAD(images); + + name = params; + type = driver_type; + + for (;;) { + err = -ENOMEM; + image = tapdisk_image_allocate(name, type, + vbd->storage, flags, vbd); + + /* free 'name' if it was created by td_get_parent_id() */ + if (name != params) { + free(name); + name = NULL; + } + + if (!image) + return NULL; + + + /* We have to do this to set the driver info for child drivers. this conflicts with td_open */ + driver = image->driver; + if (!driver) { + driver = tapdisk_driver_allocate(image->type, + image->name, + image->flags, + image->storage); + if (!driver) + return NULL; + } + /* the image has a driver, set the info and driver */ + image->driver = driver; + image->info = driver->info; + + /* XXX: we don't touch driver->refcount, broken? */ + /* XXX: we've replicated about 90% of td_open() gross! */ + /* XXX: this breaks if a driver modifies its info within a layer */ + + /* if the parent info is set, pass it to the child */ + if(parent_info) + { + image->driver->info = *parent_info; + } + + err = td_load(image); + if (err) { + if (err != -ENODEV) + return NULL; + + err = td_open(image); + if (err) + return NULL; + } + + /* TODO: non-sink drivers that don't care about their child + * currently return EINVAL. Could return TD_PARENT_OK or + * TD_ANY_PARENT */ + + err = td_get_parent_id(image, &id); + if (err && (err != TD_NO_PARENT && err != -EINVAL)) { + td_close(image); + return NULL; + } + + if (!image->storage) + image->storage = vbd->storage; + + /* add this image to the end of the list */ + list_add_tail(&image->next, images); + + image = NULL; + + /* if the image does not have a parent we return the + * list of images generated by this level of the stack */ + if (err == TD_NO_PARENT || err == -EINVAL) + break; + + name = id.name; + type = id.drivertype; +#if 0 + /* catch this by validate, not here */ + flags |= (TD_OPEN_RDONLY | TD_OPEN_SHAREABLE); +#endif + } + return images; +} + static int __tapdisk_vbd_open_vdi(td_vbd_t *vbd, td_flag_t extra_flags) { @@ -548,58 +648,35 @@ __tapdisk_vbd_open_vdi(td_vbd_t *vbd, td int err, type; td_flag_t flags; td_disk_id_t id; - td_image_t *image, *tmp; + td_image_t *tmp; struct tfilter *filter = NULL; + td_vbd_driver_info_t *driver_info; + struct list_head *images; + td_disk_info_t *parent_info = NULL; err = tapdisk_vbd_reactivate_volumes(vbd, 0); if (err) return err; flags = (vbd->flags & ~TD_OPEN_SHAREABLE) | extra_flags; - file = vbd->name; - type = vbd->type; - - for (;;) { - err = -ENOMEM; - image = tapdisk_image_allocate(file, type, - vbd->storage, flags, vbd); - - if (file != vbd->name) { - free(file); - file = NULL; - } - - if (!image) - goto fail; - - err = td_load(image); - if (err) { - if (err != -ENODEV) - goto fail; - - err = td_open(image); - if (err) - goto fail; - } - - err = td_get_parent_id(image, &id); - if (err && err != TD_NO_PARENT) { - td_close(image); - goto fail; - } - - if (!image->storage) - image->storage = vbd->storage; - - tapdisk_vbd_add_image(vbd, image); - image = NULL; - - if (err == TD_NO_PARENT) - break; - - file = id.name; - type = id.drivertype; - flags |= (TD_OPEN_RDONLY | TD_OPEN_SHAREABLE); + + /* loop on each user specified driver. + * NOTE: driver_info is in reverse order. That is, the first + * item is the 'parent' or 'sink' driver */ + list_for_each_entry(driver_info, &vbd->driver_stack, next) { + file = driver_info->params; + type = driver_info->type; + images = tapdisk_vbd_open_level(vbd, file, type, parent_info, flags); + if (!images) + return -EINVAL; + + /* after each loop, append the created stack to the result stack */ + list_splice(images, &vbd->images); + free(images); + + /* set the parent_info to the first diskinfo on the stack */ + tmp = tapdisk_vbd_first_image(vbd); + parent_info = &tmp->info; } if (td_flag_test(vbd->flags, TD_OPEN_LOG_DIRTY)) { @@ -623,11 +700,88 @@ __tapdisk_vbd_open_vdi(td_vbd_t *vbd, td return 0; fail: + +/* TODO: loop over vbd to free images? maybe do that in vbd_close_vdi */ +#if 0 if (image) tapdisk_image_free(image); - +#endif + + /* TODO: handle partial stack creation? */ tapdisk_vbd_close_vdi(vbd); + return err; +} + +/* this populates a vbd type based on path */ +int +tapdisk_vbd_parse_stack(td_vbd_t *vbd, const char *path) +{ + int err; + char *params, *driver_str; + td_vbd_driver_info_t *driver; + + /* make a copy of path */ + /* TODO: check against MAX_NAME_LEM ? */ + err = tapdisk_namedup(¶ms, path); + if(err) + goto error; + + + /* tokenize params based on pipe '|' */ + driver_str = strtok(params, "|"); + while(driver_str != NULL) + { + /* parse driver info and add to vbd */ + driver = calloc(1, sizeof(td_vbd_driver_info_t)); + INIT_LIST_HEAD(&driver->next); + err = tapdisk_parse_disk_type(driver_str, &driver->params, &driver->type); + if(err) + goto error; + + /* build the list backwards as the last driver will be the first + * driver to open in the stack */ + list_add(&driver->next, &vbd->driver_stack); + + /* get next driver string */ + driver_str = strtok(NULL, "|"); + } + + return 0; + + /* error: free any driver_info's and params */ + error: + while(!list_empty(&vbd->driver_stack)) { + driver = list_entry(vbd->driver_stack.next, td_vbd_driver_info_t, next); + list_del(&driver->next); + free(driver); + } + + return err; +} + +/* NOTE: driver type, etc. must be set */ +static int +tapdisk_vbd_open_stack(td_vbd_t *vbd, uint16_t storage, td_flag_t flags) +{ + int i, err; + + vbd->flags = flags; + vbd->storage = storage; + + for (i = 0; i < TD_VBD_EIO_RETRIES; i++) { + err = __tapdisk_vbd_open_vdi(vbd, 0); + if (err != -EIO) + break; + + sleep(TD_VBD_EIO_SLEEP); + } + if (err) + goto fail; + + return 0; + + fail: return err; } @@ -759,7 +913,7 @@ tapdisk_vbd_open(td_vbd_t *vbd, const ch { int err; - err = tapdisk_vbd_open_vdi(vbd, name, type, storage, flags); + err = tapdisk_vbd_open_stack(vbd, storage, flags); if (err) goto out; diff -r f6091947ffed -r 94c3f3d4b864 tools/blktap2/drivers/tapdisk-vbd.h --- a/tools/blktap2/drivers/tapdisk-vbd.h Mon Nov 09 19:19:27 2009 +0000 +++ b/tools/blktap2/drivers/tapdisk-vbd.h Mon Nov 09 19:40:14 2009 +0000 @@ -53,6 +53,7 @@ typedef struct td_ring td_ring_t; typedef struct td_vbd_request td_vbd_request_t; +typedef struct td_vbd_driver_info td_vbd_driver_info_t; typedef struct td_vbd_handle td_vbd_t; typedef void (*td_vbd_cb_t) (void *, blkif_response_t *); @@ -79,11 +80,19 @@ struct td_vbd_request { struct list_head next; }; +struct td_vbd_driver_info { + char *params; + int type; + struct list_head next; +}; + struct td_vbd_handle { char *name; td_uuid_t uuid; int type; + + struct list_head driver_stack; int storage; @@ -164,6 +173,7 @@ tapdisk_vbd_next_image(td_image_t *image int tapdisk_vbd_initialize(int, int, td_uuid_t); void tapdisk_vbd_set_callback(td_vbd_t *, td_vbd_cb_t, void *); +int tapdisk_vbd_parse_stack(td_vbd_t *vbd, const char *path); int tapdisk_vbd_open(td_vbd_t *, const char *, uint16_t, uint16_t, const char *, td_flag_t); int tapdisk_vbd_close(td_vbd_t *); diff -r f6091947ffed -r 94c3f3d4b864 tools/blktap2/drivers/tapdisk2.c --- a/tools/blktap2/drivers/tapdisk2.c Mon Nov 09 19:19:27 2009 +0000 +++ b/tools/blktap2/drivers/tapdisk2.c Mon Nov 09 19:40:14 2009 +0000 @@ -264,6 +264,13 @@ tapdisk2_open_device(int type, const cha return err; } + err = tapdisk_vbd_parse_stack(vbd, name); + if (err) { + CHILD_ERR(err, "vbd_parse_stack failed: %d\n", err); + return err; + } + + /* TODO: clean this up */ err = tapdisk_vbd_open(vbd, path, type, TAPDISK_STORAGE_TYPE_DEFAULT, devname, 0); diff -r f6091947ffed -r 94c3f3d4b864 tools/blktap2/include/list.h --- a/tools/blktap2/include/list.h Mon Nov 09 19:19:27 2009 +0000 +++ b/tools/blktap2/include/list.h Mon Nov 09 19:40:14 2009 +0000 @@ -87,6 +87,26 @@ static inline int list_is_last(const str return list->next == head; } +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |