[PATCH 3/4] xen-fbfront: Use grant references when requested

From: Konrad Rzeszutek Wilk
Date: Tue Mar 15 2011 - 10:12:10 EST


From: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>

The current version of the Xen framebuffer API passes MFNs directly
to the backend driver, which requires the backend to have full access
to this domain's memory. Add a parameter in xenbus to request the use of
grant entries instead, which are slightly slower to map but provide
inter-domain isolation.

Signed-off-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
Acked-by: Ian Campbell <Ian.Campbell@xxxxxxxxxxxxx>
---
drivers/video/xen-fbfront.c | 96 +++++++++++++++++++++++++++++++++++-------
1 files changed, 80 insertions(+), 16 deletions(-)

diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index 56d6061..b43c5c9 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -11,13 +11,6 @@
* more details.
*/

-/*
- * TODO:
- *
- * Switch to grant tables when they become capable of dealing with the
- * frame buffer.
- */
-
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -32,6 +25,8 @@
#include <xen/xen.h>
#include <xen/events.h>
#include <xen/page.h>
+#include <xen/grant_table.h>
+#include <xen/interface/grant_table.h>
#include <xen/interface/io/fbif.h>
#include <xen/interface/io/protocols.h>
#include <xen/xenbus.h>
@@ -46,6 +41,8 @@ struct xenfb_info {
int irq;
struct xenfb_page *page;
unsigned long *mfns;
+ grant_ref_t *mfn_grefs;
+ int page_gref;
int update_wanted; /* XENFB_TYPE_UPDATE wanted */
int feature_resize; /* XENFB_TYPE_RESIZE ok */
struct xenfb_resize resize; /* protected by resize_lock */
@@ -65,7 +62,7 @@ MODULE_PARM_DESC(video,

static void xenfb_make_preferred_console(void);
static int xenfb_remove(struct xenbus_device *);
-static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *);
+static void xenfb_init_shared_page(struct xenbus_device *, struct xenfb_info *, struct fb_info *);
static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *);
static void xenfb_disconnect_backend(struct xenfb_info *);

@@ -412,6 +409,7 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
info->x1 = info->y1 = INT_MAX;
spin_lock_init(&info->dirty_lock);
spin_lock_init(&info->resize_lock);
+ info->page_gref = -1;

info->fb = vmalloc(fb_size);
if (info->fb == NULL)
@@ -474,7 +472,7 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
fb_info->fbdefio = &xenfb_defio;
fb_deferred_io_init(fb_info);

- xenfb_init_shared_page(info, fb_info);
+ xenfb_init_shared_page(dev, info, fb_info);

ret = xenfb_connect_backend(dev, info);
if (ret < 0)
@@ -528,7 +526,7 @@ static int xenfb_resume(struct xenbus_device *dev)
struct xenfb_info *info = dev_get_drvdata(&dev->dev);

xenfb_disconnect_backend(info);
- xenfb_init_shared_page(info, info->fb_info);
+ xenfb_init_shared_page(dev, info, info->fb_info);
return xenfb_connect_backend(dev, info);
}

@@ -543,9 +541,25 @@ static int xenfb_remove(struct xenbus_device *dev)
fb_dealloc_cmap(&info->fb_info->cmap);
framebuffer_release(info->fb_info);
}
+ if (info->page_gref >= 0) {
+ int epd = PAGE_SIZE / sizeof(info->mfns[0]);
+ int pdpages = (info->nr_pages + epd - 1) / epd;
+ int i;
+ gnttab_end_foreign_access_ref(info->page_gref, 0);
+ gnttab_free_grant_reference(info->page_gref);
+ for (i = 0; i < pdpages; i++) {
+ gnttab_end_foreign_access_ref(info->mfn_grefs[i], 1);
+ gnttab_free_grant_reference(info->mfn_grefs[i]);
+ }
+ for (i = 0; i < info->nr_pages; i++) {
+ gnttab_end_foreign_access_ref(info->mfns[i], 1);
+ gnttab_free_grant_reference(info->mfns[i]);
+ }
+ }
free_page((unsigned long)info->page);
vfree(info->mfns);
vfree(info->fb);
+ kfree(info->mfn_grefs);
kfree(info);

return 0;
@@ -556,17 +570,63 @@ static unsigned long vmalloc_to_mfn(void *address)
return pfn_to_mfn(vmalloc_to_pfn(address));
}

-static void xenfb_init_shared_page(struct xenfb_info *info,
+static void xenfb_init_shared_page(struct xenbus_device *dev,
+ struct xenfb_info *info,
struct fb_info *fb_info)
{
- int i;
int epd = PAGE_SIZE / sizeof(info->mfns[0]);
+ int be_id = dev->otherend_id;
+ int i, ref;
+ unsigned long mfn;
+ grant_ref_t gref_head;
+ int pdpages = (info->nr_pages + epd - 1) / epd;
+ int allpages = info->nr_pages + pdpages + 1;
+
+ int grants = 0;
+ xenbus_scanf(XBT_NIL, dev->otherend, "feature-grants", "%d", &grants);
+
+ if (grants) {
+ int err = gnttab_alloc_grant_references(allpages, &gref_head);
+ info->mfn_grefs = kzalloc(pdpages*sizeof(grant_ref_t), GFP_KERNEL);
+ if (!info->mfn_grefs || err < 0) {
+ info->page_gref = -ENOSPC;
+ if (err >= 0)
+ gnttab_free_grant_references(gref_head);
+ grants = 0;
+ } else {
+ ref = gnttab_claim_grant_reference(&gref_head);
+ mfn = virt_to_mfn(info->page);
+ BUG_ON(ref == -ENOSPC);
+ gnttab_grant_foreign_access_ref(ref, be_id, mfn, 0);
+ info->page_gref = ref;
+ }
+ } else
+ info->page_gref = -ENOENT;

for (i = 0; i < info->nr_pages; i++)
- info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
+ {
+ mfn = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
+ if (grants) {
+ ref = gnttab_claim_grant_reference(&gref_head);
+ BUG_ON(ref == -ENOSPC);
+ gnttab_grant_foreign_access_ref(ref, be_id, mfn, 1);
+ info->mfns[i] = ref;
+ } else
+ info->mfns[i] = mfn;
+ }

for (i = 0; i * epd < info->nr_pages; i++)
- info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]);
+ {
+ mfn = vmalloc_to_mfn(&info->mfns[i * epd]);
+ if (grants) {
+ ref = gnttab_claim_grant_reference(&gref_head);
+ BUG_ON(ref == -ENOSPC);
+ gnttab_grant_foreign_access_ref(ref, be_id, mfn, 1);
+ info->mfn_grefs[i] = ref;
+ info->page->pd[i] = ref;
+ } else
+ info->page->pd[i] = mfn;
+ }

info->page->width = fb_info->var.xres;
info->page->height = fb_info->var.yres;
@@ -599,8 +659,12 @@ static int xenfb_connect_backend(struct xenbus_device *dev,
xenbus_dev_fatal(dev, ret, "starting transaction");
goto unbind_irq;
}
- ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
- virt_to_mfn(info->page));
+ if (info->page_gref < 0)
+ ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
+ virt_to_mfn(info->page));
+ else
+ ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u",
+ info->page_gref);
if (ret)
goto error_xenbus;
ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/