[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


 


Rackspace

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