Pull percpu-dtc into release branch
[linux-drm-fsl-dcu.git] / drivers / char / tty_io.c
index 558ca927e32b1ebd4d9a7ea0c5b5b41b028b696b..7a32df59490750775b6df3b718e0b33be2ee8514 100644 (file)
@@ -155,6 +155,8 @@ 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_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,19 @@ 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;
+       put_pid(tty->session);
+       put_pid(tty->pgrp);
+       tty->session = NULL;
+       tty->pgrp = NULL;
        tty->ctrl_status = 0;
        /*
         *      If one of the devices matches a console pointer, we
@@ -1459,12 +1464,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 +1499,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);
-       current->signal->tty_old_pgrp = 0;
-       session = process_session(current);
+       tty_pgrp = current->signal->tty_old_pgrp;
+       current->signal->tty_old_pgrp = NULL;
        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 +1557,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();
 }
@@ -1890,6 +1903,20 @@ static int init_dev(struct tty_driver *driver, int idx,
        /* check whether we're reopening an existing tty */
        if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
                tty = devpts_get_tty(idx);
+               /*
+                * If we don't have a tty here on a slave open, it's because
+                * the master already started the close process and there's
+                * no relation between devpts file and tty anymore.
+                */
+               if (!tty && driver->subtype == PTY_TYPE_SLAVE) {
+                       retval = -EIO;
+                       goto end_init;
+               }
+               /*
+                * It's safe from now on because init_dev() is called with
+                * tty_mutex held and release_dev() won't change tty->count
+                * or tty->flags without having to grab tty_mutex
+                */
                if (tty && driver->subtype == PTY_TYPE_MASTER)
                        tty = tty->link;
        } else {
@@ -2481,6 +2508,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);
        
@@ -2574,15 +2602,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;
 }
 
@@ -2721,9 +2751,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 {
@@ -2825,10 +2864,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:
@@ -2913,8 +2952,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);
@@ -2927,7 +2965,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!
@@ -2970,7 +3008,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);
 }
 
 /**
@@ -2987,7 +3025,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)
@@ -2996,16 +3035,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;
 }
 
 /**
@@ -3028,9 +3077,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);
 }
 
 /**
@@ -3330,7 +3379,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;
@@ -3346,12 +3395,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.
         */
@@ -3409,7 +3458,6 @@ void do_SAK(struct tty_struct *tty)
 {
        if (!tty)
                return;
-       PREPARE_WORK(&tty->SAK_work, do_SAK_work);
        schedule_work(&tty->SAK_work);
 }
 
@@ -3520,7 +3568,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);
@@ -3534,7 +3583,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
        mutex_init(&tty->atomic_write_lock);
        spin_lock_init(&tty->read_lock);
        INIT_LIST_HEAD(&tty->tty_files);
-       INIT_WORK(&tty->SAK_work, NULL);
+       INIT_WORK(&tty->SAK_work, do_SAK_work);
 }
 
 /*
@@ -3680,15 +3729,14 @@ int tty_register_driver(struct tty_driver *driver)
 
        if (!driver->major) {
                error = alloc_chrdev_region(&dev, driver->minor_start, driver->num,
-                                               (char*)driver->name);
+                                               driver->name);
                if (!error) {
                        driver->major = MAJOR(dev);
                        driver->minor_start = MINOR(dev);
                }
        } else {
                dev = MKDEV(driver->major, driver->minor_start);
-               error = register_chrdev_region(dev, driver->num,
-                                               (char*)driver->name);
+               error = register_chrdev_region(dev, driver->num, driver->name);
        }
        if (error < 0) {
                kfree(p);
@@ -3791,21 +3839,31 @@ 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);
+               /* We should not have a session or pgrp to here but.... */
+               put_pid(tty->session);
+               put_pid(tty->pgrp);
+               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)