tty: push the BKL down into the handlers a bit
authorAlan Cox <alan@linux.intel.com>
Mon, 30 Nov 2009 13:18:29 +0000 (13:18 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 11 Dec 2009 23:18:08 +0000 (15:18 -0800)
Start trying to untangle the remaining BKL mess

Updated to fix missing unlock_kernel noted by Dan Carpenter

Signed-off-by: Alan "I must be out of my tree" Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/char/pty.c
drivers/char/tty_io.c
drivers/char/tty_ldisc.c
include/linux/tty.h

index d86c0bc05c1c7839b4db8873daf96a21fd32cfe8..385c44b3034f4000df9d8a4ad917f3e030c4a143 100644 (file)
@@ -659,7 +659,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
        if (!retval)
                return 0;
 out1:
-       tty_release_dev(filp);
+       tty_release(inode, filp);
        return retval;
 out:
        devpts_kill_index(inode, index);
index 59499ee0fe6a11850eb851ad829dbb1a1b0d6dbc..1e2413093615be802b2c8eb7c62940660b6c6c6a 100644 (file)
@@ -142,7 +142,6 @@ ssize_t redirected_tty_write(struct file *, const char __user *,
                                                        size_t, loff_t *);
 static unsigned int tty_poll(struct file *, poll_table *);
 static int tty_open(struct inode *, struct file *);
-static int tty_release(struct inode *, struct file *);
 long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 #ifdef CONFIG_COMPAT
 static long tty_compat_ioctl(struct file *file, unsigned int cmd,
@@ -1017,14 +1016,16 @@ out:
 
 void tty_write_message(struct tty_struct *tty, char *msg)
 {
-       lock_kernel();
        if (tty) {
                mutex_lock(&tty->atomic_write_lock);
-               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags))
+               lock_kernel();
+               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
+                       unlock_kernel();
                        tty->ops->write(tty, msg, strlen(msg));
+               } else
+                       unlock_kernel();
                tty_write_unlock(tty);
        }
-       unlock_kernel();
        return;
 }
 
@@ -1202,14 +1203,21 @@ static int tty_driver_install_tty(struct tty_driver *driver,
                                                struct tty_struct *tty)
 {
        int idx = tty->index;
+       int ret;
 
-       if (driver->ops->install)
-               return driver->ops->install(driver, tty);
+       if (driver->ops->install) {
+               lock_kernel();
+               ret = driver->ops->install(driver, tty);
+               unlock_kernel();
+               return ret;
+       }
 
        if (tty_init_termios(tty) == 0) {
+               lock_kernel();
                tty_driver_kref_get(driver);
                tty->count++;
                driver->ttys[idx] = tty;
+               unlock_kernel();
                return 0;
        }
        return -ENOMEM;
@@ -1302,10 +1310,14 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
        struct tty_struct *tty;
        int retval;
 
+       lock_kernel();
        /* Check if pty master is being opened multiple times */
        if (driver->subtype == PTY_TYPE_MASTER &&
-               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
+               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
+               unlock_kernel();
                return ERR_PTR(-EIO);
+       }
+       unlock_kernel();
 
        /*
         * First time open is complex, especially for PTY devices.
@@ -1335,8 +1347,9 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
         * If we fail here just call release_tty to clean up.  No need
         * to decrement the use counts, as release_tty doesn't care.
         */
-
+       lock_kernel();
        retval = tty_ldisc_setup(tty, tty->link);
+       unlock_kernel();
        if (retval)
                goto release_mem_out;
        return tty;
@@ -1350,7 +1363,9 @@ release_mem_out:
        if (printk_ratelimit())
                printk(KERN_INFO "tty_init_dev: ldisc open failed, "
                                 "clearing slot %d\n", idx);
+       lock_kernel();
        release_tty(tty, idx);
+       unlock_kernel();
        return ERR_PTR(retval);
 }
 
@@ -1464,7 +1479,17 @@ static void release_tty(struct tty_struct *tty, int idx)
        tty_kref_put(tty);
 }
 
-/*
+/**
+ *     tty_release             -       vfs callback for close
+ *     @inode: inode of tty
+ *     @filp: file pointer for handle to tty
+ *
+ *     Called the last time each file handle is closed that references
+ *     this tty. There may however be several such references.
+ *
+ *     Locking:
+ *             Takes bkl. See tty_release_dev
+ *
  * Even releasing the tty structures is a tricky business.. We have
  * to be very careful that the structures are all released at the
  * same time, as interrupts might otherwise get the wrong pointers.
@@ -1472,20 +1497,20 @@ static void release_tty(struct tty_struct *tty, int idx)
  * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
  * lead to double frees or releasing memory still in use.
  */
-void tty_release_dev(struct file *filp)
+
+int tty_release(struct inode *inode, struct file *filp)
 {
        struct tty_struct *tty, *o_tty;
        int     pty_master, tty_closing, o_tty_closing, do_sleep;
        int     devpts;
        int     idx;
        char    buf[64];
-       struct  inode *inode;
 
-       inode = filp->f_path.dentry->d_inode;
        tty = (struct tty_struct *)filp->private_data;
        if (tty_paranoia_check(tty, inode, "tty_release_dev"))
-               return;
+               return 0;
 
+       lock_kernel();
        check_tty_count(tty, "tty_release_dev");
 
        tty_fasync(-1, filp, 0);
@@ -1500,19 +1525,22 @@ void tty_release_dev(struct file *filp)
        if (idx < 0 || idx >= tty->driver->num) {
                printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
                                  "free (%s)\n", tty->name);
-               return;
+               unlock_kernel();
+               return 0;
        }
        if (!devpts) {
                if (tty != tty->driver->ttys[idx]) {
+                       unlock_kernel();
                        printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
                               "for (%s)\n", idx, tty->name);
-                       return;
+                       return 0;
                }
                if (tty->termios != tty->driver->termios[idx]) {
+                       unlock_kernel();
                        printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
                               "for (%s)\n",
                               idx, tty->name);
-                       return;
+                       return 0;
                }
        }
 #endif
@@ -1526,26 +1554,30 @@ void tty_release_dev(struct file *filp)
        if (tty->driver->other &&
             !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
                if (o_tty != tty->driver->other->ttys[idx]) {
+                       unlock_kernel();
                        printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
                                          "not o_tty for (%s)\n",
                               idx, tty->name);
-                       return;
+                       return 0 ;
                }
                if (o_tty->termios != tty->driver->other->termios[idx]) {
+                       unlock_kernel();
                        printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
                                          "not o_termios for (%s)\n",
                               idx, tty->name);
-                       return;
+                       return 0;
                }
                if (o_tty->link != tty) {
+                       unlock_kernel();
                        printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
-                       return;
+                       return 0;
                }
        }
 #endif
        if (tty->ops->close)
                tty->ops->close(tty, filp);
 
+       unlock_kernel();
        /*
         * Sanity check: if tty->count is going to zero, there shouldn't be
         * any waiters on tty->read_wait or tty->write_wait.  We test the
@@ -1568,6 +1600,7 @@ void tty_release_dev(struct file *filp)
                   opens on /dev/tty */
 
                mutex_lock(&tty_mutex);
+               lock_kernel();
                tty_closing = tty->count <= 1;
                o_tty_closing = o_tty &&
                        (o_tty->count <= (pty_master ? 1 : 0));
@@ -1598,6 +1631,7 @@ void tty_release_dev(struct file *filp)
 
                printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
                                    "active!\n", tty_name(tty, buf));
+               unlock_kernel();
                mutex_unlock(&tty_mutex);
                schedule();
        }
@@ -1661,8 +1695,10 @@ void tty_release_dev(struct file *filp)
        mutex_unlock(&tty_mutex);
 
        /* check whether both sides are closing ... */
-       if (!tty_closing || (o_tty && !o_tty_closing))
-               return;
+       if (!tty_closing || (o_tty && !o_tty_closing)) {
+               unlock_kernel();
+               return 0;
+       }
 
 #ifdef TTY_DEBUG_HANGUP
        printk(KERN_DEBUG "freeing tty structure...");
@@ -1680,10 +1716,12 @@ void tty_release_dev(struct file *filp)
        /* Make this pty number available for reallocation */
        if (devpts)
                devpts_kill_index(inode, idx);
+       unlock_kernel();
+       return 0;
 }
 
 /**
- *     __tty_open              -       open a tty device
+ *     tty_open                -       open a tty device
  *     @inode: inode of device file
  *     @filp: file pointer to tty
  *
@@ -1703,7 +1741,7 @@ void tty_release_dev(struct file *filp)
  *              ->siglock protects ->signal/->sighand
  */
 
-static int __tty_open(struct inode *inode, struct file *filp)
+static int tty_open(struct inode *inode, struct file *filp)
 {
        struct tty_struct *tty = NULL;
        int noctty, retval;
@@ -1720,10 +1758,12 @@ retry_open:
        retval = 0;
 
        mutex_lock(&tty_mutex);
+       lock_kernel();
 
        if (device == MKDEV(TTYAUX_MAJOR, 0)) {
                tty = get_current_tty();
                if (!tty) {
+                       unlock_kernel();
                        mutex_unlock(&tty_mutex);
                        return -ENXIO;
                }
@@ -1755,12 +1795,14 @@ retry_open:
                                goto got_driver;
                        }
                }
+               unlock_kernel();
                mutex_unlock(&tty_mutex);
                return -ENODEV;
        }
 
        driver = get_tty_driver(device, &index);
        if (!driver) {
+               unlock_kernel();
                mutex_unlock(&tty_mutex);
                return -ENODEV;
        }
@@ -1770,6 +1812,7 @@ got_driver:
                tty = tty_driver_lookup_tty(driver, inode, index);
 
                if (IS_ERR(tty)) {
+                       unlock_kernel();
                        mutex_unlock(&tty_mutex);
                        return PTR_ERR(tty);
                }
@@ -1784,8 +1827,10 @@ got_driver:
 
        mutex_unlock(&tty_mutex);
        tty_driver_kref_put(driver);
-       if (IS_ERR(tty))
+       if (IS_ERR(tty)) {
+               unlock_kernel();
                return PTR_ERR(tty);
+       }
 
        filp->private_data = tty;
        file_move(filp, &tty->tty_files);
@@ -1813,11 +1858,15 @@ got_driver:
                printk(KERN_DEBUG "error %d in opening %s...", retval,
                       tty->name);
 #endif
-               tty_release_dev(filp);
-               if (retval != -ERESTARTSYS)
+               tty_release(inode, filp);
+               if (retval != -ERESTARTSYS) {
+                       unlock_kernel();
                        return retval;
-               if (signal_pending(current))
+               }
+               if (signal_pending(current)) {
+                       unlock_kernel();
                        return retval;
+               }
                schedule();
                /*
                 * Need to reset f_op in case a hangup happened.
@@ -1826,8 +1875,11 @@ got_driver:
                        filp->f_op = &tty_fops;
                goto retry_open;
        }
+       unlock_kernel();
+
 
        mutex_lock(&tty_mutex);
+       lock_kernel();
        spin_lock_irq(&current->sighand->siglock);
        if (!noctty &&
            current->signal->leader &&
@@ -1835,44 +1887,13 @@ got_driver:
            tty->session == NULL)
                __proc_set_tty(current, tty);
        spin_unlock_irq(&current->sighand->siglock);
+       unlock_kernel();
        mutex_unlock(&tty_mutex);
        return 0;
 }
 
-/* BKL pushdown: scary code avoidance wrapper */
-static int tty_open(struct inode *inode, struct file *filp)
-{
-       int ret;
-
-       lock_kernel();
-       ret = __tty_open(inode, filp);
-       unlock_kernel();
-       return ret;
-}
 
 
-
-
-/**
- *     tty_release             -       vfs callback for close
- *     @inode: inode of tty
- *     @filp: file pointer for handle to tty
- *
- *     Called the last time each file handle is closed that references
- *     this tty. There may however be several such references.
- *
- *     Locking:
- *             Takes bkl. See tty_release_dev
- */
-
-static int tty_release(struct inode *inode, struct file *filp)
-{
-       lock_kernel();
-       tty_release_dev(filp);
-       unlock_kernel();
-       return 0;
-}
-
 /**
  *     tty_poll        -       check tty status
  *     @filp: file being polled
@@ -2317,9 +2338,7 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
        if (get_user(ldisc, p))
                return -EFAULT;
 
-       lock_kernel();
        ret = tty_set_ldisc(tty, ldisc);
-       unlock_kernel();
 
        return ret;
 }
index feb55075819bab4f7d9f75ce11f7aa7232ba9dc1..d914e77f7f0167d242a0b00c86cd478d53940773 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
 
+#include <linux/smp_lock.h>    /* For the moment */
+
 #include <linux/kmod.h>
 #include <linux/nsproxy.h>
 
@@ -545,6 +547,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        if (IS_ERR(new_ldisc))
                return PTR_ERR(new_ldisc);
 
+       lock_kernel();
        /*
         *      We need to look at the tty locking here for pty/tty pairs
         *      when both sides try to change in parallel.
@@ -558,6 +561,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
         */
 
        if (tty->ldisc->ops->num == ldisc) {
+               unlock_kernel();
                tty_ldisc_put(new_ldisc);
                return 0;
        }
@@ -569,6 +573,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
        tty_wait_until_sent(tty, 0);
 
+       unlock_kernel();
        mutex_lock(&tty->ldisc_mutex);
 
        /*
@@ -582,6 +587,9 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
                        test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
                mutex_lock(&tty->ldisc_mutex);
        }
+
+       lock_kernel();
+
        set_bit(TTY_LDISC_CHANGING, &tty->flags);
 
        /*
@@ -592,6 +600,8 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        tty->receive_room = 0;
 
        o_ldisc = tty->ldisc;
+
+       unlock_kernel();
        /*
         *      Make sure we don't change while someone holds a
         *      reference to the line discipline. The TTY_LDISC bit
@@ -617,12 +627,14 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        flush_scheduled_work();
 
        mutex_lock(&tty->ldisc_mutex);
+       lock_kernel();
        if (test_bit(TTY_HUPPED, &tty->flags)) {
                /* We were raced by the hangup method. It will have stomped
                   the ldisc data and closed the ldisc down */
                clear_bit(TTY_LDISC_CHANGING, &tty->flags);
                mutex_unlock(&tty->ldisc_mutex);
                tty_ldisc_put(new_ldisc);
+               unlock_kernel();
                return -EIO;
        }
 
@@ -664,6 +676,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        if (o_work)
                schedule_delayed_work(&o_tty->buf.work, 1);
        mutex_unlock(&tty->ldisc_mutex);
+       unlock_kernel();
        return retval;
 }
 
index e6da667ba34df265535e8a1d15feef4611829bd1..405a9035fe40601114e02d77a98aa0090bcd8646 100644 (file)
@@ -449,7 +449,7 @@ extern void initialize_tty_struct(struct tty_struct *tty,
                struct tty_driver *driver, int idx);
 extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
                                                                int first_ok);
-extern void tty_release_dev(struct file *filp);
+extern int tty_release(struct inode *inode, struct file *filp);
 extern int tty_init_termios(struct tty_struct *tty);
 
 extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);