]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/tty/tty_io.c
tty: Destroy ldisc instance on hangup
[karo-tx-linux.git] / drivers / tty / tty_io.c
index 71a9409c8d7ee50859e4faa0f06ff8ba38f4e663..d3ecbb513fa14fd7a9f8b7df8c2c9c8093949812 100644 (file)
@@ -727,7 +727,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
        while (refs--)
                tty_kref_put(tty);
 
-       tty_ldisc_hangup(tty);
+       tty_ldisc_hangup(tty, cons_filp != NULL);
 
        spin_lock_irq(&tty->ctrl_lock);
        clear_bit(TTY_THROTTLED, &tty->flags);
@@ -752,10 +752,9 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
        } else if (tty->ops->hangup)
                tty->ops->hangup(tty);
        /*
-        * We don't want to have driver/ldisc interactions beyond
-        * the ones we did here. The driver layer expects no
-        * calls after ->hangup() from the ldisc side. However we
-        * can't yet guarantee all that.
+        * We don't want to have driver/ldisc interactions beyond the ones
+        * we did here. The driver layer expects no calls after ->hangup()
+        * from the ldisc side, which is now guaranteed.
         */
        set_bit(TTY_HUPPED, &tty->flags);
        tty_unlock(tty);
@@ -1068,6 +1067,8 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
        /* We want to wait for the line discipline to sort out in this
           situation */
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return hung_up_tty_read(file, buf, count, ppos);
        if (ld->ops->read)
                i = ld->ops->read(tty, file, buf, count);
        else
@@ -1242,6 +1243,8 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
        if (tty->ops->write_room == NULL)
                tty_err(tty, "missing write_room method\n");
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return hung_up_tty_write(file, buf, count, ppos);
        if (!ld->ops->write)
                ret = -EIO;
        else
@@ -1471,7 +1474,8 @@ static int tty_reopen(struct tty_struct *tty)
 
        tty->count++;
 
-       WARN_ON(!tty->ldisc);
+       if (!tty->ldisc)
+               return tty_ldisc_reinit(tty, tty->termios.c_line);
 
        return 0;
 }
@@ -2201,6 +2205,8 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
                return 0;
 
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return hung_up_tty_poll(filp, wait);
        if (ld->ops->poll)
                ret = ld->ops->poll(tty, filp, wait);
        tty_ldisc_deref(ld);
@@ -2290,6 +2296,8 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
                return -EFAULT;
        tty_audit_tiocsti(tty, ch);
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return -EIO;
        ld->ops->receive_buf(tty, &ch, &mbz, 1);
        tty_ldisc_deref(ld);
        return 0;
@@ -2654,13 +2662,13 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
 
 static int tiocsetd(struct tty_struct *tty, int __user *p)
 {
-       int ldisc;
+       int disc;
        int ret;
 
-       if (get_user(ldisc, p))
+       if (get_user(disc, p))
                return -EFAULT;
 
-       ret = tty_set_ldisc(tty, ldisc);
+       ret = tty_set_ldisc(tty, disc);
 
        return ret;
 }
@@ -2682,6 +2690,8 @@ static int tiocgetd(struct tty_struct *tty, int __user *p)
        int ret;
 
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return -EIO;
        ret = put_user(ld->ops->num, p);
        tty_ldisc_deref(ld);
        return ret;
@@ -2979,6 +2989,8 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        return retval;
        }
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return hung_up_tty_ioctl(file, cmd, arg);
        retval = -EINVAL;
        if (ld->ops->ioctl) {
                retval = ld->ops->ioctl(tty, file, cmd, arg);
@@ -3007,6 +3019,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
        }
 
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return hung_up_tty_compat_ioctl(file, cmd, arg);
        if (ld->ops->compat_ioctl)
                retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
        else