aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/gntdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen/gntdev.c')
-rw-r--r--drivers/xen/gntdev.c61
1 files changed, 60 insertions, 1 deletions
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index bcaf797216d1..9694a1a8b2e2 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -37,6 +37,7 @@
37#include <xen/xen.h> 37#include <xen/xen.h>
38#include <xen/grant_table.h> 38#include <xen/grant_table.h>
39#include <xen/gntdev.h> 39#include <xen/gntdev.h>
40#include <xen/events.h>
40#include <asm/xen/hypervisor.h> 41#include <asm/xen/hypervisor.h>
41#include <asm/xen/hypercall.h> 42#include <asm/xen/hypercall.h>
42#include <asm/xen/page.h> 43#include <asm/xen/page.h>
@@ -63,6 +64,13 @@ struct gntdev_priv {
63 struct mmu_notifier mn; 64 struct mmu_notifier mn;
64}; 65};
65 66
67struct unmap_notify {
68 int flags;
69 /* Address relative to the start of the grant_map */
70 int addr;
71 int event;
72};
73
66struct grant_map { 74struct grant_map {
67 struct list_head next; 75 struct list_head next;
68 struct vm_area_struct *vma; 76 struct vm_area_struct *vma;
@@ -71,6 +79,7 @@ struct grant_map {
71 int flags; 79 int flags;
72 int is_mapped; 80 int is_mapped;
73 atomic_t users; 81 atomic_t users;
82 struct unmap_notify notify;
74 struct ioctl_gntdev_grant_ref *grants; 83 struct ioctl_gntdev_grant_ref *grants;
75 struct gnttab_map_grant_ref *map_ops; 84 struct gnttab_map_grant_ref *map_ops;
76 struct gnttab_unmap_grant_ref *unmap_ops; 85 struct gnttab_unmap_grant_ref *unmap_ops;
@@ -165,7 +174,7 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv,
165 list_for_each_entry(map, &priv->maps, next) { 174 list_for_each_entry(map, &priv->maps, next) {
166 if (map->index != index) 175 if (map->index != index)
167 continue; 176 continue;
168 if (map->count != count) 177 if (count && map->count != count)
169 continue; 178 continue;
170 return map; 179 return map;
171 } 180 }
@@ -184,6 +193,10 @@ static void gntdev_put_map(struct grant_map *map)
184 193
185 atomic_sub(map->count, &pages_mapped); 194 atomic_sub(map->count, &pages_mapped);
186 195
196 if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) {
197 notify_remote_via_evtchn(map->notify.event);
198 }
199
187 if (map->pages) { 200 if (map->pages) {
188 if (!use_ptemod) 201 if (!use_ptemod)
189 unmap_grant_pages(map, 0, map->count); 202 unmap_grant_pages(map, 0, map->count);
@@ -274,6 +287,16 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int pages)
274{ 287{
275 int i, err = 0; 288 int i, err = 0;
276 289
290 if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
291 int pgno = (map->notify.addr >> PAGE_SHIFT);
292 if (pgno >= offset && pgno < offset + pages) {
293 uint8_t *tmp = kmap(map->pages[pgno]);
294 tmp[map->notify.addr & (PAGE_SIZE-1)] = 0;
295 kunmap(map->pages[pgno]);
296 map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
297 }
298 }
299
277 pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset, pages); 300 pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset, pages);
278 err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages, pages); 301 err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages, pages);
279 if (err) 302 if (err)
@@ -519,6 +542,39 @@ static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv *priv,
519 return 0; 542 return 0;
520} 543}
521 544
545static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
546{
547 struct ioctl_gntdev_unmap_notify op;
548 struct grant_map *map;
549 int rc;
550
551 if (copy_from_user(&op, u, sizeof(op)))
552 return -EFAULT;
553
554 if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT))
555 return -EINVAL;
556
557 spin_lock(&priv->lock);
558
559 list_for_each_entry(map, &priv->maps, next) {
560 uint64_t begin = map->index << PAGE_SHIFT;
561 uint64_t end = (map->index + map->count) << PAGE_SHIFT;
562 if (op.index >= begin && op.index < end)
563 goto found;
564 }
565 rc = -ENOENT;
566 goto unlock_out;
567
568 found:
569 map->notify.flags = op.action;
570 map->notify.addr = op.index - (map->index << PAGE_SHIFT);
571 map->notify.event = op.event_channel_port;
572 rc = 0;
573 unlock_out:
574 spin_unlock(&priv->lock);
575 return rc;
576}
577
522static long gntdev_ioctl(struct file *flip, 578static long gntdev_ioctl(struct file *flip,
523 unsigned int cmd, unsigned long arg) 579 unsigned int cmd, unsigned long arg)
524{ 580{
@@ -535,6 +591,9 @@ static long gntdev_ioctl(struct file *flip,
535 case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR: 591 case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR:
536 return gntdev_ioctl_get_offset_for_vaddr(priv, ptr); 592 return gntdev_ioctl_get_offset_for_vaddr(priv, ptr);
537 593
594 case IOCTL_GNTDEV_SET_UNMAP_NOTIFY:
595 return gntdev_ioctl_notify(priv, ptr);
596
538 default: 597 default:
539 pr_debug("priv %p, unknown cmd %x\n", priv, cmd); 598 pr_debug("priv %p, unknown cmd %x\n", priv, cmd);
540 return -ENOIOCTLCMD; 599 return -ENOIOCTLCMD;