[PATCH] Ref counting for tty_struct and some locking clean up

From: Jon Smirl
Date: Fri Jul 07 2006 - 20:35:53 EST


This patch removes tty_mutex and replaces it with a ref counted
tty_struct. A new spinlock, tty_lock, serializes tty
creation/destruction. This code thoroughly audits everyone taking
references to tty_struct and tracks them. I have been running it
locally for a few days without any issues.

If there is a refcount problem it will trigger a WARN_ON. If you hit
one, defining DEBUG_TTY_REFCOUNT will provide plenty of debug info to
help locate the missing reference. I definitely found multiple locking
holes in the old tty_mutex code but they they look hard to hit.

This is just a first step, if this code proves to be stable I'll do
another round of cleanup. There is room for a lot more work to be
done. Ultimately there may not even be a need for a tty refcount if
everything is locked correctly. But that is a big step and we should
take some smaller ones first.

This is meant for mm until it gets some testing - I don't want to
break anyone's console. If gmail wraps it let me know and I'll send
you an attachment.

--
Jon Smirl
jonsmirl@xxxxxxxxx



diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index bfdb902..5c673e0 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -126,9 +126,8 @@ EXPORT_SYMBOL(tty_std_termios);

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);
+/* Spinlock to protect creating and releasing a tty. */
+static DEFINE_SPINLOCK(tty_lock);

#ifdef CONFIG_UNIX98_PTYS
extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
@@ -158,21 +157,21 @@ static struct tty_struct *alloc_tty_stru
{
struct tty_struct *tty;

- tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
- if (tty)
- memset(tty, 0, sizeof(struct tty_struct));
+ tty = kmalloc(sizeof(*tty), GFP_KERNEL);
return tty;
}

static void tty_buffer_free_all(struct tty_struct *);

-static inline void free_tty_struct(struct tty_struct *tty)
+void free_tty_struct(struct tty_struct *tty)
{
kfree(tty->write_buf);
tty_buffer_free_all(tty);
kfree(tty);
}

+EXPORT_SYMBOL(free_tty_struct);
+
#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)

char *tty_name(struct tty_struct *tty, char *buf)
@@ -1090,7 +1089,7 @@ static void do_tty_hangup(void *data)
if (tty->session > 0) {
do_each_task_pid(tty->session, PIDTYPE_SID, p) {
if (p->signal->tty == tty)
- p->signal->tty = NULL;
+ tty_put(&p->signal->tty, 0, __FILE__, __LINE__);
if (!p->signal->leader)
continue;
group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
@@ -1184,11 +1183,9 @@ void disassociate_ctty(int on_exit)

lock_kernel();

- mutex_lock(&tty_mutex);
tty = current->signal->tty;
if (tty) {
tty_pgrp = tty->pgrp;
- mutex_unlock(&tty_mutex);
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
tty_vhangup(tty);
} else {
@@ -1196,7 +1193,6 @@ void disassociate_ctty(int on_exit)
kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit);
kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit);
}
- mutex_unlock(&tty_mutex);
unlock_kernel();
return;
}
@@ -1206,8 +1202,6 @@ void disassociate_ctty(int on_exit)
kill_pg(tty_pgrp, SIGCONT, on_exit);
}

- /* Must lock changes to tty_old_pgrp */
- mutex_lock(&tty_mutex);
current->signal->tty_old_pgrp = 0;
tty->session = 0;
tty->pgrp = -1;
@@ -1215,10 +1209,9 @@ void disassociate_ctty(int on_exit)
/* Now clear signal->tty under the lock */
read_lock(&tasklist_lock);
do_each_task_pid(current->signal->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
+ tty_put(&p->signal->tty, 0, __FILE__, __LINE__);
} while_each_task_pid(current->signal->session, PIDTYPE_SID, p);
read_unlock(&tasklist_lock);
- mutex_unlock(&tty_mutex);
unlock_kernel();
}

@@ -1546,7 +1539,8 @@ static int init_dev(struct tty_driver *d
* Everything allocated ... set up the o_tty structure.
*/
if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM)) {
- driver->other->ttys[idx] = o_tty;
+ driver->other->ttys[idx] = tty_get(o_tty,
+ __FILE__, __LINE__);
}
if (!*o_tp_loc)
*o_tp_loc = o_tp;
@@ -1559,8 +1553,8 @@ static int init_dev(struct tty_driver *d
o_tty->count++;

/* Establish the links in both directions */
- tty->link = o_tty;
- o_tty->link = tty;
+ tty->link = tty_get(o_tty, __FILE__, __LINE__);
+ o_tty->link = tty_get(tty, __FILE__, __LINE__);
}

/*
@@ -1569,7 +1563,7 @@ static int init_dev(struct tty_driver *d
* there's no need to null out the local pointers.
*/
if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
- driver->ttys[idx] = tty;
+ driver->ttys[idx] = tty_get(tty, __FILE__, __LINE__);
}

if (!*tp_loc)
@@ -1636,7 +1630,6 @@ fast_track:
success:
*ret_tty = tty;

- /* All paths come through here to release the mutex */
end_init:
return retval;

@@ -1644,10 +1637,10 @@ end_init:
free_mem_out:
kfree(o_tp);
if (o_tty)
- free_tty_struct(o_tty);
+ tty_put(&o_tty, 1, __FILE__, __LINE__);
kfree(ltp);
kfree(tp);
- free_tty_struct(tty);
+ tty_put(&tty, 1, __FILE__, __LINE__);

fail_no_mem:
module_put(driver->owner);
@@ -1674,7 +1667,8 @@ static void release_mem(struct tty_struc

if ((o_tty = tty->link) != NULL) {
if (!devpts)
- o_tty->driver->ttys[idx] = NULL;
+ tty_put(&o_tty->driver->ttys[idx], 0,
+ __FILE__, __LINE__);
if (o_tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
tp = o_tty->termios;
if (!devpts)
@@ -1691,11 +1685,14 @@ static void release_mem(struct tty_struc
file_list_lock();
list_del_init(&o_tty->tty_files);
file_list_unlock();
- free_tty_struct(o_tty);
+ tty_put(&o_tty->link, 0, __FILE__, __LINE__);
+ tty_put(&tty->link, 0, __FILE__, __LINE__);
+ tty_put(&o_tty, 1, __FILE__, __LINE__);
}

if (!devpts)
- tty->driver->ttys[idx] = NULL;
+ tty_put(&tty->driver->ttys[idx], 0,
+ __FILE__, __LINE__);
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
tp = tty->termios;
if (!devpts)
@@ -1714,7 +1711,7 @@ static void release_mem(struct tty_struc
list_del_init(&tty->tty_files);
file_list_unlock();
module_put(tty->driver->owner);
- free_tty_struct(tty);
+ tty_put(&tty, 1, __FILE__, __LINE__);
}

/*
@@ -1832,7 +1829,7 @@ #endif
/* Guard against races with tty->count changes elsewhere and
opens on /dev/tty */

- mutex_lock(&tty_mutex);
+ spin_lock(&tty_lock);
tty_closing = tty->count <= 1;
o_tty_closing = o_tty &&
(o_tty->count <= (pty_master ? 1 : 0));
@@ -1861,9 +1858,9 @@ #endif
if (!do_sleep)
break;

+ spin_unlock(&tty_lock);
printk(KERN_WARNING "release_dev: %s: read/write wait queue "
"active!\n", tty_name(tty, buf));
- mutex_unlock(&tty_mutex);
schedule();
}

@@ -1896,7 +1893,8 @@ #endif
* something that needs to be handled for hangups.
*/
file_kill(filp);
- filp->private_data = NULL;
+ tty_put((struct tty_struct **)(&filp->private_data),
+ 0, __FILE__, __LINE__);

/*
* Perform some housekeeping before deciding whether to return.
@@ -1920,16 +1918,16 @@ #endif

read_lock(&tasklist_lock);
do_each_task_pid(tty->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
+ tty_put(&p->signal->tty, 0, __FILE__, __LINE__);
} while_each_task_pid(tty->session, PIDTYPE_SID, p);
if (o_tty)
do_each_task_pid(o_tty->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
+ tty_put(&p->signal->tty, 0, __FILE__, __LINE__);
} while_each_task_pid(o_tty->session, PIDTYPE_SID, p);
read_unlock(&tasklist_lock);
}

- mutex_unlock(&tty_mutex);
+ spin_unlock(&tty_lock);

/* check whether both sides are closing ... */
if (!tty_closing || (o_tty && !o_tty_closing))
@@ -2034,11 +2032,11 @@ retry_open:
index = -1;
retval = 0;

- mutex_lock(&tty_mutex);
-
+ spin_lock(&tty_lock);
+
if (device == MKDEV(TTYAUX_MAJOR,0)) {
if (!current->signal->tty) {
- mutex_unlock(&tty_mutex);
+ spin_unlock(&tty_lock);
return -ENXIO;
}
driver = current->signal->tty->driver;
@@ -2064,22 +2062,22 @@ #endif
noctty = 1;
goto got_driver;
}
- mutex_unlock(&tty_mutex);
+ spin_unlock(&tty_lock);
return -ENODEV;
}

driver = get_tty_driver(device, &index);
if (!driver) {
- mutex_unlock(&tty_mutex);
+ spin_unlock(&tty_lock);
return -ENODEV;
}
got_driver:
retval = init_dev(driver, index, &tty);
- mutex_unlock(&tty_mutex);
+ spin_unlock(&tty_lock);
if (retval)
return retval;

- filp->private_data = tty;
+ filp->private_data = tty_get(tty, __FILE__, __LINE__);
file_move(filp, &tty->tty_files);
check_tty_count(tty, "tty_open");
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -2122,7 +2120,7 @@ #endif
!current->signal->tty &&
tty->session == 0) {
task_lock(current);
- current->signal->tty = tty;
+ current->signal->tty = tty_get(tty, __FILE__, __LINE__);
task_unlock(current);
current->signal->tty_old_pgrp = 0;
tty->session = current->signal->session;
@@ -2161,15 +2159,15 @@ static int ptmx_open(struct inode * inod
}
up(&allocated_ptys_lock);

- mutex_lock(&tty_mutex);
+ spin_lock(&tty_lock);
retval = init_dev(ptm_driver, index, &tty);
- mutex_unlock(&tty_mutex);
+ spin_unlock(&tty_lock);

if (retval)
goto out;

set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
- filp->private_data = tty;
+ filp->private_data = tty_get(tty, __FILE__, __LINE__);
file_move(filp, &tty->tty_files);

retval = -ENOMEM;
@@ -2359,14 +2357,14 @@ static int tiocsctty(struct tty_struct *

read_lock(&tasklist_lock);
do_each_task_pid(tty->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
+ tty_put(&p->signal->tty, 0, __FILE__, __LINE__);
} while_each_task_pid(tty->session, PIDTYPE_SID, p);
read_unlock(&tasklist_lock);
} else
return -EPERM;
}
task_lock(current);
- current->signal->tty = tty;
+ current->signal->tty = tty_get(tty, __FILE__, __LINE__);
task_unlock(current);
current->signal->tty_old_pgrp = 0;
tty->session = current->signal->session;
@@ -2578,7 +2576,7 @@ int tty_ioctl(struct inode * inode, stru
if (current->signal->leader)
disassociate_ctty(0);
task_lock(current);
- current->signal->tty = NULL;
+ tty_put(&current->signal->tty, 0, __FILE__, __LINE__);
task_unlock(current);
return 0;
case TIOCSCTTY:
@@ -2670,7 +2668,7 @@ #ifdef TTY_SOFT_SAK
#else
struct tty_struct *tty = arg;
struct task_struct *g, *p;
- int session;
+ pid_t session;
int i;
struct file *filp;
struct tty_ldisc *disc;
@@ -2914,6 +2912,11 @@ static void initialize_tty_struct(struct
{
memset(tty, 0, sizeof(struct tty_struct));
tty->magic = TTY_MAGIC;
+ atomic_set(&tty->ref_count, 1);
+#ifdef DEBUG_TTY_REFCOUNT
+ printk("TTY ref count alloc: %p count %d\n",
+ tty, atomic_read(&tty->ref_count));
+#endif
tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
tty->pgrp = -1;
tty->overrun_time = jiffies;
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index a9247b5..97c36fc 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -474,14 +474,14 @@ static const struct file_operations vcs_

static struct class *vc_class;

-void vcs_make_devfs(struct tty_struct *tty)
+void vcs_make_sysfs(struct tty_struct *tty)
{
class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1),
NULL, "vcs%u", tty->index + 1);
class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129),
NULL, "vcsa%u", tty->index + 1);
}
-void vcs_remove_devfs(struct tty_struct *tty)
+void vcs_remove_sysfs(struct tty_struct *tty)
{
class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1));
class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129));
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index da7e66a..dd39020 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -128,8 +128,8 @@ #define CTRL_ALWAYS 0x0800f501 /* Cannot
#define DEFAULT_BELL_PITCH 750
#define DEFAULT_BELL_DURATION (HZ/8)

-extern void vcs_make_devfs(struct tty_struct *tty);
-extern void vcs_remove_devfs(struct tty_struct *tty);
+extern void vcs_make_sysfs(struct tty_struct *tty);
+extern void vcs_remove_sysfs(struct tty_struct *tty);

extern void console_map_init(void);
#ifdef CONFIG_PROM_CONSOLE
@@ -2491,14 +2491,14 @@ static int con_open(struct tty_struct *t
if (ret == 0) {
struct vc_data *vc = vc_cons[currcons].d;
tty->driver_data = vc;
- vc->vc_tty = tty;
+ vc->vc_tty = tty_get(tty, __FILE__, __LINE__);

if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
}
release_console_sem();
- vcs_make_devfs(tty);
+ vcs_make_sysfs(tty);
return ret;
}
}
@@ -2510,30 +2510,25 @@ static int con_open(struct tty_struct *t
* We take tty_mutex in here to prevent another thread from coming in
via init_dev
* and taking a ref against the tty while we're in the process of forgetting
* about it and cleaning things up.
- *
- * This is because vcs_remove_devfs() can sleep and will drop the BKL.
*/
static void con_close(struct tty_struct *tty, struct file *filp)
{
- mutex_lock(&tty_mutex);
acquire_console_sem();
- if (tty && tty->count == 1) {
+ if (tty && (tty->count == 1)) {
struct vc_data *vc = tty->driver_data;

if (vc)
- vc->vc_tty = NULL;
+ tty_put(&vc->vc_tty, 0, __FILE__, __LINE__);
tty->driver_data = NULL;
release_console_sem();
- vcs_remove_devfs(tty);
- mutex_unlock(&tty_mutex);
+ vcs_remove_sysfs(tty);
/*
- * tty_mutex is released, but we still hold BKL, so there is
+ * We still hold BKL, so there is
* still exclusion against init_dev()
*/
return;
}
release_console_sem();
- mutex_unlock(&tty_mutex);
}

static void vc_init(struct vc_data *vc, unsigned int rows,
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 23659fd..d0e804c 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -165,7 +165,7 @@ ppp_asynctty_open(struct tty_struct *tty

/* initialize the asyncppp structure */
memset(ap, 0, sizeof(*ap));
- ap->tty = tty;
+ ap->tty = tty_get(tty, __FILE__, __LINE__);
ap->mru = PPP_MRU;
spin_lock_init(&ap->xmit_lock);
spin_lock_init(&ap->recv_lock);
@@ -218,6 +218,7 @@ ppp_asynctty_close(struct tty_struct *tt
write_unlock_irq(&disc_data_lock);
if (ap == 0)
return;
+ tty_put(&ap->tty, 0, __FILE__, __LINE__);

/*
* We have now ensured that nobody can start using ap from now
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index d5f636f..0b6e4e4 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1279,7 +1279,7 @@ static void uart_close(struct tty_struct
tty_ldisc_flush(tty);

tty->closing = 0;
- state->info->tty = NULL;
+ tty_put(&state->info->tty, 0, __FILE__, __LINE__);

if (state->info->blocked_open) {
if (state->close_delay)
@@ -1375,6 +1375,7 @@ static void uart_hangup(struct tty_struc
uart_shutdown(state);
state->count = 0;
state->info->flags &= ~UIF_NORMAL_ACTIVE;
+ tty_put(&state->info->tty, 0, __FILE__, __LINE__);
state->info->tty = NULL;
wake_up_interruptible(&state->info->open_wait);
wake_up_interruptible(&state->info->delta_msr_wait);
@@ -1598,7 +1599,7 @@ static int uart_open(struct tty_struct *
tty->driver_data = state;
tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;
tty->alt_speed = 0;
- state->info->tty = tty;
+ state->info->tty = tty_get(tty, __FILE__, __LINE__);

/*
* If the port is in the middle of closing, bail out now.
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 3670d77..06e96df 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -451,7 +451,7 @@ static int acm_tty_open(struct tty_struc
rv = 0;

tty->driver_data = acm;
- acm->tty = tty;
+ acm->tty = tty_get(tty, __FILE__, __LINE__);

/* force low_latency on so that our tty_push actually forces the data through,
otherwise it is scheduled, and with high data rates data can get lost. */
@@ -519,6 +519,7 @@ static void acm_tty_close(struct tty_str
return;

nr = acm->rx_buflimit;
+ tty_put(&acm->tty, 0, __FILE__, __LINE__);
mutex_lock(&open_mutex);
if (!--acm->used) {
if (acm->dev) {
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index f7aef5b..74eb9de 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -177,7 +177,7 @@ int devpts_pty_new(struct tty_struct *tt
inode->i_gid = config.setgid ? config.gid : current->fsgid;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
init_special_inode(inode, S_IFCHR|config.mode, device);
- inode->u.generic_ip = tty;
+ inode->u.generic_ip = tty_get(tty, __FILE__, __LINE__);

dentry = get_node(number);
if (!IS_ERR(dentry) && !dentry->d_inode)
@@ -212,6 +212,8 @@ void devpts_pty_kill(int number)
if (!IS_ERR(dentry)) {
struct inode *inode = dentry->d_inode;
if (inode) {
+ tty_put((struct tty_struct **)(&inode->u.generic_ip),
+ 0, __FILE__, __LINE__);
inode->i_nlink--;
d_delete(dentry);
dput(dentry);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index b3b807e..f159a12 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -181,14 +181,15 @@ struct device;
*/
struct tty_struct {
int magic;
+ atomic_t ref_count;
struct tty_driver *driver;
int index;
struct tty_ldisc ldisc;
struct semaphore termios_sem;
struct termios *termios, *termios_locked;
char name[64];
- int pgrp;
- int session;
+ pid_t pgrp;
+ pid_t session;
unsigned long flags;
int count;
struct winsize winsize;
@@ -267,6 +268,44 @@ #define TTY_HUPPED 18 /* Post driver->

#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))

+#undef DEBUG_TTY_REFCOUNT
+static inline struct tty_struct *
+tty_get(struct tty_struct * tty, char *file, int line)
+{
+ if (tty) {
+ WARN_ON(!atomic_read(&tty->ref_count));
+ atomic_inc(&tty->ref_count);
+#ifdef DEBUG_TTY_REFCOUNT
+ printk("TTY ref count get: %s:%d %s %p count %d\n", file,
+ line, tty->name, tty, atomic_read(&tty->ref_count));
+#endif
+ }
+ return tty;
+}
+
+extern void free_tty_struct(struct tty_struct *tty);
+static inline void
+tty_put(struct tty_struct ** tty, int free_me, char *file, int line)
+{
+ int count;
+
+ if (*tty) {
+ count = atomic_dec_return(&(*tty)->ref_count);
+ if (count == 0) {
+ WARN_ON(!free_me);
+ free_tty_struct(*tty);
+#ifdef DEBUG_TTY_REFCOUNT
+ printk("TTY ref count put freed: %s:%d %s %p\n",
+ file, line, (*tty)->name, *tty);
+ } else {
+ printk("TTY ref count put: %s:%d %s %p count %d\n",
+ file, line, (*tty)->name, *tty, count);
+#endif
+ }
+ *tty = NULL;
+ }
+}
+
extern void tty_write_flush(struct tty_struct *);

extern struct termios tty_std_termios;
@@ -319,8 +358,6 @@ extern void tty_ldisc_put(int);
extern void tty_wakeup(struct tty_struct *tty);
extern void tty_ldisc_flush(struct tty_struct *tty);

-extern struct mutex tty_mutex;
-
/* n_tty.c */
extern struct tty_ldisc tty_ldisc_N_TTY;

diff --git a/kernel/exit.c b/kernel/exit.c
index 6664c08..a6cc755 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -108,6 +108,7 @@ static void __exit_signal(struct task_st
sig->nvcsw += tsk->nvcsw;
sig->nivcsw += tsk->nivcsw;
sig->sched_time += tsk->sched_time;
+ tty_put(&sig->tty, 0, __FILE__, __LINE__);
sig = NULL; /* Marker for below. */
}

@@ -391,9 +392,7 @@ void daemonize(const char *name, ...)
exit_mm(current);

set_special_pids(1, 1);
- mutex_lock(&tty_mutex);
- current->signal->tty = NULL;
- mutex_unlock(&tty_mutex);
+ tty_put(&current->signal->tty, 0, __FILE__, __LINE__);

/* Block and flush all signals */
sigfillset(&blocked);
diff --git a/kernel/fork.c b/kernel/fork.c
index 56e4e07..90cc4e3 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -43,6 +43,7 @@ #include <linux/profile.h>
#include <linux/rmap.h>
#include <linux/acct.h>
#include <linux/cn_proc.h>
+#include <linux/tty.h>

#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -856,6 +857,7 @@ static inline int copy_signal(unsigned l

sig->leader = 0; /* session leadership doesn't inherit */
sig->tty_old_pgrp = 0;
+ sig->tty = NULL;

sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
@@ -885,6 +887,7 @@ static inline int copy_signal(unsigned l
void __cleanup_signal(struct signal_struct *sig)
{
exit_thread_group_keys(sig);
+ tty_put(&sig->tty, 0, __FILE__, __LINE__);
kmem_cache_free(signal_cachep, sig);
}

@@ -1227,7 +1230,8 @@ #endif
__ptrace_link(p, current->parent);

if (thread_group_leader(p)) {
- p->signal->tty = current->signal->tty;
+ p->signal->tty = tty_get(current->signal->tty,
+ __FILE__, __LINE__);
p->signal->pgrp = process_group(current);
p->signal->session = current->signal->session;
attach_pid(p, PIDTYPE_PGID, process_group(p));
diff --git a/kernel/sys.c b/kernel/sys.c
index dbb3b9c..31f486a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1379,7 +1379,6 @@ asmlinkage long sys_setsid(void)
pid_t session;
int err = -EPERM;

- mutex_lock(&tty_mutex);
write_lock_irq(&tasklist_lock);

/* Fail if I am already a session leader */
@@ -1399,12 +1398,11 @@ asmlinkage long sys_setsid(void)

group_leader->signal->leader = 1;
__set_special_pids(session, session);
- group_leader->signal->tty = NULL;
+ tty_put(&group_leader->signal->tty, 0, __FILE__, __LINE__);
group_leader->signal->tty_old_pgrp = 0;
err = process_group(group_leader);
out:
write_unlock_irq(&tasklist_lock);
- mutex_unlock(&tty_mutex);
return err;
}

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 24caaee..db53c4e 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1638,7 +1638,8 @@ static inline void flush_unauthorized_fi
if (inode_has_perm(current, inode,
FILE__READ | FILE__WRITE, NULL)) {
/* Reset controlling tty. */
- current->signal->tty = NULL;
+ tty_put(&current->signal->tty, 0,
+ __FILE__, __LINE__);
current->signal->tty_old_pgrp = 0;
}
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/