patch-2.1.115 linux/drivers/char/tty_io.c

Next file: linux/drivers/char/vt.c
Previous file: linux/drivers/char/stallion.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.114/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
@@ -65,6 +65,7 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
+#include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/devpts_fs.h>
 #include <linux/file.h>
@@ -80,6 +81,7 @@
 #include <linux/proc_fs.h>
 #endif
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -107,6 +109,10 @@
 struct tty_driver *tty_drivers = NULL;	/* linked list of tty drivers */
 struct tty_ldisc ldiscs[NR_LDISCS];	/* line disc dispatch table	*/
 
+#ifdef CONFIG_UNIX98_PTYS
+extern struct tty_driver ptm_driver[];	/* Unix98 pty masters; for /dev/ptmx */
+#endif
+
 /*
  * redirect is the pseudo-tty that console output
  * is redirected to if asked by TIOCCONS.
@@ -371,17 +377,24 @@
 	NULL		/* hung_up_tty_fasync */
 };
 
+/*
+ * This can be called through the "tq_scheduler" 
+ * task-list. That is process synchronous, but
+ * doesn't hold any locks, so we need to make
+ * sure we have the appropriate locks for what
+ * we're doing..
+ */
 void do_tty_hangup(void *data)
 {
 	struct tty_struct *tty = (struct tty_struct *) data;
 	struct file * filp;
 	struct task_struct *p;
-	unsigned long	flags;
 
 	if (!tty)
 		return;
-	
-	save_flags(flags); cli();
+
+	/* inuse_filps is protected by the single kernel lock */
+	lock_kernel();
 	
 	check_tty_count(tty, "do_tty_hangup");
 	for (filp = inuse_filps; filp; filp = filp->f_next) {
@@ -400,13 +413,21 @@
 		filp->f_op = &hung_up_tty_fops;
 	}
 	
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
-	if (tty->driver.flush_buffer)
-		tty->driver.flush_buffer(tty);
-	if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+	/* FIXME! What are the locking issues here? This may me overdoing things.. */
+	{
+		unsigned long flags;
+
+		save_flags(flags); cli();
+		if (tty->ldisc.flush_buffer)
+			tty->ldisc.flush_buffer(tty);
+		if (tty->driver.flush_buffer)
+			tty->driver.flush_buffer(tty);
+		if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		restore_flags(flags);
+	}
+
 	wake_up_interruptible(&tty->write_wait);
 	wake_up_interruptible(&tty->read_wait);
 
@@ -449,7 +470,7 @@
 	tty->ctrl_status = 0;
 	if (tty->driver.hangup)
 		(tty->driver.hangup)(tty);
-	restore_flags(flags);
+	unlock_kernel();
 }
 
 void tty_hangup(struct tty_struct * tty)
@@ -459,7 +480,7 @@
 	
 	printk("%s hangup...\n", tty_name(tty, buf));
 #endif
-	queue_task(&tty->tq_hangup, &tq_timer);
+	queue_task(&tty->tq_hangup, &tq_scheduler);
 }
 
 void tty_vhangup(struct tty_struct * tty)
@@ -1158,6 +1179,7 @@
 	 * Make sure that the tty's task queue isn't activated. 
 	 */
 	run_task_queue(&tq_timer);
+	run_task_queue(&tq_scheduler);
 
 	/* 
 	 * The release_mem function takes care of the details of clearing
@@ -1213,34 +1235,33 @@
                 device = c->device(c);
 		noctty = 1;
 	}
+#ifdef CONFIG_UNIX98_PTYS
 	if (device == PTMX_DEV) {
 		/* find a free pty. */
-		struct tty_driver *driver = tty_drivers;
-		int minor, line;
+		int major, minor, line;
+		struct tty_driver *driver;
 
-		/* find the pty driver */
-		for (driver=tty_drivers; driver; driver=driver->next)
-			if (driver->major == PTY_MASTER_MAJOR)
-				break;
-		if (!driver) return -ENODEV;
-
-		/* find a minor device that is not in use. */
-		for (minor=driver->minor_start;
-		     minor<driver->minor_start+driver->num;
-		     minor++) {
-			device = MKDEV(driver->major, minor);
-			retval = init_dev(device, &tty);
-			if (retval==0) break; /* success! */
+		/* find a device that is not in use. */
+		retval = -1;
+		for ( major = 0 ; major < UNIX98_NR_MAJORS ; major++ ) {
+			driver = &ptm_driver[major];
+			for (minor = driver->minor_start ;
+			     minor < driver->minor_start + driver->num ;
+			     minor++) {
+				device = MKDEV(driver->major, minor);
+				if (!init_dev(device, &tty)) goto ptmx_found; /* ok! */
+			}
 		}
-		if (minor==driver->minor_start+driver->num) /* no success */
-			return -EIO; /* no free ptys */
-		
+		return -EIO; /* no free ptys */
+	ptmx_found:
 		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 		line = minor - driver->minor_start;
-		devpts_pty_new(line, MKDEV(driver->other->major, line+driver->other->minor_start));
+		devpts_pty_new(line + major*NR_PTYS, MKDEV(driver->other->major,
+				   line+driver->other->minor_start));
 		noctty = 1;
 		goto init_dev_done;
 	}
+#endif
 	
 	retval = init_dev(device, &tty);
 	if (retval)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov