xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Thanos Makatos <thanos.makatos@citrix.com>
To: xen-devel@lists.xenproject.org
Cc: thanos.makatos@citrix.com, boris.ostrovsky@oracle.com,
	david.vrabel@citrix.com
Subject: [PATCH] introduce grant copy for user land
Date: Thu, 2 Oct 2014 16:15:16 +0100	[thread overview]
Message-ID: <1412262916-22596-1-git-send-email-thanos.makatos@citrix.com> (raw)

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@citrix.com>
---
 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

             reply	other threads:[~2014-10-02 15:15 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-02 15:15 Thanos Makatos [this message]
2014-11-03 18:03 ` [PATCH] introduce grant copy for user land David Vrabel
2014-11-11 12:27   ` Thanos Makatos
2014-11-11 13:34     ` David Vrabel
2014-11-11 14:42       ` Thanos Makatos
2014-11-11 15:06         ` David Vrabel
2014-11-11 15:23           ` Thanos Makatos

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1412262916-22596-1-git-send-email-thanos.makatos@citrix.com \
    --to=thanos.makatos@citrix.com \
    --cc=boris.ostrovsky@oracle.com \
    --cc=david.vrabel@citrix.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).