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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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
[email protected]



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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux