diff -ur linux-2.2.9-np/fs/file.c linux/fs/file.c
--- linux-2.2.9-np/fs/file.c	Wed May 26 16:06:16 1999
+++ linux/fs/file.c	Fri May 28 12:43:18 1999
@@ -158,11 +158,49 @@
 }
 
 /*
+ * Allocate high-level bitmap
+ */
+
+unsigned long * alloc_fdbmap(int num)
+{
+	unsigned long *new_fdbmap;
+	int size = (num / FILES_PER_BIT + 7) / 8;
+
+	if (size < PAGE_SIZE)
+		new_fdbmap = (unsigned long *) kmalloc(size, GFP_KERNEL);
+	else if (size == PAGE_SIZE)
+		new_fdbmap = (unsigned long *) __get_free_page(GFP_KERNEL);
+	else
+		new_fdbmap = (unsigned long *) vmalloc(size);
+	return new_fdbmap;
+}
+
+void free_fdbmap(unsigned long *array, int num)
+{
+	int size = (num / FILES_PER_BIT + 7) / 8;
+
+	if (!array) {
+		printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num);
+		return;
+	}
+
+	if (num <= __FD_SETSIZE) /* Don't free an embedded fdset */
+		return;
+	else if (size < PAGE_SIZE)
+		kfree(array);
+	else if (size == PAGE_SIZE)
+		free_page((unsigned long) array);
+	else
+		vfree(array);
+}
+
+/*
  * Expand the fdset in the files_struct.
  */
 int expand_fdset(struct files_struct *files, int nr)
 {
 	fd_set *new_openset = 0, *new_execset = 0;
+	unsigned long *new_fdbmap = 0;
 	int error, nfds = 0;
 
 	error = -EMFILE;
@@ -184,7 +222,8 @@
 	error = -ENOMEM;
 	new_openset = alloc_fdset(nfds);
 	new_execset = alloc_fdset(nfds);
-	if (!new_openset || !new_execset)
+	new_fdbmap = alloc_fdbmap(nfds);
+	if (!new_openset || !new_execset || !new_fdbmap)
 		goto out;
 
 	error = 0;
@@ -203,12 +242,20 @@
 			memcpy (new_execset, files->close_on_exec, files->max_fdset/8);
 			memset (&new_openset->fds_bits[i], 0, count);
 			memset (&new_execset->fds_bits[i], 0, count);
+
+			i = (files->max_fdset / FILES_PER_BIT + 7) / 8;
+			count = (nfds / FILES_PER_BIT + 7) / 8 - i;
+			memcpy (new_fdbmap, files->open_fds_bmap,
+				(files->max_fdset / FILES_PER_BIT + 7) / 8);
+			memset ((char *)new_fdbmap + i, 0, count);
 		}
 
 		free_fdset (files->close_on_exec, files->max_fdset);
 		free_fdset (files->open_fds, files->max_fdset);
+		free_fdbmap (files->open_fds_bmap, files->max_fdset);
 		files->max_fdset = nfds;
 		files->open_fds = new_openset;
+		files->open_fds_bmap = new_fdbmap;
 		files->close_on_exec = new_execset;
 		return 0;
 	} 
@@ -217,8 +264,9 @@
 out:
 	if (new_openset)
 		free_fdset(new_openset, nfds);
+	if (new_fdbmap)
+		free_fdbmap(new_fdbmap, nfds);
 	if (new_execset)
 		free_fdset(new_execset, nfds);
 	return error;
 }
-
diff -ur linux-2.2.9-np/fs/open.c linux/fs/open.c
--- linux-2.2.9-np/fs/open.c	Wed May 26 16:06:16 1999
+++ linux/fs/open.c	Fri May 28 12:43:18 1999
@@ -684,6 +684,21 @@
 	return ERR_PTR(error);
 }
 
+inline void put_unused_fd(unsigned int fd) 
+{
+	FD_CLR(fd / FILES_PER_BIT, current->files->open_fds_bmap);
+	FD_CLR(fd, current->files->open_fds);
+	if (fd < current->files->next_fd)
+		current->files->next_fd = fd;
+}
+
+inline void put_used_fd(unsigned int fd) 
+{
+	FD_SET(fd, current->files->open_fds);
+	if (current->files->open_fds->fds_bits[fd / FILES_PER_BIT] == ~0UL)
+		FD_SET(fd / FILES_PER_BIT, current->files->open_fds_bmap);
+}
+
 /*
  * Find an empty file descriptor entry, and mark it busy.
  */
@@ -695,9 +710,17 @@
 repeat:
 	error = -EMFILE;
 
-	fd = find_next_zero_bit(files->open_fds, 
-				current->files->max_fdset, 
-				files->next_fd);
+	/*
+	 * Two-level bitmap, search first level for a free bucket, 
+	 * afterwards find free fd in bucket on lower-level bitmap. 
+	 */
+	fd = find_next_zero_bit(files->open_fds_bmap,
+				current->files->max_fdset / FILES_PER_BIT,
+				files->next_fd / FILES_PER_BIT) * FILES_PER_BIT;
+
+	if (fd < current->files->max_fdset)
+		fd += ffz(files->open_fds->fds_bits[fd / (8 * sizeof(unsigned long))]);
+
 	/*
 	 * N.B. For clone tasks sharing a files structure, this test
 	 * will limit the total number of files that can be opened.
@@ -723,7 +746,7 @@
 		goto out;
 	}
 
-	FD_SET(fd, files->open_fds);
+	put_used_fd(fd);
 	FD_CLR(fd, files->close_on_exec);
 	files->next_fd = fd + 1;
 #if 1
@@ -741,13 +764,6 @@
 		printk (KERN_ERR __FUNCTION__ ": return %d\n", error);
 #endif
 	return error;
-}
-
-inline void put_unused_fd(unsigned int fd)
-{
-	FD_CLR(fd, current->files->open_fds);
-	if (fd < current->files->next_fd)
-		current->files->next_fd = fd;
 }
 
 asmlinkage int sys_open(const char * filename, int flags, int mode)
diff -ur linux-2.2.9-np/include/linux/sched.h linux/include/linux/sched.h
--- linux-2.2.9-np/include/linux/sched.h	Wed May 26 16:06:16 1999
+++ linux/include/linux/sched.h	Fri May 28 12:44:42 1999
@@ -130,6 +130,14 @@
 #define NR_OPEN_DEFAULT BITS_PER_LONG
 
 /*
+ * Two-level bitmap to keep track of open files, one bit
+ * in the higher level bitmap corresponds to FILES_PER_BIT
+ * files in the lower level bitmap.
+ */
+
+#define FILES_PER_BIT  BITS_PER_LONG
+
+/*
  * Open file table structure
  */
 struct files_struct {
@@ -140,8 +148,10 @@
 	struct file ** fd;	/* current fd array */
 	fd_set *close_on_exec;
 	fd_set *open_fds;
+	unsigned long *open_fds_bmap;
 	fd_set close_on_exec_init;
 	fd_set open_fds_init;
+	unsigned long open_fds_bmap_init[__FD_SETSIZE/BITS_PER_LONG/FILES_PER_BIT];
 	struct file * fd_array[NR_OPEN_DEFAULT];
 };
 
@@ -153,8 +163,10 @@
 	&init_files.fd_array[0], \
 	&init_files.close_on_exec_init, \
 	&init_files.open_fds_init, \
+	&init_files.open_fds_bmap_init[0], \
 	{ { 0, } }, \
 	{ { 0, } }, \
+	{ 0, }, \
 	{ NULL, } \
 }
 
@@ -642,8 +654,10 @@
 extern void free_fd_array(struct file **, int);
 
 extern fd_set *alloc_fdset(int);
-extern int expand_fdset(struct files_struct *, int nr);
 extern void free_fdset(fd_set *, int);
+extern unsigned long *alloc_fdbmap(int);
+extern void free_fdbmap(unsigned long *, int);
+extern int expand_fdset(struct files_struct *, int nr);
 
 /* Expand files.  Return <0 on error; 0 nothing done; 1 files expanded,
  * we may have blocked. */
diff -ur linux-2.2.9-np/include/linux/tasks.h linux/include/linux/tasks.h
--- linux-2.2.9-np/include/linux/tasks.h	Sat May 22 14:15:22 1999
+++ linux/include/linux/tasks.h	Fri May 28 12:44:42 1999
@@ -11,9 +11,9 @@
 #define NR_CPUS 1
 #endif
 
-#define NR_TASKS	512	/* On x86 Max 4092, or 4090 w/APM configured. */
+#define NR_TASKS	4000	/* On x86 Max 4092, or 4090 w/APM configured. */
 
-#define MAX_TASKS_PER_USER (NR_TASKS/2)
+#define MAX_TASKS_PER_USER 3500
 #define MIN_TASKS_LEFT_FOR_ROOT 4
 
 
diff -ur linux-2.2.9-np/kernel/exit.c linux/kernel/exit.c
--- linux-2.2.9-np/kernel/exit.c	Wed May 26 16:06:16 1999
+++ linux/kernel/exit.c	Fri May 28 12:43:18 1999
@@ -196,6 +196,7 @@
  				free_fd_array(files->fd, files->max_fds);
  			if (files->max_fdset > __FD_SETSIZE) {
  				free_fdset(files->open_fds, files->max_fdset);
+				free_fdbmap(files->open_fds_bmap, files->max_fdset);
  				free_fdset(files->close_on_exec, files->max_fdset);
  			}
 			kmem_cache_free(files_cachep, files);
diff -ur linux-2.2.9-np/kernel/fork.c linux/kernel/fork.c
--- linux-2.2.9-np/kernel/fork.c	Wed May 26 16:06:16 1999
+++ linux/kernel/fork.c	Fri May 28 12:43:18 1999
@@ -455,6 +455,7 @@
 	newf->max_fdset	    = __FD_SETSIZE;
 	newf->close_on_exec = &newf->close_on_exec_init;
 	newf->open_fds	    = &newf->open_fds_init;
+	newf->open_fds_bmap = &newf->open_fds_bmap_init[0];
 	newf->fd	    = &newf->fd_array[0];
 
 	/* Even if the old fdset gets grown here, we'll only copy "size" fds */
@@ -464,7 +465,10 @@
 		if (error)
 			goto out_release;
 	}
+
 	memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, size/8);
+	memcpy(newf->open_fds_bmap, oldf->open_fds_bmap,
+		(size/FILES_PER_BIT + 7)/8);
 	memcpy(newf->close_on_exec->fds_bits, oldf->close_on_exec->fds_bits, size/8);
 	if (newf->max_fdset > size) {
 		int left = (newf->max_fdset-size)/8;
@@ -472,6 +476,10 @@
 		
 		memset(&newf->open_fds->fds_bits[start], 0, left);
 		memset(&newf->close_on_exec->fds_bits[start], 0, left);
+
+		start = (size/FILES_PER_BIT + 7)/8;
+		left = (newf->max_fdset/FILES_PER_BIT + 7)/8 - start;
+		memset((char *)&newf->open_fds_bmap + start, 0, left);
 	}
 
 	/* Find the last open fd */
@@ -531,6 +539,7 @@
 out_release:
 	free_fdset (newf->close_on_exec, newf->max_fdset);
 	free_fdset (newf->open_fds, newf->max_fdset);
+	free_fdbmap (newf->open_fds_bmap, newf->max_fdset);
 	kmem_cache_free(files_cachep, newf);
 	goto out;
 }
