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

Re: [Xen-devel] [PATCH 08 of 11] blktap2: configurable driver chains



Hey Ryan.

The command line idea is ok, but how about "!"?

Also, please check the line width.

Also, please don't alter the kernel list macros [..or submit yours to
lkml].

Daniel

On Thu, 2009-11-05 at 17:58 -0500, Brendan Cully wrote:
> # 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(&params, 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



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.