diff -ruN linux-2.2.3-ac4-reference/fs/file.c linux/fs/file.c --- linux-2.2.3-ac4-reference/fs/file.c Wed Mar 24 16:03:44 1999 +++ linux/fs/file.c Wed Mar 24 13:47:55 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 -ruN linux-2.2.3-ac4-reference/fs/open.c linux/fs/open.c --- linux-2.2.3-ac4-reference/fs/open.c Wed Mar 24 16:03:44 1999 +++ linux/fs/open.c Wed Mar 24 13:35:31 1999 @@ -675,6 +675,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. */ @@ -686,9 +701,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. @@ -714,7 +737,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 @@ -732,13 +755,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 -ruN linux-2.2.3-ac4-reference/include/linux/sched.h linux/include/linux/sched.h --- linux-2.2.3-ac4-reference/include/linux/sched.h Wed Mar 24 16:03:44 1999 +++ linux/include/linux/sched.h Wed Mar 24 13:55:50 1999 @@ -129,6 +129,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 { @@ -139,8 +147,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]; }; @@ -152,8 +162,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, } \ } @@ -641,8 +653,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 -ruN linux-2.2.3-ac4-reference/include/linux/tasks.h linux/include/linux/tasks.h --- linux-2.2.3-ac4-reference/include/linux/tasks.h Mon Jan 25 19:04:20 1999 +++ linux/include/linux/tasks.h Wed Mar 24 13:55:50 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 -ruN linux-2.2.3-ac4-reference/kernel/exit.c linux/kernel/exit.c --- linux-2.2.3-ac4-reference/kernel/exit.c Wed Mar 24 16:03:44 1999 +++ linux/kernel/exit.c Wed Mar 24 13:40:17 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 -ruN linux-2.2.3-ac4-reference/kernel/fork.c linux/kernel/fork.c --- linux-2.2.3-ac4-reference/kernel/fork.c Wed Mar 24 16:03:44 1999 +++ linux/kernel/fork.c Wed Mar 24 13:52:51 1999 @@ -416,6 +416,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 */ @@ -425,7 +426,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; @@ -433,6 +437,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 */ @@ -492,6 +500,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; }