Merge branch 'topic/usb' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound...
[cascardo/linux.git] / drivers / char / hvc_console.c
index 465185f..35cca4c 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/spinlock.h>
 #include <linux/delay.h>
 #include <linux/freezer.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 
@@ -312,6 +313,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
        spin_lock_irqsave(&hp->lock, flags);
        /* Check and then increment for fast path open. */
        if (hp->count++ > 0) {
+               tty_kref_get(tty);
                spin_unlock_irqrestore(&hp->lock, flags);
                hvc_kick();
                return 0;
@@ -319,7 +321,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 
        tty->driver_data = hp;
 
-       hp->tty = tty;
+       hp->tty = tty_kref_get(tty);
 
        spin_unlock_irqrestore(&hp->lock, flags);
 
@@ -336,6 +338,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
                spin_lock_irqsave(&hp->lock, flags);
                hp->tty = NULL;
                spin_unlock_irqrestore(&hp->lock, flags);
+               tty_kref_put(tty);
                tty->driver_data = NULL;
                kref_put(&hp->kref, destroy_hvc_struct);
                printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
@@ -363,6 +366,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
                return;
 
        hp = tty->driver_data;
+
        spin_lock_irqsave(&hp->lock, flags);
 
        if (--hp->count == 0) {
@@ -389,6 +393,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
                spin_unlock_irqrestore(&hp->lock, flags);
        }
 
+       tty_kref_put(tty);
        kref_put(&hp->kref, destroy_hvc_struct);
 }
 
@@ -424,10 +429,11 @@ static void hvc_hangup(struct tty_struct *tty)
        spin_unlock_irqrestore(&hp->lock, flags);
 
        if (hp->ops->notifier_hangup)
-                       hp->ops->notifier_hangup(hp, hp->data);
+               hp->ops->notifier_hangup(hp, hp->data);
 
        while(temp_open_count) {
                --temp_open_count;
+               tty_kref_put(tty);
                kref_put(&hp->kref, destroy_hvc_struct);
        }
 }
@@ -592,7 +598,7 @@ int hvc_poll(struct hvc_struct *hp)
        }
 
        /* No tty attached, just skip */
-       tty = hp->tty;
+       tty = tty_kref_get(hp->tty);
        if (tty == NULL)
                goto bail;
 
@@ -672,6 +678,8 @@ int hvc_poll(struct hvc_struct *hp)
 
                tty_flip_buffer_push(tty);
        }
+       if (tty)
+               tty_kref_put(tty);
 
        return poll_mask;
 }
@@ -807,7 +815,7 @@ int hvc_remove(struct hvc_struct *hp)
        struct tty_struct *tty;
 
        spin_lock_irqsave(&hp->lock, flags);
-       tty = hp->tty;
+       tty = tty_kref_get(hp->tty);
 
        if (hp->index < MAX_NR_HVC_CONSOLES)
                vtermnos[hp->index] = -1;
@@ -819,18 +827,18 @@ int hvc_remove(struct hvc_struct *hp)
        /*
         * We 'put' the instance that was grabbed when the kref instance
         * was initialized using kref_init().  Let the last holder of this
-        * kref cause it to be removed, which will probably be the tty_hangup
+        * kref cause it to be removed, which will probably be the tty_vhangup
         * below.
         */
        kref_put(&hp->kref, destroy_hvc_struct);
 
        /*
-        * This function call will auto chain call hvc_hangup.  The tty should
-        * always be valid at this time unless a simultaneous tty close already
-        * cleaned up the hvc_struct.
+        * This function call will auto chain call hvc_hangup.
         */
-       if (tty)
-               tty_hangup(tty);
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(hvc_remove);