Merge branch 'master' into for_paulus
[linux-drm-fsl-dcu.git] / drivers / char / tty_io.c
index 305e46db70e48cf5013bbfc14c782834c1bae197..65672c57470b87282c3f4a73d261564310ca5565 100644 (file)
@@ -154,7 +154,9 @@ static int tty_release(struct inode *, struct file *);
 int tty_ioctl(struct inode * inode, struct file * file,
              unsigned int cmd, unsigned long arg);
 static int tty_fasync(int fd, struct file * filp, int on);
-static void release_mem(struct tty_struct *tty, int idx);
+static void release_tty(struct tty_struct *tty, int idx);
+static struct pid *__proc_set_tty(struct task_struct *tsk,
+                               struct tty_struct *tty);
 
 /**
  *     alloc_tty_struct        -       allocate a tty object
@@ -1109,17 +1111,17 @@ int tty_check_change(struct tty_struct * tty)
 {
        if (current->signal->tty != tty)
                return 0;
-       if (tty->pgrp <= 0) {
-               printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n");
+       if (!tty->pgrp) {
+               printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
                return 0;
        }
-       if (process_group(current) == tty->pgrp)
+       if (task_pgrp(current) == tty->pgrp)
                return 0;
        if (is_ignored(SIGTTOU))
                return 0;
-       if (is_orphaned_pgrp(process_group(current)))
+       if (is_current_pgrp_orphaned())
                return -EIO;
-       (void) kill_pg(process_group(current), SIGTTOU, 1);
+       (void) kill_pgrp(task_pgrp(current), SIGTTOU, 1);
        return -ERESTARTSYS;
 }
 
@@ -1354,8 +1356,8 @@ static void do_tty_hangup(struct work_struct *work)
          tty_release is called */
        
        read_lock(&tasklist_lock);
-       if (tty->session > 0) {
-               do_each_task_pid(tty->session, PIDTYPE_SID, p) {
+       if (tty->session) {
+               do_each_pid_task(tty->session, PIDTYPE_SID, p) {
                        spin_lock_irq(&p->sighand->siglock);
                        if (p->signal->tty == tty)
                                p->signal->tty = NULL;
@@ -1365,16 +1367,17 @@ static void do_tty_hangup(struct work_struct *work)
                        }
                        __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
                        __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
-                       if (tty->pgrp > 0)
-                               p->signal->tty_old_pgrp = tty->pgrp;
+                       put_pid(p->signal->tty_old_pgrp);  /* A noop */
+                       if (tty->pgrp)
+                               p->signal->tty_old_pgrp = get_pid(tty->pgrp);
                        spin_unlock_irq(&p->sighand->siglock);
-               } while_each_task_pid(tty->session, PIDTYPE_SID, p);
+               } while_each_pid_task(tty->session, PIDTYPE_SID, p);
        }
        read_unlock(&tasklist_lock);
 
        tty->flags = 0;
-       tty->session = 0;
-       tty->pgrp = -1;
+       tty->session = NULL;
+       tty->pgrp = NULL;
        tty->ctrl_status = 0;
        /*
         *      If one of the devices matches a console pointer, we
@@ -1459,12 +1462,12 @@ int tty_hung_up_p(struct file * filp)
 
 EXPORT_SYMBOL(tty_hung_up_p);
 
-static void session_clear_tty(pid_t session)
+static void session_clear_tty(struct pid *session)
 {
        struct task_struct *p;
-       do_each_task_pid(session, PIDTYPE_SID, p) {
+       do_each_pid_task(session, PIDTYPE_SID, p) {
                proc_clear_tty(p);
-       } while_each_task_pid(session, PIDTYPE_SID, p);
+       } while_each_pid_task(session, PIDTYPE_SID, p);
 }
 
 /**
@@ -1494,46 +1497,54 @@ static void session_clear_tty(pid_t session)
 void disassociate_ctty(int on_exit)
 {
        struct tty_struct *tty;
-       int tty_pgrp = -1;
-       int session;
+       struct pid *tty_pgrp = NULL;
 
        lock_kernel();
 
        mutex_lock(&tty_mutex);
        tty = get_current_tty();
        if (tty) {
-               tty_pgrp = tty->pgrp;
+               tty_pgrp = get_pid(tty->pgrp);
                mutex_unlock(&tty_mutex);
                /* XXX: here we race, there is nothing protecting tty */
                if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
                        tty_vhangup(tty);
-       } else {
-               pid_t old_pgrp = current->signal->tty_old_pgrp;
+       } else if (on_exit) {
+               struct pid *old_pgrp;
+               spin_lock_irq(&current->sighand->siglock);
+               old_pgrp = current->signal->tty_old_pgrp;
+               current->signal->tty_old_pgrp = NULL;
+               spin_unlock_irq(&current->sighand->siglock);
                if (old_pgrp) {
-                       kill_pg(old_pgrp, SIGHUP, on_exit);
-                       kill_pg(old_pgrp, SIGCONT, on_exit);
+                       kill_pgrp(old_pgrp, SIGHUP, on_exit);
+                       kill_pgrp(old_pgrp, SIGCONT, on_exit);
+                       put_pid(old_pgrp);
                }
                mutex_unlock(&tty_mutex);
                unlock_kernel();        
                return;
        }
-       if (tty_pgrp > 0) {
-               kill_pg(tty_pgrp, SIGHUP, on_exit);
+       if (tty_pgrp) {
+               kill_pgrp(tty_pgrp, SIGHUP, on_exit);
                if (!on_exit)
-                       kill_pg(tty_pgrp, SIGCONT, on_exit);
+                       kill_pgrp(tty_pgrp, SIGCONT, on_exit);
+               put_pid(tty_pgrp);
        }
 
        spin_lock_irq(&current->sighand->siglock);
+       tty_pgrp = current->signal->tty_old_pgrp;
        current->signal->tty_old_pgrp = 0;
-       session = process_session(current);
        spin_unlock_irq(&current->sighand->siglock);
+       put_pid(tty_pgrp);
 
        mutex_lock(&tty_mutex);
        /* It is possible that do_tty_hangup has free'd this tty */
        tty = get_current_tty();
        if (tty) {
-               tty->session = 0;
-               tty->pgrp = 0;
+               put_pid(tty->session);
+               put_pid(tty->pgrp);
+               tty->session = NULL;
+               tty->pgrp = NULL;
        } else {
 #ifdef TTY_DEBUG_HANGUP
                printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
@@ -1544,7 +1555,7 @@ void disassociate_ctty(int on_exit)
 
        /* Now clear signal->tty under the lock */
        read_lock(&tasklist_lock);
-       session_clear_tty(session);
+       session_clear_tty(task_session(current));
        read_unlock(&tasklist_lock);
        unlock_kernel();
 }
@@ -2002,7 +2013,7 @@ static int init_dev(struct tty_driver *driver, int idx,
 
        /* 
         * All structures have been allocated, so now we install them.
-        * Failures after this point use release_mem to clean up, so 
+        * Failures after this point use release_tty to clean up, so
         * there's no need to null out the local pointers.
         */
        if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
@@ -2023,8 +2034,8 @@ static int init_dev(struct tty_driver *driver, int idx,
 
        /* 
         * Structures all installed ... call the ldisc open routines.
-        * If we fail here just call release_mem to clean up.  No need
-        * to decrement the use counts, as release_mem doesn't care.
+        * If we fail here just call release_tty to clean up.  No need
+        * to decrement the use counts, as release_tty doesn't care.
         */
 
        if (tty->ldisc.open) {
@@ -2094,17 +2105,17 @@ fail_no_mem:
        retval = -ENOMEM;
        goto end_init;
 
-       /* call the tty release_mem routine to clean out this slot */
+       /* call the tty release_tty routine to clean out this slot */
 release_mem_out:
        if (printk_ratelimit())
                printk(KERN_INFO "init_dev: ldisc open failed, "
                                 "clearing slot %d\n", idx);
-       release_mem(tty, idx);
+       release_tty(tty, idx);
        goto end_init;
 }
 
 /**
- *     release_mem             -       release tty structure memory
+ *     release_one_tty         -       release tty structure memory
  *
  *     Releases memory associated with a tty structure, and clears out the
  *     driver table slots. This function is called when a device is no longer
@@ -2116,37 +2127,14 @@ release_mem_out:
  *     of ttys that the driver keeps.
  *             FIXME: should we require tty_mutex is held here ??
  */
-
-static void release_mem(struct tty_struct *tty, int idx)
+static void release_one_tty(struct tty_struct *tty, int idx)
 {
-       struct tty_struct *o_tty;
-       struct ktermios *tp;
        int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
-
-       if ((o_tty = tty->link) != NULL) {
-               if (!devpts)
-                       o_tty->driver->ttys[idx] = NULL;
-               if (o_tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-                       tp = o_tty->termios;
-                       if (!devpts)
-                               o_tty->driver->termios[idx] = NULL;
-                       kfree(tp);
-
-                       tp = o_tty->termios_locked;
-                       if (!devpts)
-                               o_tty->driver->termios_locked[idx] = NULL;
-                       kfree(tp);
-               }
-               o_tty->magic = 0;
-               o_tty->driver->refcount--;
-               file_list_lock();
-               list_del_init(&o_tty->tty_files);
-               file_list_unlock();
-               free_tty_struct(o_tty);
-       }
+       struct ktermios *tp;
 
        if (!devpts)
                tty->driver->ttys[idx] = NULL;
+
        if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
                tp = tty->termios;
                if (!devpts)
@@ -2159,15 +2147,39 @@ static void release_mem(struct tty_struct *tty, int idx)
                kfree(tp);
        }
 
+
        tty->magic = 0;
        tty->driver->refcount--;
+
        file_list_lock();
        list_del_init(&tty->tty_files);
        file_list_unlock();
-       module_put(tty->driver->owner);
+
        free_tty_struct(tty);
 }
 
+/**
+ *     release_tty             -       release tty structure memory
+ *
+ *     Release both @tty and a possible linked partner (think pty pair),
+ *     and decrement the refcount of the backing module.
+ *
+ *     Locking:
+ *             tty_mutex - sometimes only
+ *             takes the file list lock internally when working on the list
+ *     of ttys that the driver keeps.
+ *             FIXME: should we require tty_mutex is held here ??
+ */
+static void release_tty(struct tty_struct *tty, int idx)
+{
+       struct tty_driver *driver = tty->driver;
+
+       if (tty->link)
+               release_one_tty(tty->link, idx);
+       release_one_tty(tty, idx);
+       module_put(driver->owner);
+}
+
 /*
  * Even releasing the tty structures is a tricky business.. We have
  * to be very careful that the structures are all released at the
@@ -2435,10 +2447,10 @@ static void release_dev(struct file * filp)
                tty_set_termios_ldisc(o_tty,N_TTY); 
        }
        /*
-        * The release_mem function takes care of the details of clearing
+        * The release_tty function takes care of the details of clearing
         * the slots and preserving the termios structure.
         */
-       release_mem(tty, idx);
+       release_tty(tty, idx);
 
 #ifdef CONFIG_UNIX98_PTYS
        /* Make this pty number available for reallocation */
@@ -2480,6 +2492,7 @@ static int tty_open(struct inode * inode, struct file * filp)
        int index;
        dev_t device = inode->i_rdev;
        unsigned short saved_flags = filp->f_flags;
+       struct pid *old_pgrp;
 
        nonseekable_open(inode, filp);
        
@@ -2573,15 +2586,17 @@ got_driver:
                goto retry_open;
        }
 
+       old_pgrp = NULL;
        mutex_lock(&tty_mutex);
        spin_lock_irq(&current->sighand->siglock);
        if (!noctty &&
            current->signal->leader &&
            !current->signal->tty &&
-           tty->session == 0)
-               __proc_set_tty(current, tty);
+           tty->session == NULL)
+               old_pgrp = __proc_set_tty(current, tty);
        spin_unlock_irq(&current->sighand->siglock);
        mutex_unlock(&tty_mutex);
+       put_pid(old_pgrp);
        return 0;
 }
 
@@ -2720,9 +2735,18 @@ static int tty_fasync(int fd, struct file * filp, int on)
                return retval;
 
        if (on) {
+               enum pid_type type;
+               struct pid *pid;
                if (!waitqueue_active(&tty->read_wait))
                        tty->minimum_to_wake = 1;
-               retval = f_setown(filp, (-tty->pgrp) ? : current->pid, 0);
+               if (tty->pgrp) {
+                       pid = tty->pgrp;
+                       type = PIDTYPE_PGID;
+               } else {
+                       pid = task_pid(current);
+                       type = PIDTYPE_PID;
+               }
+               retval = __f_setown(filp, pid, type, 0);
                if (retval)
                        return retval;
        } else {
@@ -2824,10 +2848,10 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
                }
        }
 #endif
-       if (tty->pgrp > 0)
-               kill_pg(tty->pgrp, SIGWINCH, 1);
-       if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0))
-               kill_pg(real_tty->pgrp, SIGWINCH, 1);
+       if (tty->pgrp)
+               kill_pgrp(tty->pgrp, SIGWINCH, 1);
+       if ((real_tty->pgrp != tty->pgrp) && real_tty->pgrp)
+               kill_pgrp(real_tty->pgrp, SIGWINCH, 1);
        tty->winsize = tmp_ws;
        real_tty->winsize = tmp_ws;
 done:
@@ -2912,8 +2936,7 @@ static int fionbio(struct file *file, int __user *p)
 static int tiocsctty(struct tty_struct *tty, int arg)
 {
        int ret = 0;
-       if (current->signal->leader &&
-                       (process_session(current) == tty->session))
+       if (current->signal->leader && (task_session(current) == tty->session))
                return ret;
 
        mutex_lock(&tty_mutex);
@@ -2926,7 +2949,7 @@ static int tiocsctty(struct tty_struct *tty, int arg)
                goto unlock;
        }
 
-       if (tty->session > 0) {
+       if (tty->session) {
                /*
                 * This tty is already the controlling
                 * tty for another session group!
@@ -2969,7 +2992,7 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
         */
        if (tty == real_tty && current->signal->tty != real_tty)
                return -ENOTTY;
-       return put_user(real_tty->pgrp, p);
+       return put_user(pid_nr(real_tty->pgrp), p);
 }
 
 /**
@@ -2986,7 +3009,8 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
 
 static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
 {
-       pid_t pgrp;
+       struct pid *pgrp;
+       pid_t pgrp_nr;
        int retval = tty_check_change(real_tty);
 
        if (retval == -EIO)
@@ -2995,16 +3019,26 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
                return retval;
        if (!current->signal->tty ||
            (current->signal->tty != real_tty) ||
-           (real_tty->session != process_session(current)))
+           (real_tty->session != task_session(current)))
                return -ENOTTY;
-       if (get_user(pgrp, p))
+       if (get_user(pgrp_nr, p))
                return -EFAULT;
-       if (pgrp < 0)
+       if (pgrp_nr < 0)
                return -EINVAL;
-       if (session_of_pgrp(pgrp) != process_session(current))
-               return -EPERM;
-       real_tty->pgrp = pgrp;
-       return 0;
+       rcu_read_lock();
+       pgrp = find_pid(pgrp_nr);
+       retval = -ESRCH;
+       if (!pgrp)
+               goto out_unlock;
+       retval = -EPERM;
+       if (session_of_pgrp(pgrp) != task_session(current))
+               goto out_unlock;
+       retval = 0;
+       put_pid(real_tty->pgrp);
+       real_tty->pgrp = get_pid(pgrp);
+out_unlock:
+       rcu_read_unlock();
+       return retval;
 }
 
 /**
@@ -3027,9 +3061,9 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
        */
        if (tty == real_tty && current->signal->tty != real_tty)
                return -ENOTTY;
-       if (real_tty->session <= 0)
+       if (!real_tty->session)
                return -ENOTTY;
-       return put_user(real_tty->session, p);
+       return put_user(pid_nr(real_tty->session), p);
 }
 
 /**
@@ -3329,7 +3363,7 @@ void __do_SAK(struct tty_struct *tty)
        tty_hangup(tty);
 #else
        struct task_struct *g, *p;
-       int session;
+       struct pid *session;
        int             i;
        struct file     *filp;
        struct fdtable *fdt;
@@ -3345,12 +3379,12 @@ void __do_SAK(struct tty_struct *tty)
        
        read_lock(&tasklist_lock);
        /* Kill the entire session */
-       do_each_task_pid(session, PIDTYPE_SID, p) {
+       do_each_pid_task(session, PIDTYPE_SID, p) {
                printk(KERN_NOTICE "SAK: killed process %d"
                        " (%s): process_session(p)==tty->session\n",
                        p->pid, p->comm);
                send_sig(SIGKILL, p, 1);
-       } while_each_task_pid(session, PIDTYPE_SID, p);
+       } while_each_pid_task(session, PIDTYPE_SID, p);
        /* Now kill any processes that happen to have the
         * tty open.
         */
@@ -3519,7 +3553,8 @@ static void initialize_tty_struct(struct tty_struct *tty)
        memset(tty, 0, sizeof(struct tty_struct));
        tty->magic = TTY_MAGIC;
        tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
-       tty->pgrp = -1;
+       tty->session = NULL;
+       tty->pgrp = NULL;
        tty->overrun_time = jiffies;
        tty->buf.head = tty->buf.tail = NULL;
        tty_buffer_init(tty);
@@ -3790,21 +3825,28 @@ void proc_clear_tty(struct task_struct *p)
 }
 EXPORT_SYMBOL(proc_clear_tty);
 
-void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
 {
+       struct pid *old_pgrp;
        if (tty) {
-               tty->session = process_session(tsk);
-               tty->pgrp = process_group(tsk);
+               tty->session = get_pid(task_session(tsk));
+               tty->pgrp = get_pid(task_pgrp(tsk));
        }
+       old_pgrp = tsk->signal->tty_old_pgrp;
        tsk->signal->tty = tty;
-       tsk->signal->tty_old_pgrp = 0;
+       tsk->signal->tty_old_pgrp = NULL;
+       return old_pgrp;
 }
 
 void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
 {
+       struct pid *old_pgrp;
+
        spin_lock_irq(&tsk->sighand->siglock);
-       __proc_set_tty(tsk, tty);
+       old_pgrp = __proc_set_tty(tsk, tty);
        spin_unlock_irq(&tsk->sighand->siglock);
+
+       put_pid(old_pgrp);
 }
 
 struct tty_struct *get_current_tty(void)