Эх сурвалжийг харах

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>
Jeremy Fitzhardinge 15 жил өмнө
parent
commit
3f5e554f66

+ 11 - 2
drivers/xen/evtchn.c

@@ -375,10 +375,12 @@ static long evtchn_ioctl(struct file *file,
 			break;
 			break;
 		}
 		}
 
 
-		evtchn_unbind_from_user(u, unbind.port);
+		disable_irq(irq_from_evtchn(unbind.port));
 
 
 		spin_unlock_irq(&port_user_lock);
 		spin_unlock_irq(&port_user_lock);
 
 
+		evtchn_unbind_from_user(u, unbind.port);
+
 		rc = 0;
 		rc = 0;
 		break;
 		break;
 	}
 	}
@@ -484,11 +486,18 @@ static int evtchn_release(struct inode *inode, struct file *filp)
 		if (get_port_user(i) != u)
 		if (get_port_user(i) != u)
 			continue;
 			continue;
 
 
-		evtchn_unbind_from_user(get_port_user(i), i);
+		disable_irq(irq_from_evtchn(i));
 	}
 	}
 
 
 	spin_unlock_irq(&port_user_lock);
 	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->name);
 	kfree(u);
 	kfree(u);