diff options
author | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-05-28 18:28:27 -0400 |
---|---|---|
committer | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-05-28 18:28:27 -0400 |
commit | 3f5e554f669098c84c82ce75e7577f7e0f3fccde (patch) | |
tree | fb8147269b5f9b412e03e3539fdb2dd3cedc0ace /drivers/xen | |
parent | 1a1a17cddbfb1f81222b3f18ee8530c41fbc3b82 (diff) |
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/xen')
-rw-r--r-- | drivers/xen/evtchn.c | 13 |
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, | |||
375 | break; | 375 | break; |
376 | } | 376 | } |
377 | 377 | ||
378 | evtchn_unbind_from_user(u, unbind.port); | 378 | disable_irq(irq_from_evtchn(unbind.port)); |
379 | 379 | ||
380 | spin_unlock_irq(&port_user_lock); | 380 | spin_unlock_irq(&port_user_lock); |
381 | 381 | ||
382 | evtchn_unbind_from_user(u, unbind.port); | ||
383 | |||
382 | rc = 0; | 384 | rc = 0; |
383 | break; | 385 | break; |
384 | } | 386 | } |
@@ -484,11 +486,18 @@ static int evtchn_release(struct inode *inode, struct file *filp) | |||
484 | if (get_port_user(i) != u) | 486 | if (get_port_user(i) != u) |
485 | continue; | 487 | continue; |
486 | 488 | ||
487 | evtchn_unbind_from_user(get_port_user(i), i); | 489 | disable_irq(irq_from_evtchn(i)); |
488 | } | 490 | } |
489 | 491 | ||
490 | spin_unlock_irq(&port_user_lock); | 492 | spin_unlock_irq(&port_user_lock); |
491 | 493 | ||
494 | for (i = 0; i < NR_EVENT_CHANNELS; i++) { | ||
495 | if (get_port_user(i) != u) | ||
496 | continue; | ||
497 | |||
498 | evtchn_unbind_from_user(get_port_user(i), i); | ||
499 | } | ||
500 | |||
492 | kfree(u->name); | 501 | kfree(u->name); |
493 | kfree(u); | 502 | kfree(u); |
494 | 503 | ||