diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 13:09:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 13:09:59 -0500 |
commit | 90160371b3a3e67ef78d68210a94dd30664a703d (patch) | |
tree | 2841ea811be129133cf9b83d9c3badd96e7ffab4 /drivers/xen/gntdev.c | |
parent | ae5cfc0546ca2698b9dcddf72accbd70e57590a0 (diff) | |
parent | 6c254de16a1d14c1ac931d3aa08dc88ac9fc582b (diff) |
Merge branch 'stable/for-linus-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen
* 'stable/for-linus-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen: (37 commits)
xen/pciback: Expand the warning message to include domain id.
xen/pciback: Fix "device has been assigned to X domain!" warning
xen/pciback: Move the PCI_DEV_FLAGS_ASSIGNED ops to the "[un|]bind"
xen/xenbus: don't reimplement kvasprintf via a fixed size buffer
xenbus: maximum buffer size is XENSTORE_PAYLOAD_MAX
xen/xenbus: Reject replies with payload > XENSTORE_PAYLOAD_MAX.
Xen: consolidate and simplify struct xenbus_driver instantiation
xen-gntalloc: introduce missing kfree
xen/xenbus: Fix compile error - missing header for xen_initial_domain()
xen/netback: Enable netback on HVM guests
xen/grant-table: Support mappings required by blkback
xenbus: Use grant-table wrapper functions
xenbus: Support HVM backends
xen/xenbus-frontend: Fix compile error with randconfig
xen/xenbus-frontend: Make error message more clear
xen/privcmd: Remove unused support for arch specific privcmp mmap
xen: Add xenbus_backend device
xen: Add xenbus device driver
xen: Add privcmd device driver
xen/gntalloc: fix reference counts on multi-page mappings
...
Diffstat (limited to 'drivers/xen/gntdev.c')
-rw-r--r-- | drivers/xen/gntdev.c | 34 |
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 | ||