aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDaniel De Graaf <dgdegra@tycho.nsa.gov>2011-10-27 17:58:49 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-11-21 17:14:48 -0500
commit0cc678f850f2cba0cedbd133fcbbf175554cd6c6 (patch)
tree3289a7f4681c16c89b26612625b2f3f065f3186f /drivers
parent8ca19a8937ad91703cfefccf13bd8017b39510cd (diff)
xen/gnt{dev,alloc}: reserve event channels for notify
When using the unmap notify ioctl, the event channel used for notification needs to be reserved to avoid it being deallocated prior to sending the notification. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/xen/gntalloc.c21
-rw-r--r--drivers/xen/gntdev.c31
2 files changed, 50 insertions, 2 deletions
diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c
index 439352d094db..c95181f43a6a 100644
--- a/drivers/xen/gntalloc.c
+++ b/drivers/xen/gntalloc.c
@@ -178,8 +178,10 @@ static void __del_gref(struct gntalloc_gref *gref)
178 tmp[gref->notify.pgoff] = 0; 178 tmp[gref->notify.pgoff] = 0;
179 kunmap(gref->page); 179 kunmap(gref->page);
180 } 180 }
181 if (gref->notify.flags & UNMAP_NOTIFY_SEND_EVENT) 181 if (gref->notify.flags & UNMAP_NOTIFY_SEND_EVENT) {
182 notify_remote_via_evtchn(gref->notify.event); 182 notify_remote_via_evtchn(gref->notify.event);
183 evtchn_put(gref->notify.event);
184 }
183 185
184 gref->notify.flags = 0; 186 gref->notify.flags = 0;
185 187
@@ -396,6 +398,23 @@ static long gntalloc_ioctl_unmap_notify(struct gntalloc_file_private_data *priv,
396 goto unlock_out; 398 goto unlock_out;
397 } 399 }
398 400
401 /* We need to grab a reference to the event channel we are going to use
402 * to send the notify before releasing the reference we may already have
403 * (if someone has called this ioctl twice). This is required so that
404 * it is possible to change the clear_byte part of the notification
405 * without disturbing the event channel part, which may now be the last
406 * reference to that event channel.
407 */
408 if (op.action & UNMAP_NOTIFY_SEND_EVENT) {
409 if (evtchn_get(op.event_channel_port)) {
410 rc = -EINVAL;
411 goto unlock_out;
412 }
413 }
414
415 if (gref->notify.flags & UNMAP_NOTIFY_SEND_EVENT)
416 evtchn_put(gref->notify.event);
417
399 gref->notify.flags = op.action; 418 gref->notify.flags = op.action;
400 gref->notify.pgoff = pgoff; 419 gref->notify.pgoff = pgoff;
401 gref->notify.event = op.event_channel_port; 420 gref->notify.event = op.event_channel_port;
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 39871326afa2..a7308559a26a 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)
@@ -599,6 +601,8 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
599 struct ioctl_gntdev_unmap_notify op; 601 struct ioctl_gntdev_unmap_notify op;
600 struct grant_map *map; 602 struct grant_map *map;
601 int rc; 603 int rc;
604 int out_flags;
605 unsigned int out_event;
602 606
603 if (copy_from_user(&op, u, sizeof(op))) 607 if (copy_from_user(&op, u, sizeof(op)))
604 return -EFAULT; 608 return -EFAULT;
@@ -606,6 +610,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)) 610 if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT))
607 return -EINVAL; 611 return -EINVAL;
608 612
613 /* We need to grab a reference to the event channel we are going to use
614 * to send the notify before releasing the reference we may already have
615 * (if someone has called this ioctl twice). This is required so that
616 * it is possible to change the clear_byte part of the notification
617 * without disturbing the event channel part, which may now be the last
618 * reference to that event channel.
619 */
620 if (op.action & UNMAP_NOTIFY_SEND_EVENT) {
621 if (evtchn_get(op.event_channel_port))
622 return -EINVAL;
623 }
624
625 out_flags = op.action;
626 out_event = op.event_channel_port;
627
609 spin_lock(&priv->lock); 628 spin_lock(&priv->lock);
610 629
611 list_for_each_entry(map, &priv->maps, next) { 630 list_for_each_entry(map, &priv->maps, next) {
@@ -624,12 +643,22 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
624 goto unlock_out; 643 goto unlock_out;
625 } 644 }
626 645
646 out_flags = map->notify.flags;
647 out_event = map->notify.event;
648
627 map->notify.flags = op.action; 649 map->notify.flags = op.action;
628 map->notify.addr = op.index - (map->index << PAGE_SHIFT); 650 map->notify.addr = op.index - (map->index << PAGE_SHIFT);
629 map->notify.event = op.event_channel_port; 651 map->notify.event = op.event_channel_port;
652
630 rc = 0; 653 rc = 0;
654
631 unlock_out: 655 unlock_out:
632 spin_unlock(&priv->lock); 656 spin_unlock(&priv->lock);
657
658 /* Drop the reference to the event channel we did not save in the map */
659 if (out_flags & UNMAP_NOTIFY_SEND_EVENT)
660 evtchn_put(out_event);
661
633 return rc; 662 return rc;
634} 663}
635 664