---

 25-akpm/drivers/char/tty_io.c |   57 ++++++++++++++++++++++++++++++++++--------
 1 files changed, 47 insertions(+), 10 deletions(-)

diff -puN drivers/char/tty_io.c~pty-allocation-first-fit drivers/char/tty_io.c
--- 25/drivers/char/tty_io.c~pty-allocation-first-fit	2004-05-17 18:28:49.621270672 -0700
+++ 25-akpm/drivers/char/tty_io.c	2004-05-17 18:33:02.903765880 -0700
@@ -91,6 +91,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/device.h>
+#include <linux/idr.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -128,6 +129,8 @@ DECLARE_MUTEX(tty_sem);
 #ifdef CONFIG_UNIX98_PTYS
 extern struct tty_driver *ptm_driver;	/* Unix98 pty masters; for /dev/ptmx */
 extern int pty_limit;		/* Config limit on Unix98 ptys */
+static DEFINE_IDR(allocated_ptys);
+static DECLARE_MUTEX(allocated_ptys_lock);
 #endif
 
 extern void disable_early_printk(void);
@@ -1295,6 +1298,14 @@ static void release_dev(struct file * fi
 		o_tty->ldisc = ldiscs[N_TTY];
 	}
 
+#ifdef CONFIG_UNIX98_PTYS
+	if (filp->f_dentry->d_inode->i_rdev == MKDEV(TTYAUX_MAJOR,2)) {
+		down(&allocated_ptys_lock);
+		idr_remove(&allocated_ptys, idx);
+		up(&allocated_ptys_lock);
+	}
+#endif
+
 	/* 
 	 * The release_mem function takes care of the details of clearing
 	 * the slots and preserving the termios structure.
@@ -1319,7 +1330,7 @@ static int tty_open(struct inode * inode
 	struct tty_struct *tty;
 	int noctty, retval;
 	struct tty_driver *driver;
-	int index;
+	int index = -1;
 	dev_t device = inode->i_rdev;
 	unsigned short saved_flags = filp->f_flags;
 retry_open:
@@ -1361,23 +1372,41 @@ retry_open:
 
 #ifdef CONFIG_UNIX98_PTYS
 	if (device == MKDEV(TTYAUX_MAJOR,2)) {
+		int idr_ret;
+
 		/* find a device that is not in use. */
-		static int next_ptmx_dev = 0;
-		retval = -1;
+		down(&allocated_ptys_lock);
+		if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
+			up(&allocated_ptys_lock);
+			return -ENOMEM;
+		}
+		idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
+		if (idr_ret < 0) {
+			up(&allocated_ptys_lock);
+			if (idr_ret == -EAGAIN)
+				return -ENOMEM;
+			return -EIO;
+		}
+		if (index >= pty_limit) {
+			idr_remove(&allocated_ptys, index);
+			up(&allocated_ptys_lock);
+			return -EIO;
+		}
 		driver = ptm_driver;
-		while (driver->refcount < pty_limit) {
-			index = next_ptmx_dev;
-			next_ptmx_dev = (next_ptmx_dev+1) % driver->num;
-			if (!init_dev(driver, index, &tty))
-				goto ptmx_found; /* ok! */
+		retval = init_dev(driver, index, &tty);
+		if (retval) {
+			idr_remove(&allocated_ptys, index);
+			up(&allocated_ptys_lock);
+			return retval;
 		}
-		return -EIO; /* no free ptys */
-	ptmx_found:
 		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 		if (devpts_pty_new(tty->link)) {
 			/* BADNESS - need to destroy both ptm and pts! */
+			idr_remove(&allocated_ptys, index);
+			up(&allocated_ptys_lock);
 			return -ENOMEM;
 		}
+		up(&allocated_ptys_lock);
 		noctty = 1;
 	} else
 #endif
@@ -1415,6 +1444,14 @@ got_driver:
 		       tty->name);
 #endif
 
+#ifdef CONFIG_UNIX98_PTYS
+		if (index != -1) {
+			down(&allocated_ptys_lock);
+			idr_remove(&allocated_ptys, index);
+			up(&allocated_ptys_lock);
+		}
+#endif
+
 		release_dev(filp);
 		if (retval != -ERESTARTSYS)
 			return retval;

_