diff options
author | Daniel De Graaf <dgdegra@tycho.nsa.gov> | 2011-02-03 12:19:04 -0500 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2011-02-14 14:16:17 -0500 |
commit | bdc612dc6903c4ea06e40d02f84ad5e25d93459d (patch) | |
tree | f7f3e3272b21ae3c6015e86f9c1f7be31534704d /drivers/xen/gntalloc.c | |
parent | dd3140588d9551235ebc2a0dacdca098e7677573 (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.c | 59 |
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 | ||
69 | static int limit = 1024; | 71 | static int limit = 1024; |
70 | module_param(limit, int, 0644); | 72 | module_param(limit, int, 0644); |
@@ -75,6 +77,12 @@ static LIST_HEAD(gref_list); | |||
75 | static DEFINE_SPINLOCK(gref_lock); | 77 | static DEFINE_SPINLOCK(gref_lock); |
76 | static int gref_size; | 78 | static int gref_size; |
77 | 79 | ||
80 | struct 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. */ |
79 | struct gntalloc_gref { | 87 | struct 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 | ||
88 | struct gntalloc_file_private_data { | 97 | struct gntalloc_file_private_data { |
@@ -164,6 +173,16 @@ undo: | |||
164 | 173 | ||
165 | static void __del_gref(struct gntalloc_gref *gref) | 174 | static 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 | ||
371 | static 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 | |||
352 | static long gntalloc_ioctl(struct file *filp, unsigned int cmd, | 408 | static 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 | } |