[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 08 of 11] blktap2: configurable driver chains
# HG changeset patch # User Ryan O'Connor <rjo@xxxxxxxxx> # Date 1252530408 25200 # Node ID 4ca00ee41ce9731b8725c736b27c841b484dce5d # Parent 6ca67fe3514ada809a62282c30fe46d5df5ce265 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> diff --git a/tools/blktap2/drivers/tapdisk-vbd.c b/tools/blktap2/drivers/tapdisk-vbd.c --- a/tools/blktap2/drivers/tapdisk-vbd.c +++ b/tools/blktap2/drivers/tapdisk-vbd.c @@ -106,6 +106,7 @@ 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 @@ 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,36 @@ 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; - } + /* 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; - if (!image) - goto fail; + /* after each loop, append the created stack to the result stack */ + list_splice(images, &vbd->images); + free(images); - 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); + /* 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,14 +701,91 @@ 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 createion? */ 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; +} + int tapdisk_vbd_open_vdi(td_vbd_t *vbd, const char *path, uint16_t drivertype, uint16_t storage, td_flag_t flags) @@ -759,7 +914,7 @@ { 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 --git a/tools/blktap2/drivers/tapdisk-vbd.h b/tools/blktap2/drivers/tapdisk-vbd.h --- a/tools/blktap2/drivers/tapdisk-vbd.h +++ b/tools/blktap2/drivers/tapdisk-vbd.h @@ -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,12 +80,20 @@ 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; uint8_t reopened; @@ -164,6 +173,7 @@ 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 --git a/tools/blktap2/drivers/tapdisk2.c b/tools/blktap2/drivers/tapdisk2.c --- a/tools/blktap2/drivers/tapdisk2.c +++ b/tools/blktap2/drivers/tapdisk2.c @@ -264,6 +264,13 @@ 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 --git a/tools/blktap2/include/list.h b/tools/blktap2/include/list.h --- a/tools/blktap2/include/list.h +++ b/tools/blktap2/include/list.h @@ -87,6 +87,26 @@ 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-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |