hvc_console: Fix free_irq in spinlocked section
authorChristian Borntraeger <borntraeger@de.ibm.com>
Sun, 12 Oct 2008 21:51:31 +0000 (21:51 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 14 Oct 2008 23:13:28 +0000 (10:13 +1100)
    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>
drivers/char/hvc_console.c

index fd64137b1ab915fb9384fa674ad54be65c5f0074..f2e4caf70599efcafa2e235a13fb764545d9a0f9 100644 (file)
@@ -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);