aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/gntalloc.c
diff options
context:
space:
mode:
authorDaniel De Graaf <dgdegra@tycho.nsa.gov>2011-02-03 12:19:04 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-02-14 14:16:17 -0500
commitbdc612dc6903c4ea06e40d02f84ad5e25d93459d (patch)
treef7f3e3272b21ae3c6015e86f9c1f7be31534704d /drivers/xen/gntalloc.c
parentdd3140588d9551235ebc2a0dacdca098e7677573 (diff)
xen/gntalloc,gntdev: Add unmap notify ioctl
This ioctl allows the users of a shared page to be notified when the other end exits abnormally. [v2: updated description in structs] Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen/gntalloc.c')
-rw-r--r--drivers/xen/gntalloc.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c
index d06bf2b4cd07..a7ffdfe19fc9 100644
--- a/drivers/xen/gntalloc.c
+++ b/drivers/xen/gntalloc.c
@@ -60,11 +60,13 @@
60#include <linux/uaccess.h> 60#include <linux/uaccess.h>
61#include <linux/types.h> 61#include <linux/types.h>
62#include <linux/list.h> 62#include <linux/list.h>
63#include <linux/highmem.h>
63 64
64#include <xen/xen.h> 65#include <xen/xen.h>
65#include <xen/page.h> 66#include <xen/page.h>
66#include <xen/grant_table.h> 67#include <xen/grant_table.h>
67#include <xen/gntalloc.h> 68#include <xen/gntalloc.h>
69#include <xen/events.h>
68 70
69static int limit = 1024; 71static int limit = 1024;
70module_param(limit, int, 0644); 72module_param(limit, int, 0644);
@@ -75,6 +77,12 @@ static LIST_HEAD(gref_list);
75static DEFINE_SPINLOCK(gref_lock); 77static DEFINE_SPINLOCK(gref_lock);
76static int gref_size; 78static int gref_size;
77 79
80struct notify_info {
81 uint16_t pgoff:12; /* Bits 0-11: Offset of the byte to clear */
82 uint16_t flags:2; /* Bits 12-13: Unmap notification flags */
83 int event; /* Port (event channel) to notify */
84};
85
78/* Metadata on a grant reference. */ 86/* Metadata on a grant reference. */
79struct gntalloc_gref { 87struct gntalloc_gref {
80 struct list_head next_gref; /* list entry gref_list */ 88 struct list_head next_gref; /* list entry gref_list */
@@ -83,6 +91,7 @@ struct gntalloc_gref {
83 uint64_t file_index; /* File offset for mmap() */ 91 uint64_t file_index; /* File offset for mmap() */
84 unsigned int users; /* Use count - when zero, waiting on Xen */ 92 unsigned int users; /* Use count - when zero, waiting on Xen */
85 grant_ref_t gref_id; /* The grant reference number */ 93 grant_ref_t gref_id; /* The grant reference number */
94 struct notify_info notify; /* Unmap notification */
86}; 95};
87 96
88struct gntalloc_file_private_data { 97struct gntalloc_file_private_data {
@@ -164,6 +173,16 @@ undo:
164 173
165static void __del_gref(struct gntalloc_gref *gref) 174static void __del_gref(struct gntalloc_gref *gref)
166{ 175{
176 if (gref->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
177 uint8_t *tmp = kmap(gref->page);
178 tmp[gref->notify.pgoff] = 0;
179 kunmap(gref->page);
180 }
181 if (gref->notify.flags & UNMAP_NOTIFY_SEND_EVENT)
182 notify_remote_via_evtchn(gref->notify.event);
183
184 gref->notify.flags = 0;
185
167 if (gref->gref_id > 0) { 186 if (gref->gref_id > 0) {
168 if (gnttab_query_foreign_access(gref->gref_id)) 187 if (gnttab_query_foreign_access(gref->gref_id))
169 return; 188 return;
@@ -349,6 +368,43 @@ dealloc_grant_out:
349 return rc; 368 return rc;
350} 369}
351 370
371static long gntalloc_ioctl_unmap_notify(struct gntalloc_file_private_data *priv,
372 void __user *arg)
373{
374 struct ioctl_gntalloc_unmap_notify op;
375 struct gntalloc_gref *gref;
376 uint64_t index;
377 int pgoff;
378 int rc;
379
380 if (copy_from_user(&op, arg, sizeof(op)))
381 return -EFAULT;
382
383 index = op.index & ~(PAGE_SIZE - 1);
384 pgoff = op.index & (PAGE_SIZE - 1);
385
386 spin_lock(&gref_lock);
387
388 gref = find_grefs(priv, index, 1);
389 if (!gref) {
390 rc = -ENOENT;
391 goto unlock_out;
392 }
393
394 if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT)) {
395 rc = -EINVAL;
396 goto unlock_out;
397 }
398
399 gref->notify.flags = op.action;
400 gref->notify.pgoff = pgoff;
401 gref->notify.event = op.event_channel_port;
402 rc = 0;
403 unlock_out:
404 spin_unlock(&gref_lock);
405 return rc;
406}
407
352static long gntalloc_ioctl(struct file *filp, unsigned int cmd, 408static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
353 unsigned long arg) 409 unsigned long arg)
354{ 410{
@@ -361,6 +417,9 @@ static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
361 case IOCTL_GNTALLOC_DEALLOC_GREF: 417 case IOCTL_GNTALLOC_DEALLOC_GREF:
362 return gntalloc_ioctl_dealloc(priv, (void __user *)arg); 418 return gntalloc_ioctl_dealloc(priv, (void __user *)arg);
363 419
420 case IOCTL_GNTALLOC_SET_UNMAP_NOTIFY:
421 return gntalloc_ioctl_unmap_notify(priv, (void __user *)arg);
422
364 default: 423 default:
365 return -ENOIOCTLCMD; 424 return -ENOIOCTLCMD;
366 } 425 }