Re: tty_mutex and tty_old_pgrp

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

 



Here's what I have done so far.  These new functions need better names
and probably some reorganization. They move the job control code out
of tty_io.c over to exit.c (or is there a better place?) to make it
easier to see what is going on.  I haven't tried removing tty_mutex
yet.

void set_controlling_tty(struct tty_struct *tty);
void reset_controlling_tty(struct task_struct *task);
void reset_session_tty(pid_t session);
extern void clear_controlling_tty(int on_exit);
extern void clear_session_tty(pid_t session, struct tty_struct *tty,
pid_t pgrp);

--
Jon Smirl
[email protected]


diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 8b2a599..c677402 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -161,14 +161,16 @@ static struct tty_struct *alloc_tty_stru
 	struct tty_struct *tty;

 	tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
-	if (tty)
+	if (tty) {
 		memset(tty, 0, sizeof(struct tty_struct));
+		atomic_set(&tty->ref_count, 1);
+	}
 	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);
@@ -1026,7 +1028,6 @@ static void do_tty_hangup(void *data)
 	struct tty_struct *tty = (struct tty_struct *) data;
 	struct file * cons_filp = NULL;
 	struct file *filp, *f = NULL;
-	struct task_struct *p;
 	struct tty_ldisc *ld;
 	int    closecount = 0, n;

@@ -1096,22 +1097,9 @@ static void do_tty_hangup(void *data)
	
	  This should get done automatically when the port closes and
	  tty_release is called */
+	
+	clear_session_tty(tty->session, tty, tty->pgrp);
	
-	read_lock(&tasklist_lock);
-	if (tty->session > 0) {
-		do_each_task_pid(tty->session, PIDTYPE_SID, p) {
-			if (p->signal->tty == tty)
-				p->signal->tty = NULL;
-			if (!p->signal->leader)
-				continue;
-			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;
-		} while_each_task_pid(tty->session, PIDTYPE_SID, p);
-	}
-	read_unlock(&tasklist_lock);
-
 	tty->flags = 0;
 	tty->session = 0;
 	tty->pgrp = -1;
@@ -1174,65 +1162,6 @@ int tty_hung_up_p(struct file * filp)

EXPORT_SYMBOL(tty_hung_up_p);

-/*
- * This function is typically called only by the session leader, when
- * it wants to disassociate itself from its controlling tty.
- *
- * It performs the following functions:
- * 	(1)  Sends a SIGHUP and SIGCONT to the foreground process group
- * 	(2)  Clears the tty from being controlling the session
- * 	(3)  Clears the controlling tty for all processes in the
- * 		session group.
- *
- * The argument on_exit is set to 1 if called when a process is
- * exiting; it is 0 if called by the ioctl TIOCNOTTY.
- */
-void disassociate_ctty(int on_exit)
-{
-	struct tty_struct *tty;
-	struct task_struct *p;
-	int tty_pgrp = -1;
-
-	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 {
-		if (current->signal->tty_old_pgrp) {
-			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;
-	}
-	if (tty_pgrp > 0) {
-		kill_pg(tty_pgrp, SIGHUP, on_exit);
-		if (!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;
-
-	/* 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;
-	} while_each_task_pid(current->signal->session, PIDTYPE_SID, p);
-	read_unlock(&tasklist_lock);
-	mutex_unlock(&tty_mutex);
-	unlock_kernel();
-}
-
 void stop_tty(struct tty_struct *tty)
{
 	if (tty->stopped)
@@ -1931,10 +1860,12 @@ #endif

		read_lock(&tasklist_lock);
 		do_each_task_pid(tty->session, PIDTYPE_SID, p) {
+			tty_put(p->signal->tty);
 			p->signal->tty = NULL;
 		} while_each_task_pid(tty->session, PIDTYPE_SID, p);
		if (o_tty)
			do_each_task_pid(o_tty->session, PIDTYPE_SID, p) {
+				tty_put(p->signal->tty);
 				p->signal->tty = NULL;
			} while_each_task_pid(o_tty->session, PIDTYPE_SID, p);
		read_unlock(&tasklist_lock);
@@ -2133,10 +2064,7 @@ #endif
	    current->signal->leader &&
 	    !current->signal->tty &&
 	    tty->session == 0) {
-	    	task_lock(current);
-		current->signal->tty = tty;
-		task_unlock(current);
-		current->signal->tty_old_pgrp = 0;
+	    	set_controlling_tty(tty);
 		tty->session = current->signal->session;
 		tty->pgrp = process_group(current);
	}
@@ -2348,8 +2276,6 @@ static int fionbio(struct file *file, in

 static int tiocsctty(struct tty_struct *tty, int arg)
{
-	task_t *p;
-
	if (current->signal->leader &&
 	    (current->signal->session == tty->session))
		return 0;
@@ -2368,19 +2294,11 @@ static int tiocsctty(struct tty_struct *
			/*
			 * Steal it away
			 */
-
-			read_lock(&tasklist_lock);
-			do_each_task_pid(tty->session, PIDTYPE_SID, p) {
-				p->signal->tty = NULL;
-			} while_each_task_pid(tty->session, PIDTYPE_SID, p);
-			read_unlock(&tasklist_lock);
+			reset_session_tty(tty->session);
		} else
 			return -EPERM;
	}
-	task_lock(current);
-	current->signal->tty = tty;
-	task_unlock(current);
-	current->signal->tty_old_pgrp = 0;
+	set_controlling_tty(tty);
 	tty->session = current->signal->session;
 	tty->pgrp = process_group(current);
	return 0;
@@ -2588,8 +2506,9 @@ int tty_ioctl(struct inode * inode, stru
 			if (current->signal->tty != tty)
 				return -ENOTTY;
			if (current->signal->leader)
-				disassociate_ctty(0);
+				clear_controlling_tty(0);
			task_lock(current);
+			tty_put(current->signal->tty);
 			current->signal->tty = NULL;
			task_unlock(current);
			return 0;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 8d11d93..181f036 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1181,6 +1181,12 @@ extern void exit_itimers(struct signal_s

 extern NORET_TYPE void do_group_exit(int);

+void set_controlling_tty(struct tty_struct *tty);
+void reset_controlling_tty(struct task_struct *task);
+void reset_session_tty(pid_t session);
+extern void clear_controlling_tty(int on_exit);
+extern void clear_session_tty(pid_t session, struct tty_struct *tty,
pid_t pgrp);
+
 extern void daemonize(const char *, ...);
 extern int allow_signal(int);
 extern int disallow_signal(int);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index cb35ca5..3937a4e 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -182,6 +182,7 @@ struct device;
 */
 struct tty_struct {
	int	magic;
+	atomic_t ref_count;
 	struct tty_driver *driver;
	int index;
 	struct tty_ldisc ldisc;
@@ -269,6 +270,22 @@ #define TTY_HUPPED 		18	/* Post driver->

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

+static inline struct tty_struct * tty_get(struct tty_struct * tty)
+{
+        if (tty) {
+                WARN_ON(!atomic_read(&tty->ref_count));
+                atomic_inc(&tty->ref_count);
+        }
+        return tty;
+}
+
+extern void free_tty_struct(struct tty_struct *tty);
+static inline void tty_put(struct tty_struct * tty)
+{
+        if (tty && atomic_dec_and_test(&tty->ref_count))
+                free_tty_struct(tty);
+}
+
 extern void tty_write_flush(struct tty_struct *);

 extern struct termios tty_std_termios;
@@ -306,7 +323,6 @@ extern void tty_vhangup(struct tty_struc
 extern void tty_unhangup(struct file *filp);
 extern int tty_hung_up_p(struct file * filp);
 extern void do_SAK(struct tty_struct *tty);
-extern void disassociate_ctty(int priv);
 extern void tty_flip_buffer_push(struct tty_struct *tty);
 extern int tty_get_baud_rate(struct tty_struct *tty);
 extern int tty_termios_baud_rate(struct termios *termios);
diff --git a/kernel/exit.c b/kernel/exit.c
index e76bd02..ea09822 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -379,6 +379,122 @@ EXPORT_SYMBOL(disallow_signal);
 *	attached user resources in one place where it belongs.
 */

+void set_controlling_tty(struct tty_struct *tty)
+{
+	task_lock(current);
+	current->signal->tty = tty_get(tty);
+	task_unlock(current);
+	current->signal->tty_old_pgrp = 0;
+}
+
+EXPORT_SYMBOL(set_controlling_tty);
+
+void reset_session_tty(pid_t session)
+{
+	struct task_struct *p;
+	
+	read_lock(&tasklist_lock);
+	do_each_task_pid(session, PIDTYPE_SID, p) {
+		tty_put(p->signal->tty);
+		p->signal->tty = NULL;
+	} while_each_task_pid(session, PIDTYPE_SID, p);
+	read_unlock(&tasklist_lock);
+}
+
+EXPORT_SYMBOL(reset_session_tty);
+
+void reset_controlling_tty(struct task_struct *task)
+{
+	/* Reset controlling tty. */
+	mutex_lock(&tty_mutex);
+	tty_put(task->signal->tty);
+	task->signal->tty = NULL;
+	task->signal->tty_old_pgrp = 0;
+	mutex_unlock(&tty_mutex);
+}
+
+EXPORT_SYMBOL(reset_controlling_tty);
+
+/*
+ * This function is typically called only by the session leader, when
+ * it wants to disassociate itself from its controlling tty.
+ *
+ * It performs the following functions:
+ * 	(1)  Sends a SIGHUP and SIGCONT to the foreground process group
+ * 	(2)  Clears the tty from being controlling the session
+ * 	(3)  Clears the controlling tty for all processes in the
+ * 		session group.
+ *
+ * The argument on_exit is set to 1 if called when a process is
+ * exiting; it is 0 if called by the ioctl TIOCNOTTY.
+ */
+void clear_controlling_tty(int on_exit)
+{
+	struct tty_struct *tty;
+	int tty_pgrp = -1;
+
+	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 {
+		if (current->signal->tty_old_pgrp) {
+			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;
+	}
+	if (tty_pgrp > 0) {
+		kill_pg(tty_pgrp, SIGHUP, on_exit);
+		if (!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;
+
+	/* Now clear signal->tty under the lock */
+	reset_session_tty(current->signal->session);
+	mutex_unlock(&tty_mutex);
+	unlock_kernel();
+}
+
+EXPORT_SYMBOL(clear_controlling_tty);
+
+void clear_session_tty(pid_t session, struct tty_struct *tty, pid_t pgrp)
+{
+	struct task_struct *p;
+	
+	read_lock(&tasklist_lock);
+	if (session > 0) {
+		do_each_task_pid(session, PIDTYPE_SID, p) {
+			if (p->signal->tty == tty) {
+				tty_put(p->signal->tty);
+				p->signal->tty = NULL;
+			}
+			if (!p->signal->leader)
+				continue;
+			group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+			group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
+			if (pgrp > 0)
+				p->signal->tty_old_pgrp = tty->pgrp;
+		} while_each_task_pid(session, PIDTYPE_SID, p);
+	}
+	read_unlock(&tasklist_lock);
+}
+
+EXPORT_SYMBOL(clear_session_tty);
+
void daemonize(const char *name, ...)
{
	va_list args;
@@ -398,6 +514,7 @@ void daemonize(const char *name, ...)

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

@@ -917,7 +1034,7 @@ #endif
	exit_keys(tsk);

	if (group_dead && tsk->signal->leader)
-		disassociate_ctty(1);
+		clear_controlling_tty(1);

	module_put(task_thread_info(tsk)->exec_domain->module);
	if (tsk->binfmt)
diff --git a/kernel/fork.c b/kernel/fork.c
index dfd10cb..34e7797 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -44,6 +44,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>
@@ -1201,7 +1202,7 @@ #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);
			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 2d5179c..c97370f 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1400,8 +1400,7 @@ asmlinkage long sys_setsid(void)

	group_leader->signal->leader = 1;
	__set_special_pids(session, session);
-	group_leader->signal->tty = NULL;
-	group_leader->signal->tty_old_pgrp = 0;
+	reset_controlling_tty(group_leader);
	err = process_group(group_leader);
out:
	write_unlock_irq(&tasklist_lock);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 79c16e3..f3e128a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1624,9 +1624,7 @@ static inline void flush_unauthorized_fi
			struct inode *inode = file->f_dentry->d_inode;
			if (inode_has_perm(current, inode,
					   FILE__READ | FILE__WRITE, NULL)) {
-				/* Reset controlling tty. */
-				current->signal->tty = NULL;
-				current->signal->tty_old_pgrp = 0;
+				reset_controlling_tty(current);
			}
		}
		file_list_unlock();
-
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