From: Alan Cox This fixes the last couple of pid struct locking failures I know about. Signed-off-by: Alan Cox Cc: Oleg Nesterov Signed-off-by: Andrew Morton --- drivers/char/tty_io.c | 28 +++++++++++++++++++++++++++- fs/proc/array.c | 5 ++++- include/linux/tty.h | 1 + 3 files changed, 32 insertions(+), 2 deletions(-) diff -puN drivers/char/tty_io.c~tty_io-fix-remaining-pid-struct-locking drivers/char/tty_io.c --- a/drivers/char/tty_io.c~tty_io-fix-remaining-pid-struct-locking +++ a/drivers/char/tty_io.c @@ -3174,6 +3174,27 @@ unlock: } /** + * tty_get_pgrp - return a ref counted pgrp pid + * @tty: tty to read + * + * Returns a refcounted instance of the pid struct for the process + * group controlling the tty. + */ + +struct pid *tty_get_pgrp(struct tty_struct *tty) +{ + unsigned long flags; + struct pid *pgrp; + + spin_lock_irqsave(&tty->ctrl_lock, flags); + pgrp = get_pid(tty->pgrp); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + + return pgrp; +} +EXPORT_SYMBOL_GPL(tty_get_pgrp); + +/** * tiocgpgrp - get process group * @tty: tty passed by user * @real_tty: tty side of the tty pased by the user if a pty else the tty @@ -3187,13 +3208,18 @@ unlock: static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { + struct pid *pid; + int ret; /* * (tty == real_tty) is a cheap way of * testing if the tty is NOT a master pty. */ if (tty == real_tty && current->signal->tty != real_tty) return -ENOTTY; - return put_user(pid_vnr(real_tty->pgrp), p); + pid = tty_get_pgrp(real_tty); + ret = put_user(pid_vnr(pid), p); + put_pid(pid); + return ret; } /** diff -puN fs/proc/array.c~tty_io-fix-remaining-pid-struct-locking fs/proc/array.c --- a/fs/proc/array.c~tty_io-fix-remaining-pid-struct-locking +++ a/fs/proc/array.c @@ -408,6 +408,7 @@ static int do_task_stat(struct seq_file unsigned long rsslim = 0; char tcomm[sizeof(task->comm)]; unsigned long flags; + struct pid *pgrp; state = *get_task_state(task); vsize = eip = esp = 0; @@ -429,7 +430,9 @@ static int do_task_stat(struct seq_file struct signal_struct *sig = task->signal; if (sig->tty) { - tty_pgrp = pid_nr_ns(sig->tty->pgrp, ns); + pgrp = tty_get_pgrp(sig->tty); + tty_pgrp = pid_nr_ns(pgrp, ns); + put_pid(pgrp); tty_nr = new_encode_dev(tty_devnum(sig->tty)); } diff -puN include/linux/tty.h~tty_io-fix-remaining-pid-struct-locking include/linux/tty.h --- a/include/linux/tty.h~tty_io-fix-remaining-pid-struct-locking +++ a/include/linux/tty.h @@ -297,6 +297,7 @@ extern int tty_read_raw_data(struct tty_ extern void tty_write_message(struct tty_struct *tty, char *msg); extern int is_current_pgrp_orphaned(void); +extern struct pid *tty_get_pgrp(struct tty_struct *tty); extern int is_ignored(int sig); extern int tty_signal(int sig, struct tty_struct *tty); extern void tty_hangup(struct tty_struct * tty); _