summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2010-05-29 02:28:27 +0400
committerJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2010-05-29 02:28:27 +0400
commit3f5e554f669098c84c82ce75e7577f7e0f3fccde (patch)
treefb8147269b5f9b412e03e3539fdb2dd3cedc0ace /drivers
parent1a1a17cddbfb1f81222b3f18ee8530c41fbc3b82 (diff)
downloadlinux-3f5e554f669098c84c82ce75e7577f7e0f3fccde.tar.xz
xen/evtchn: don't do unbind_from_irqhandler under spinlock
unbind_from_irqhandler can end up doing /proc operations, which can't happen under a spinlock. So before removing the IRQ handler, disable the irq under the port_user lock (masking the underlying event channel and making sure the irq handler isn't running concurrently and won't start running), then remove the handler without the lock. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/xen/evtchn.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index f79ac5ca3793..6a3a12945d02 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -375,10 +375,12 @@ static long evtchn_ioctl(struct file *file,
break;
}
- evtchn_unbind_from_user(u, unbind.port);
+ disable_irq(irq_from_evtchn(unbind.port));
spin_unlock_irq(&port_user_lock);
+ evtchn_unbind_from_user(u, unbind.port);
+
rc = 0;
break;
}
@@ -484,11 +486,18 @@ static int evtchn_release(struct inode *inode, struct file *filp)
if (get_port_user(i) != u)
continue;
- evtchn_unbind_from_user(get_port_user(i), i);
+ disable_irq(irq_from_evtchn(i));
}
spin_unlock_irq(&port_user_lock);
+ for (i = 0; i < NR_EVENT_CHANNELS; i++) {
+ if (get_port_user(i) != u)
+ continue;
+
+ evtchn_unbind_from_user(get_port_user(i), i);
+ }
+
kfree(u->name);
kfree(u);