summary refs log tree commit diff
path: root/drivers/char
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2008-10-12 21:51:31 +0000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-15 10:13:28 +1100
commiteef2622a9fcfa964073333ea72c7c9cd20ad45e6 (patch)
tree39d698245b018baf78cb03a369bcde2051b68ff9 /drivers/char
parentf5ea64dcbad89875d130596df14c9b25d994a737 (diff)
downloadlinux-eef2622a9fcfa964073333ea72c7c9cd20ad45e6.tar.gz
hvc_console: Fix free_irq in spinlocked section
    commit 611e097d7707741a336a0677d9d69bec40f29f3d
    Author: Christian Borntraeger <borntraeger@de.ibm.com>
    hvc_console: rework setup to replace irq functions with callbacks
    introduced a spinlock recursion problem. The notifier_del is
    called with a lock held, and in turns calls free_irq which then
    complains when manipulating procfs. This fixes it by moving the
    call to the notifier to outside of the locked section.

Signed-off-by: Christian Borntraeger<borntraeger@de.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/hvc_console.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index fd64137b1ab9..f2e4caf70599 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -367,13 +367,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
 	spin_lock_irqsave(&hp->lock, flags);
 
 	if (--hp->count == 0) {
-		if (hp->ops->notifier_del)
-			hp->ops->notifier_del(hp, hp->data);
-
 		/* We are done with the tty pointer now. */
 		hp->tty = NULL;
 		spin_unlock_irqrestore(&hp->lock, flags);
 
+		if (hp->ops->notifier_del)
+			hp->ops->notifier_del(hp, hp->data);
+
 		/*
 		 * Chain calls chars_in_buffer() and returns immediately if
 		 * there is no buffered data otherwise sleeps on a wait queue
@@ -416,11 +416,11 @@ static void hvc_hangup(struct tty_struct *tty)
 	hp->n_outbuf = 0;
 	hp->tty = NULL;
 
+	spin_unlock_irqrestore(&hp->lock, flags);
+
 	if (hp->ops->notifier_del)
 			hp->ops->notifier_del(hp, hp->data);
 
-	spin_unlock_irqrestore(&hp->lock, flags);
-
 	while(temp_open_count) {
 		--temp_open_count;
 		kref_put(&hp->kref, destroy_hvc_struct);