[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] introduce grant copy for user land
This patch introduces the interface to allow user-space applications execute grant-copy operations. This is done by sending an ioctl to the grant device. The number of grant-copy segments is currently limited to 16 in order to simplify the implementation, however the ABI allows an arbitrary number of operations. Signed-off-by: Thanos Makatos <thanos.makatos@xxxxxxxxxx> --- drivers/xen/gntdev.c | 115 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/xen/gntdev.h | 38 +++++++++++++++ 2 files changed, 153 insertions(+) diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 073b4a1..77d5b14 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -707,6 +707,118 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u) return rc; } +/* + * Limit number of operations to simplify implementation. NB the API + * allows for an arbitrary number of operations. + */ +#define GNTDEV_GRANT_COPY_MAX_OPS 16 + +static long gntdev_ioctl_grant_copy(struct gntdev_priv *priv, void __user *u) +{ + struct ioctl_gntdev_grant_copy op; + int err = 0, i; + unsigned int nr_pinned = 0; + struct gcopy_cb { + struct page *pages[GNTDEV_GRANT_COPY_MAX_OPS]; + struct gnttab_copy batch[GNTDEV_GRANT_COPY_MAX_OPS]; + struct gntdev_grant_copy_segment + segments[GNTDEV_GRANT_COPY_MAX_OPS]; + } *gcopy_cb = NULL; + struct gntdev_grant_copy_segment *segments; + + if (copy_from_user(&op, u, sizeof(op))) { + err = -EFAULT; + goto out; + } + + if (!op.count) { + err = 0; + goto out; + } + + if (op.count > GNTDEV_GRANT_COPY_MAX_OPS) { + pr_warn("copying more than %d segments not yet implemented\n", + GNTDEV_GRANT_COPY_MAX_OPS); + err = -ENOSYS; + goto out; + } + + gcopy_cb = kmalloc(sizeof(*gcopy_cb), GFP_KERNEL); + if (!gcopy_cb) { + err = -ENOMEM; + goto out; + } + + if (copy_from_user(gcopy_cb->segments, op.segments, + sizeof(*op.segments) * op.count)) { + err = -EFAULT; + goto out; + } + + for (i = 0; i < op.count; i++) { + + unsigned long start, offset; + struct gntdev_grant_copy_segment *seg = &gcopy_cb->segments[i]; + xen_pfn_t pgaddr; + + start = (unsigned long)seg->iov.iov_base & PAGE_MASK; + offset = (unsigned long)seg->iov.iov_base & ~PAGE_MASK; + if (offset + seg->iov.iov_len > PAGE_SIZE) { + pr_warn("segments crossing page boundarys not yet implemented\n"); + err = -ENOSYS; + goto out; + } + + err = get_user_pages_fast(start, 1, op.dir, + &gcopy_cb->pages[i]); + if (err != 1) { + err = -EFAULT; + goto out; + } + + nr_pinned++; + + pgaddr = pfn_to_mfn(page_to_pfn(gcopy_cb->pages[i])); + + gcopy_cb->batch[i].len = seg->iov.iov_len; + if (op.dir) { + /* copy from guest */ + gcopy_cb->batch[i].source.u.ref = seg->ref; + gcopy_cb->batch[i].source.domid = op.domid; + gcopy_cb->batch[i].source.offset = seg->offset; + gcopy_cb->batch[i].dest.u.gmfn = pgaddr; + gcopy_cb->batch[i].dest.domid = DOMID_SELF; + gcopy_cb->batch[i].dest.offset = offset; + gcopy_cb->batch[i].flags = GNTCOPY_source_gref; + } else { + /* copy to guest */ + gcopy_cb->batch[i].source.u.gmfn = pgaddr; + gcopy_cb->batch[i].source.domid = DOMID_SELF; + gcopy_cb->batch[i].source.offset = offset; + gcopy_cb->batch[i].dest.u.ref = seg->ref; + gcopy_cb->batch[i].dest.domid = op.domid; + gcopy_cb->batch[i].dest.offset = seg->offset; + gcopy_cb->batch[i].flags = GNTCOPY_dest_gref; + } + } + + gnttab_batch_copy(gcopy_cb->batch, op.count); + segments = op.segments; + for (i = 0; i < op.count; i++) { + err = put_user(gcopy_cb->batch[i].status, &segments[i].status); + if (err) + goto out; + } + +out: + if (gcopy_cb) { + for (i = 0; i < nr_pinned; i++) + put_page(gcopy_cb->pages[i]); + kfree(gcopy_cb); + } + return err; +} + static long gntdev_ioctl(struct file *flip, unsigned int cmd, unsigned long arg) { @@ -726,6 +838,9 @@ static long gntdev_ioctl(struct file *flip, case IOCTL_GNTDEV_SET_UNMAP_NOTIFY: return gntdev_ioctl_notify(priv, ptr); + case IOCTL_GNTDEV_GRANT_COPY: + return gntdev_ioctl_grant_copy(priv, ptr); + default: pr_debug("priv %p, unknown cmd %x\n", priv, cmd); return -ENOIOCTLCMD; diff --git a/include/uapi/xen/gntdev.h b/include/uapi/xen/gntdev.h index 5304bd3..2db3186 100644 --- a/include/uapi/xen/gntdev.h +++ b/include/uapi/xen/gntdev.h @@ -33,6 +33,12 @@ #ifndef __LINUX_PUBLIC_GNTDEV_H__ #define __LINUX_PUBLIC_GNTDEV_H__ +#ifdef __KERNEL__ +#include <linux/uio.h> +#else +#include <sys/uio.h> +#endif + struct ioctl_gntdev_grant_ref { /* The domain ID of the grant to be mapped. */ uint32_t domid; @@ -142,6 +148,38 @@ struct ioctl_gntdev_unmap_notify { uint32_t event_channel_port; }; +struct gntdev_grant_copy_segment { + /* + * source address and length + */ + struct iovec iov; + + /* the granted page */ + uint32_t ref; + + /* offset in the granted page */ + uint16_t offset; + + /* grant copy result (GNTST_XXX) */ + int16_t status; +}; + +#define IOCTL_GNTDEV_GRANT_COPY \ +_IOC(_IOC_NONE, 'G', 8, sizeof(struct ioctl_gntdev_grant_copy)) +struct ioctl_gntdev_grant_copy { + /* + * copy direction: 0 to copy to guest, 1 to copy from guest + */ + int dir; + + /* domain ID */ + uint32_t domid; + + unsigned int count; + + struct gntdev_grant_copy_segment __user *segments; +}; + /* Clear (set to zero) the byte specified by index */ #define UNMAP_NOTIFY_CLEAR_BYTE 0x1 /* Send an interrupt on the indicated event channel */ -- 1.7.9.5 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |