Merge branch 'master' into gfs2
[pandora-kernel.git] / drivers / char / tty_io.c
index 18085a2..3337417 100644 (file)
@@ -129,6 +129,7 @@ LIST_HEAD(tty_drivers);                     /* linked list of tty drivers */
 /* Semaphore to protect creating and releasing a tty. This is shared with
    vt.c for deeply disgusting hack reasons */
 DEFINE_MUTEX(tty_mutex);
+EXPORT_SYMBOL(tty_mutex);
 
 #ifdef CONFIG_UNIX98_PTYS
 extern struct tty_driver *ptm_driver;  /* Unix98 pty masters; for /dev/ptmx */
@@ -618,9 +619,9 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
  
 static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
 {
-       down(&tty->termios_sem);
+       mutex_lock(&tty->termios_mutex);
        tty->termios->c_line = num;
-       up(&tty->termios_sem);
+       mutex_unlock(&tty->termios_mutex);
 }
 
 /*
@@ -1338,9 +1339,9 @@ static void do_tty_hangup(void *data)
         */
        if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
        {
-               down(&tty->termios_sem);
+               mutex_lock(&tty->termios_mutex);
                *tty->termios = tty->driver->init_termios;
-               up(&tty->termios_sem);
+               mutex_unlock(&tty->termios_mutex);
        }
        
        /* Defer ldisc switch */
@@ -2064,8 +2065,9 @@ fail_no_mem:
 
        /* call the tty release_mem routine to clean out this slot */
 release_mem_out:
-       printk(KERN_INFO "init_dev: ldisc open failed, "
-                        "clearing slot %d\n", idx);
+       if (printk_ratelimit())
+               printk(KERN_INFO "init_dev: ldisc open failed, "
+                                "clearing slot %d\n", idx);
        release_mem(tty, idx);
        goto end_init;
 }
@@ -2718,6 +2720,8 @@ static int tty_fasync(int fd, struct file * filp, int on)
  *     Locking:
  *             Called functions take tty_ldisc_lock
  *             current->signal->tty check is safe without locks
+ *
+ *     FIXME: may race normal receive processing
  */
 
 static int tiocsti(struct tty_struct *tty, char __user *p)
@@ -2740,18 +2744,21 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
  *     @tty; tty
  *     @arg: user buffer for result
  *
- *     Copies the kernel idea of the window size into the user buffer. No
- *     locking is done.
+ *     Copies the kernel idea of the window size into the user buffer.
  *
- *     FIXME: Returning random values racing a window size set is wrong
- *     should lock here against that
+ *     Locking: tty->termios_sem is taken to ensure the winsize data
+ *             is consistent.
  */
 
 static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg)
 {
-       if (copy_to_user(arg, &tty->winsize, sizeof(*arg)))
-               return -EFAULT;
-       return 0;
+       int err;
+
+       mutex_lock(&tty->termios_mutex);
+       err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
+       mutex_unlock(&tty->termios_mutex);
+
+       return err ? -EFAULT: 0;
 }
 
 /**
@@ -2779,14 +2786,15 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
        if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
                return -EFAULT;
 
-       down(&tty->termios_sem);
+       mutex_lock(&tty->termios_mutex);
        if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg)))
                goto done;
 
 #ifdef CONFIG_VT
        if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) {
-               if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row)) {
-                       up(&tty->termios_sem);
+               if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col,
+                                       tmp_ws.ws_row)) {
+                       mutex_unlock(&tty->termios_mutex);
                        return -ENXIO;
                }
        }
@@ -2798,7 +2806,7 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
        tty->winsize = tmp_ws;
        real_tty->winsize = tmp_ws;
 done:
-       up(&tty->termios_sem);
+       mutex_unlock(&tty->termios_mutex);
        return 0;
 }
 
@@ -2873,9 +2881,7 @@ static int fionbio(struct file *file, int __user *p)
  *     Locking:
  *             Takes tasklist lock internally to walk sessions
  *             Takes task_lock() when updating signal->tty
- *
- *     FIXME: tty_mutex is needed to protect signal->tty references.
- *     FIXME: why task_lock on the signal->tty reference ??
+ *             Takes tty_mutex() to protect tty instance
  *
  */
 
@@ -2910,9 +2916,11 @@ static int tiocsctty(struct tty_struct *tty, int arg)
                } else
                        return -EPERM;
        }
+       mutex_lock(&tty_mutex);
        task_lock(current);
        current->signal->tty = tty;
        task_unlock(current);
+       mutex_unlock(&tty_mutex);
        current->signal->tty_old_pgrp = 0;
        tty->session = current->signal->session;
        tty->pgrp = process_group(current);
@@ -2952,8 +2960,6 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
  *     permitted where the tty session is our session.
  *
  *     Locking: None
- *
- *     FIXME: current->signal->tty referencing is unsafe.
  */
 
 static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
@@ -3032,19 +3038,20 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
  *     timed break functionality.
  *
  *     Locking:
- *             None
+ *             atomic_write_lock serializes
  *
- *     FIXME:
- *             What if two overlap
  */
 
 static int send_break(struct tty_struct *tty, unsigned int duration)
 {
+       if (mutex_lock_interruptible(&tty->atomic_write_lock))
+               return -EINTR;
        tty->driver->break_ctl(tty, -1);
        if (!signal_pending(current)) {
                msleep_interruptible(duration);
        }
        tty->driver->break_ctl(tty, 0);
+       mutex_unlock(&tty->atomic_write_lock);
        if (signal_pending(current))
                return -EINTR;
        return 0;
@@ -3137,6 +3144,8 @@ int tty_ioctl(struct inode * inode, struct file * file,
        if (tty_paranoia_check(tty, inode, "tty_ioctl"))
                return -EINVAL;
 
+       /* CHECKME: is this safe as one end closes ? */
+
        real_tty = tty;
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
            tty->driver->subtype == PTY_TYPE_MASTER)
@@ -3573,7 +3582,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
        tty_buffer_init(tty);
        INIT_WORK(&tty->buf.work, flush_to_ldisc, tty);
        init_MUTEX(&tty->buf.pty_sem);
-       init_MUTEX(&tty->termios_sem);
+       mutex_init(&tty->termios_mutex);
        init_waitqueue_head(&tty->write_wait);
        init_waitqueue_head(&tty->read_wait);
        INIT_WORK(&tty->hangup_work, do_tty_hangup, tty);