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.c34
1 files changed, 32 insertions, 2 deletions
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index afca14d9042e..99d8151c824a 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -193,8 +193,10 @@ static void gntdev_put_map(struct grant_map *map)
193 193
194 atomic_sub(map->count, &pages_mapped); 194 atomic_sub(map->count, &pages_mapped);
195 195
196 if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) 196 if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) {
197 notify_remote_via_evtchn(map->notify.event); 197 notify_remote_via_evtchn(map->notify.event);
198 evtchn_put(map->notify.event);
199 }
198 200
199 if (map->pages) { 201 if (map->pages) {
200 if (!use_ptemod) 202 if (!use_ptemod)
@@ -312,7 +314,8 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages)
312 } 314 }
313 } 315 }
314 316
315 err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset, pages); 317 err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset,
318 pages, true);
316 if (err) 319 if (err)
317 return err; 320 return err;
318 321
@@ -599,6 +602,8 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
599 struct ioctl_gntdev_unmap_notify op; 602 struct ioctl_gntdev_unmap_notify op;
600 struct grant_map *map; 603 struct grant_map *map;
601 int rc; 604 int rc;
605 int out_flags;
606 unsigned int out_event;
602 607
603 if (copy_from_user(&op, u, sizeof(op))) 608 if (copy_from_user(&op, u, sizeof(op)))
604 return -EFAULT; 609 return -EFAULT;
@@ -606,6 +611,21 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
606 if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT)) 611 if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT))
607 return -EINVAL; 612 return -EINVAL;
608 613
614 /* We need to grab a reference to the event channel we are going to use
615 * to send the notify before releasing the reference we may already have
616 * (if someone has called this ioctl twice). This is required so that
617 * it is possible to change the clear_byte part of the notification
618 * without disturbing the event channel part, which may now be the last
619 * reference to that event channel.
620 */
621 if (op.action & UNMAP_NOTIFY_SEND_EVENT) {
622 if (evtchn_get(op.event_channel_port))
623 return -EINVAL;
624 }
625
626 out_flags = op.action;
627 out_event = op.event_channel_port;
628
609 spin_lock(&priv->lock); 629 spin_lock(&priv->lock);
610 630
611 list_for_each_entry(map, &priv->maps, next) { 631 list_for_each_entry(map, &priv->maps, next) {
@@ -624,12 +644,22 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
624 goto unlock_out; 644 goto unlock_out;
625 } 645 }
626 646
647 out_flags = map->notify.flags;
648 out_event = map->notify.event;
649
627 map->notify.flags = op.action; 650 map->notify.flags = op.action;
628 map->notify.addr = op.index - (map->index << PAGE_SHIFT); 651 map->notify.addr = op.index - (map->index << PAGE_SHIFT);
629 map->notify.event = op.event_channel_port; 652 map->notify.event = op.event_channel_port;
653
630 rc = 0; 654 rc = 0;
655
631 unlock_out: 656 unlock_out:
632 spin_unlock(&priv->lock); 657 spin_unlock(&priv->lock);
658
659 /* Drop the reference to the event channel we did not save in the map */
660 if (out_flags & UNMAP_NOTIFY_SEND_EVENT)
661 evtchn_put(out_event);
662
633 return rc; 663 return rc;
634} 664}
635 665