tty: Remove TTY_CLOSING
[firefly-linux-kernel-4.4.55.git] / drivers / tty / tty_io.c
index 07275d0e30a25d41a79c7a4bd702c5d234819616..ea8c6cae8d1254fc5b0f9a53976b3e0da8cdd00f 100644 (file)
@@ -516,8 +516,11 @@ static void __proc_set_tty(struct tty_struct *tty)
 {
        unsigned long flags;
 
-       /* We should not have a session or pgrp to put here but.... */
        spin_lock_irqsave(&tty->ctrl_lock, flags);
+       /*
+        * The session and fg pgrp references will be non-NULL if
+        * tiocsctty() is stealing the controlling tty
+        */
        put_pid(tty->session);
        put_pid(tty->pgrp);
        tty->pgrp = get_pid(task_pgrp(current));
@@ -687,9 +690,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
                return;
        }
 
-       /* some functions below drop BTM, so we need this bit */
-       set_bit(TTY_HUPPING, &tty->flags);
-
        /* inuse_filps is protected by the single tty lock,
           this really needs to change if we want to flush the
           workqueue with the lock held */
@@ -714,10 +714,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
        while (refs--)
                tty_kref_put(tty);
 
-       /*
-        * it drops BTM and thus races with reopen
-        * we protect the race by TTY_HUPPING
-        */
        tty_ldisc_hangup(tty);
 
        spin_lock_irq(&tty->ctrl_lock);
@@ -749,8 +745,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
         * can't yet guarantee all that.
         */
        set_bit(TTY_HUPPED, &tty->flags);
-       clear_bit(TTY_HUPPING, &tty->flags);
-
        tty_unlock(tty);
 
        if (f)
@@ -1203,7 +1197,7 @@ void tty_write_message(struct tty_struct *tty, char *msg)
        if (tty) {
                mutex_lock(&tty->atomic_write_lock);
                tty_lock(tty);
-               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
+               if (tty->ops->write && tty->count > 0) {
                        tty_unlock(tty);
                        tty->ops->write(tty, msg, strlen(msg));
                } else
@@ -1350,19 +1344,24 @@ static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p)
  *     @driver: the driver for the tty
  *     @idx:    the minor number
  *
- *     Return the tty, if found or ERR_PTR() otherwise.
+ *     Return the tty, if found. If not found, return NULL or ERR_PTR() if the
+ *     driver lookup() method returns an error.
  *
- *     Locking: tty_mutex must be held. If tty is found, the mutex must
- *     be held until the 'fast-open' is also done. Will change once we
- *     have refcounting in the driver and per driver locking
+ *     Locking: tty_mutex must be held. If the tty is found, bump the tty kref.
  */
 static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
                struct inode *inode, int idx)
 {
+       struct tty_struct *tty;
+
        if (driver->ops->lookup)
-               return driver->ops->lookup(driver, inode, idx);
+               tty = driver->ops->lookup(driver, inode, idx);
+       else
+               tty = driver->ttys[idx];
 
-       return driver->ttys[idx];
+       if (!IS_ERR(tty))
+               tty_kref_get(tty);
+       return tty;
 }
 
 /**
@@ -1450,29 +1449,21 @@ void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)
  *     @tty    - the tty to open
  *
  *     Return 0 on success, -errno on error.
+ *     Re-opens on master ptys are not allowed and return -EIO.
  *
- *     Locking: tty_mutex must be held from the time the tty was found
- *              till this open completes.
+ *     Locking: Caller must hold tty_lock
  */
 static int tty_reopen(struct tty_struct *tty)
 {
        struct tty_driver *driver = tty->driver;
 
-       if (test_bit(TTY_CLOSING, &tty->flags) ||
-                       test_bit(TTY_HUPPING, &tty->flags))
+       if (!tty->count)
                return -EIO;
 
        if (driver->type == TTY_DRIVER_TYPE_PTY &&
-           driver->subtype == PTY_TYPE_MASTER) {
-               /*
-                * special case for PTY masters: only one open permitted,
-                * and the slave side open count is incremented as well.
-                */
-               if (tty->count)
-                       return -EIO;
+           driver->subtype == PTY_TYPE_MASTER)
+               return -EIO;
 
-               tty->link->count++;
-       }
        tty->count++;
 
        WARN_ON(!tty->ldisc);
@@ -1888,16 +1879,6 @@ int tty_release(struct inode *inode, struct file *filp)
        /*
         * Perform some housekeeping before deciding whether to return.
         *
-        * Set the TTY_CLOSING flag if this was the last open.  In the
-        * case of a pty we may have to wait around for the other side
-        * to close, and TTY_CLOSING makes sure we can't be reopened.
-        */
-       if (tty_closing)
-               set_bit(TTY_CLOSING, &tty->flags);
-       if (o_tty_closing)
-               set_bit(TTY_CLOSING, &o_tty->flags);
-
-       /*
         * If _either_ side is closing, make sure there aren't any
         * processes that still think tty or o_tty is their controlling
         * tty.
@@ -1912,7 +1893,7 @@ int tty_release(struct inode *inode, struct file *filp)
 
        mutex_unlock(&tty_mutex);
        tty_unlock_pair(tty, o_tty);
-       /* At this point the TTY_CLOSING flag should ensure a dead tty
+       /* At this point, the tty->count == 0 should ensure a dead tty
           cannot be re-opened by a racing opener */
 
        /* check whether both sides are closing ... */
@@ -1949,20 +1930,20 @@ int tty_release(struct inode *inode, struct file *filp)
 }
 
 /**
- *     tty_open_current_tty - get tty of current task for open
+ *     tty_open_current_tty - get locked tty of current task
  *     @device: device number
  *     @filp: file pointer to tty
- *     @return: tty of the current task iff @device is /dev/tty
+ *     @return: locked tty of the current task iff @device is /dev/tty
+ *
+ *     Performs a re-open of the current task's controlling tty.
  *
  *     We cannot return driver and index like for the other nodes because
  *     devpts will not work then. It expects inodes to be from devpts FS.
- *
- *     We need to move to returning a refcounted object from all the lookup
- *     paths including this one.
  */
 static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
 {
        struct tty_struct *tty;
+       int retval;
 
        if (device != MKDEV(TTYAUX_MAJOR, 0))
                return NULL;
@@ -1973,9 +1954,14 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
 
        filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
        /* noctty = 1; */
-       tty_kref_put(tty);
-       /* FIXME: we put a reference and return a TTY! */
-       /* This is only safe because the caller holds tty_mutex */
+       tty_lock(tty);
+       tty_kref_put(tty);      /* safe to drop the kref now */
+
+       retval = tty_reopen(tty);
+       if (retval < 0) {
+               tty_unlock(tty);
+               tty = ERR_PTR(retval);
+       }
        return tty;
 }
 
@@ -2073,13 +2059,9 @@ retry_open:
        index  = -1;
        retval = 0;
 
-       mutex_lock(&tty_mutex);
-       /* This is protected by the tty_mutex */
        tty = tty_open_current_tty(device, filp);
-       if (IS_ERR(tty)) {
-               retval = PTR_ERR(tty);
-               goto err_unlock;
-       } else if (!tty) {
+       if (!tty) {
+               mutex_lock(&tty_mutex);
                driver = tty_lookup_driver(device, filp, &noctty, &index);
                if (IS_ERR(driver)) {
                        retval = PTR_ERR(driver);
@@ -2092,21 +2074,25 @@ retry_open:
                        retval = PTR_ERR(tty);
                        goto err_unlock;
                }
-       }
 
-       if (tty) {
-               tty_lock(tty);
-               retval = tty_reopen(tty);
-               if (retval < 0) {
-                       tty_unlock(tty);
-                       tty = ERR_PTR(retval);
+               if (tty) {
+                       mutex_unlock(&tty_mutex);
+                       tty_lock(tty);
+                       /* safe to drop the kref from tty_driver_lookup_tty() */
+                       tty_kref_put(tty);
+                       retval = tty_reopen(tty);
+                       if (retval < 0) {
+                               tty_unlock(tty);
+                               tty = ERR_PTR(retval);
+                       }
+               } else { /* Returns with the tty_lock held for now */
+                       tty = tty_init_dev(driver, index);
+                       mutex_unlock(&tty_mutex);
                }
-       } else  /* Returns with the tty_lock held for now */
-               tty = tty_init_dev(driver, index);
 
-       mutex_unlock(&tty_mutex);
-       if (driver)
                tty_driver_kref_put(driver);
+       }
+
        if (IS_ERR(tty)) {
                retval = PTR_ERR(tty);
                goto err_file;