diff -ur linux-2.1.130-fdset/fs/open.c linux/fs/open.c
--- linux-2.1.130-fdset/fs/open.c	Tue Dec  1 16:41:27 1998
+++ linux/fs/open.c	Tue Dec  1 16:17:18 1998
@@ -683,6 +683,21 @@
 	return 0;
 }
 
+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.
  */
@@ -694,9 +709,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.
@@ -722,7 +745,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
@@ -740,13 +763,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.1.130-fdset/include/linux/sched.h linux/include/linux/sched.h
--- linux-2.1.130-fdset/include/linux/sched.h	Tue Dec  1 16:41:27 1998
+++ linux/include/linux/sched.h	Tue Dec  1 16:53:22 1998
@@ -127,6 +127,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 {
@@ -137,8 +145,10 @@
 	struct file ** fd;	/* current fd array */
 	fd_set *close_on_exec;
 	fd_set *open_fds;
+	unsigned long *open_fds_bmap;	/* high level bitmap for open fds */
 	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];
 };
 
@@ -150,8 +160,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, } \
 }
 
@@ -627,8 +639,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.1.130-fdset/kernel/exit.c linux/kernel/exit.c
--- linux-2.1.130-fdset/kernel/exit.c	Tue Dec  1 16:41:27 1998
+++ linux/kernel/exit.c	Tue Dec  1 15:26:51 1998
@@ -195,6 +195,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.1.130-fdset/kernel/fork.c linux/kernel/fork.c
--- linux-2.1.130-fdset/kernel/fork.c	Tue Dec  1 16:41:27 1998
+++ linux/kernel/fork.c	Wed Dec  2 16:12:19 1998
@@ -1,4 +1,4 @@
-#undef FDSET_DEBUG
+#define FDSET_DEBUG
 
 /*
  *  linux/kernel/fork.c
@@ -501,11 +501,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;
 
 #ifdef FDSET_DEBUG	
@@ -531,7 +569,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;
@@ -550,12 +589,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;
 	} 
@@ -564,6 +611,8 @@
 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);
 #ifdef FDSET_DEBUG	
@@ -610,6 +659,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 */
@@ -619,7 +669,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;
@@ -627,6 +680,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 */
@@ -685,6 +742,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;
 }
