diff -urN 2.2.11/arch/alpha/kernel/process.c 2.2.11-large-fd-set/arch/alpha/kernel/process.c --- 2.2.11/arch/alpha/kernel/process.c Thu Aug 12 02:32:28 1999 +++ 2.2.11-large-fd-set/arch/alpha/kernel/process.c Thu Aug 12 03:16:25 1999 @@ -55,7 +55,6 @@ unsigned long init_user_stack[1024] = { STACK_MAGIC, }; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -urN 2.2.11/arch/i386/kernel/init_task.c 2.2.11-large-fd-set/arch/i386/kernel/init_task.c --- 2.2.11/arch/i386/kernel/init_task.c Mon Jan 18 02:28:58 1999 +++ 2.2.11-large-fd-set/arch/i386/kernel/init_task.c Thu Aug 12 03:16:25 1999 @@ -7,7 +7,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -urN 2.2.11/arch/m68k/kernel/process.c 2.2.11-large-fd-set/arch/m68k/kernel/process.c --- 2.2.11/arch/m68k/kernel/process.c Tue Jul 13 00:33:09 1999 +++ 2.2.11-large-fd-set/arch/m68k/kernel/process.c Thu Aug 12 03:16:25 1999 @@ -40,7 +40,6 @@ */ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -urN 2.2.11/arch/ppc/kernel/process.c 2.2.11-large-fd-set/arch/ppc/kernel/process.c --- 2.2.11/arch/ppc/kernel/process.c Thu Aug 12 02:32:28 1999 +++ 2.2.11-large-fd-set/arch/ppc/kernel/process.c Thu Aug 12 03:16:28 1999 @@ -47,7 +47,6 @@ struct task_struct *last_task_used_math = NULL; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -urN 2.2.11/arch/ppc/kernel/syscalls.c 2.2.11-large-fd-set/arch/ppc/kernel/syscalls.c --- 2.2.11/arch/ppc/kernel/syscalls.c Thu Aug 12 02:32:28 1999 +++ 2.2.11-large-fd-set/arch/ppc/kernel/syscalls.c Thu Aug 12 03:16:28 1999 @@ -202,7 +202,8 @@ lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if (fd >= current->files->max_fds || + !(file = current->files->fd[fd])) goto out; } diff -urN 2.2.11/arch/sparc/kernel/init_task.c 2.2.11-large-fd-set/arch/sparc/kernel/init_task.c --- 2.2.11/arch/sparc/kernel/init_task.c Mon Jan 18 02:29:08 1999 +++ 2.2.11-large-fd-set/arch/sparc/kernel/init_task.c Thu Aug 12 03:16:28 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -urN 2.2.11/arch/sparc64/kernel/init_task.c 2.2.11-large-fd-set/arch/sparc64/kernel/init_task.c --- 2.2.11/arch/sparc64/kernel/init_task.c Mon Jan 18 02:29:22 1999 +++ 2.2.11-large-fd-set/arch/sparc64/kernel/init_task.c Thu Aug 12 03:16:29 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -urN 2.2.11/arch/sparc64/solaris/timod.c 2.2.11-large-fd-set/arch/sparc64/solaris/timod.c --- 2.2.11/arch/sparc64/solaris/timod.c Mon Jan 18 02:29:23 1999 +++ 2.2.11-large-fd-set/arch/sparc64/solaris/timod.c Thu Aug 12 03:16:29 1999 @@ -866,7 +866,7 @@ SOLD("entry"); lock_kernel(); - if(fd >= NR_OPEN) goto out; + if(fd >= current->files->max_fds) goto out; filp = current->files->fd[fd]; if(!filp) goto out; @@ -933,7 +933,7 @@ SOLD("entry"); lock_kernel(); - if(fd >= NR_OPEN) goto out; + if(fd >= current->files->max_fds) goto out; filp = current->files->fd[fd]; if(!filp) goto out; diff -urN 2.2.11/fs/Makefile 2.2.11-large-fd-set/fs/Makefile --- 2.2.11/fs/Makefile Thu Aug 12 02:32:33 1999 +++ 2.2.11-large-fd-set/fs/Makefile Thu Aug 12 03:16:29 1999 @@ -13,7 +13,7 @@ O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \ super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \ - dcache.o inode.o attr.o bad_inode.o $(BINFMTS) + dcache.o inode.o attr.o bad_inode.o file.o $(BINFMTS) MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ diff -urN 2.2.11/fs/exec.c 2.2.11-large-fd-set/fs/exec.c --- 2.2.11/fs/exec.c Tue Jul 13 00:33:22 1999 +++ 2.2.11-large-fd-set/fs/exec.c Thu Aug 12 03:16:29 1999 @@ -482,10 +482,10 @@ unsigned long set, i; i = j * __NFDBITS; - if (i >= files->max_fds) + if (i >= files->max_fds || i >= files->max_fdset) break; - set = files->close_on_exec.fds_bits[j]; - files->close_on_exec.fds_bits[j] = 0; + set = files->close_on_exec->fds_bits[j]; + files->close_on_exec->fds_bits[j] = 0; j++; for ( ; set ; i++,set >>= 1) { if (set & 1) diff -urN 2.2.11/fs/fcntl.c 2.2.11-large-fd-set/fs/fcntl.c --- 2.2.11/fs/fcntl.c Mon Jan 18 02:26:48 1999 +++ 2.2.11-large-fd-set/fs/fcntl.c Thu Aug 12 03:16:29 1999 @@ -12,14 +12,15 @@ extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg); -static inline int dupfd(unsigned int fd, unsigned int arg) +static inline int dupfd(unsigned int fd, unsigned int start) { struct files_struct * files = current->files; struct file * file; + unsigned int newfd; int error; error = -EINVAL; - if (arg >= NR_OPEN) + if (start >= NR_OPEN) goto out; error = -EBADF; @@ -27,15 +28,39 @@ if (!file) goto out; +repeat: error = -EMFILE; - arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg); - if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur) + if (start < files->next_fd) + start = files->next_fd; + /* At this point, start MUST be <= max_fdset */ +#if 1 + if (start > files->max_fdset) + printk (KERN_ERR "dupfd: fd %d, max %d\n", + start, files->max_fdset); +#endif + newfd = find_next_zero_bit(files->open_fds->fds_bits, + files->max_fdset, + start); + if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur) goto out_putf; - FD_SET(arg, &files->open_fds); - FD_CLR(arg, &files->close_on_exec); - fd_install(arg, file); - error = arg; + + error = expand_files(files, newfd); + if (error < 0) + goto out_putf; + if (error) /* If we might have blocked, try again. */ + goto repeat; + + FD_SET(newfd, files->open_fds); + FD_CLR(newfd, files->close_on_exec); + if (start <= files->next_fd) + files->next_fd = newfd + 1; + fd_install(newfd, file); + error = newfd; out: +#ifdef FDSET_DEBUG + if (error < 0) + printk (KERN_ERR __FUNCTION__ ": return %d\n", error); +#endif return error; out_putf: @@ -48,18 +73,30 @@ int err = -EBADF; lock_kernel(); +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ " 0: oldfd = %d, newfd = %d\n", + oldfd, newfd); +#endif if (!fcheck(oldfd)) goto out; + if (newfd >= NR_OPEN) + goto out; /* following POSIX.1 6.2.1 */ + err = newfd; if (newfd == oldfd) goto out; - err = -EBADF; - if (newfd >= NR_OPEN) - goto out; /* following POSIX.1 6.2.1 */ + /* We must be able to do the fd setting inside dupfd() without + blocking after the sys_close(). */ + if ((err = expand_files(current->files, newfd)) < 0) + goto out; + sys_close(newfd); err = dupfd(oldfd, newfd); out: +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ ": return %d\n", err); +#endif unlock_kernel(); return err; } @@ -71,6 +108,10 @@ lock_kernel(); ret = dupfd(fildes, 0); unlock_kernel(); +#ifdef FDSET_DEBUG + if (ret < 0) + printk (KERN_ERR __FUNCTION__ ": return %d\n", ret); +#endif return ret; } @@ -117,13 +158,13 @@ err = dupfd(fd, arg); break; case F_GETFD: - err = FD_ISSET(fd, ¤t->files->close_on_exec); + err = FD_ISSET(fd, current->files->close_on_exec); break; case F_SETFD: if (arg&1) - FD_SET(fd, ¤t->files->close_on_exec); + FD_SET(fd, current->files->close_on_exec); else - FD_CLR(fd, ¤t->files->close_on_exec); + FD_CLR(fd, current->files->close_on_exec); break; case F_GETFL: err = filp->f_flags; diff -urN 2.2.11/fs/file.c 2.2.11-large-fd-set/fs/file.c --- 2.2.11/fs/file.c Thu Jan 1 01:00:00 1970 +++ 2.2.11-large-fd-set/fs/file.c Thu Aug 12 03:16:29 1999 @@ -0,0 +1,224 @@ +/* + * linux/fs/open.c + * + * Copyright (C) 1998, Stephen Tweedie and Bill Hawes + * + * Manage the dynamic fd arrays in the process files_struct. + */ + +#include +#include +#include +#include +#include + +#include + + +/* + * Allocate an fd array, using get_free_page() if possible. + * Note: the array isn't cleared at allocation time. + */ +struct file ** alloc_fd_array(int num) +{ + struct file **new_fds; + int size = num * sizeof(struct file *); + + if (size < PAGE_SIZE) + new_fds = (struct file **) kmalloc(size, GFP_KERNEL); + else if (size == PAGE_SIZE) + new_fds = (struct file **) __get_free_page(GFP_KERNEL); + else + new_fds = (struct file **) vmalloc(size); + return new_fds; +} + +void free_fd_array(struct file **array, int num) +{ + int size = num * sizeof(struct file *); + + if (!array) { + printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num); + return; + } + + if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */ + return; + else if (size < PAGE_SIZE) + kfree(array); + else if (size == PAGE_SIZE) + free_page((unsigned long) array); + else + vfree(array); +} + +/* + * Expand the fd array in the files_struct. + */ + +int expand_fd_array(struct files_struct *files, int nr) +{ + struct file **new_fds; + int error, nfds; + + + error = -EMFILE; + if (files->max_fds >= NR_OPEN || nr > NR_OPEN) + goto out; + + nfds = files->max_fds; + + /* + * Expand to the max in easy steps, and keep expanding it until + * we have enough for the requested fd array size. + */ + + do { +#if NR_OPEN_DEFAULT < 256 + if (nfds < 256) + nfds = 256; + else +#endif + if (nfds < (PAGE_SIZE / sizeof(struct file *))) + nfds = PAGE_SIZE / sizeof(struct file *); + else { + nfds = nfds * 2; + if (nfds > NR_OPEN) + nfds = NR_OPEN; + } + } while (nfds < nr); + + error = -ENOMEM; + new_fds = alloc_fd_array(nfds); + if (!new_fds) + goto out; + + /* Copy the existing array and install the new pointer */ + + if (nfds > files->max_fds) { + struct file **old_fds; + int i = files->max_fds; + + old_fds = files->fd; + files->fd = new_fds; + files->max_fds = nfds; + /* Don't copy/clear the array if we are creating a new + fd array for fork() */ + if (i) { + memcpy(new_fds, old_fds, i * sizeof(struct file *)); + /* clear the remainder of the array */ + memset(&new_fds[i], 0, + (nfds-i) * sizeof(struct file *)); + free_fd_array(old_fds, i); + } + } else { + /* Somebody expanded the array while we slept ... */ + free_fd_array(new_fds, nfds); + } + error = 0; +out: + return error; +} + +/* + * Allocate an fdset array, using get_free_page() if possible. + * Note: the array isn't cleared at allocation time. + */ +fd_set * alloc_fdset(int num) +{ + fd_set *new_fdset; + int size = num / 8; + + if (size < PAGE_SIZE) + new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL); + else if (size == PAGE_SIZE) + new_fdset = (fd_set *) __get_free_page(GFP_KERNEL); + else + new_fdset = (fd_set *) vmalloc(size); + return new_fdset; +} + +void free_fdset(fd_set *array, int num) +{ + int size = num / 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; + int error, nfds = 0; + + error = -EMFILE; + if (files->max_fdset >= NR_OPEN || nr > NR_OPEN) + goto out; + + nfds = files->max_fdset; + /* Expand to the max in easy steps */ + do { + if (nfds < (PAGE_SIZE * 8)) + nfds = PAGE_SIZE * 8; + else { + nfds = nfds * 2; + if (nfds > NR_OPEN) + nfds = NR_OPEN; + } + } while (nfds < nr); + + error = -ENOMEM; + new_openset = alloc_fdset(nfds); + new_execset = alloc_fdset(nfds); + if (!new_openset || !new_execset) + goto out; + + error = 0; + + /* Copy the existing tables and install the new pointers */ + if (nfds > files->max_fdset) { + int i = files->max_fdset / (sizeof(unsigned long) * 8); + int count = (nfds - files->max_fdset) / 8; + + /* + * Don't copy the entire array if the current fdset is + * not yet initialised. + */ + if (i) { + memcpy (new_openset, files->open_fds, files->max_fdset/8); + 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); + } + + free_fdset (files->close_on_exec, files->max_fdset); + free_fdset (files->open_fds, files->max_fdset); + files->max_fdset = nfds; + files->open_fds = new_openset; + files->close_on_exec = new_execset; + return 0; + } + /* Somebody expanded the array while we slept ... */ + +out: + if (new_openset) + free_fdset(new_openset, nfds); + if (new_execset) + free_fdset(new_execset, nfds); + return error; +} + diff -urN 2.2.11/fs/ioctl.c 2.2.11-large-fd-set/fs/ioctl.c --- 2.2.11/fs/ioctl.c Thu Aug 12 02:32:33 1999 +++ 2.2.11-large-fd-set/fs/ioctl.c Thu Aug 12 03:16:29 1999 @@ -54,11 +54,11 @@ error = 0; switch (cmd) { case FIOCLEX: - FD_SET(fd, ¤t->files->close_on_exec); + FD_SET(fd, current->files->close_on_exec); break; case FIONCLEX: - FD_CLR(fd, ¤t->files->close_on_exec); + FD_CLR(fd, current->files->close_on_exec); break; case FIONBIO: diff -urN 2.2.11/fs/open.c 2.2.11-large-fd-set/fs/open.c --- 2.2.11/fs/open.c Tue Jul 13 00:32:59 1999 +++ 2.2.11-large-fd-set/fs/open.c Thu Aug 12 03:16:29 1999 @@ -692,8 +692,12 @@ struct files_struct * files = current->files; int fd, error; +repeat: error = -EMFILE; - fd = find_first_zero_bit(&files->open_fds, NR_OPEN); + + fd = find_next_zero_bit(files->open_fds, + current->files->max_fdset, + files->next_fd); /* * N.B. For clone tasks sharing a files structure, this test * will limit the total number of files that can be opened. @@ -701,10 +705,27 @@ if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur) goto out; - /* Check here for fd > files->max_fds to do dynamic expansion */ + /* Do we need to expand the fdset array? */ + if (fd >= current->files->max_fdset) { + error = expand_fdset(files, 0); + if (!error) + goto repeat; + goto out; + } + + /* + * Check whether we need to expand the fd array. + */ + if (fd >= files->max_fds) { + error = expand_fd_array(files, 0); + if (!error) + goto repeat; + goto out; + } - FD_SET(fd, &files->open_fds); - FD_CLR(fd, &files->close_on_exec); + FD_SET(fd, files->open_fds); + FD_CLR(fd, files->close_on_exec); + files->next_fd = fd + 1; #if 1 /* Sanity check */ if (files->fd[fd] != NULL) { @@ -715,12 +736,18 @@ error = fd; out: +#ifdef FDSET_DEBUG + if (error < 0) + printk (KERN_ERR __FUNCTION__ ": return %d\n", error); +#endif return error; } inline void put_unused_fd(unsigned int fd) { - FD_CLR(fd, ¤t->files->open_fds); + 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) @@ -820,8 +847,8 @@ struct files_struct * files = current->files; files->fd[fd] = NULL; put_unused_fd(fd); - FD_CLR(fd, &files->close_on_exec); - error = filp_close(filp, files); + FD_CLR(fd, files->close_on_exec); + error = filp_close(filp, files); } unlock_kernel(); return error; diff -urN 2.2.11/fs/select.c 2.2.11-large-fd-set/fs/select.c --- 2.2.11/fs/select.c Tue Jul 13 00:33:22 1999 +++ 2.2.11-large-fd-set/fs/select.c Thu Aug 12 03:16:29 1999 @@ -107,7 +107,7 @@ /* handle last in-complete long-word first */ set = ~(~0UL << (n & (__NFDBITS-1))); n /= __NFDBITS; - open_fds = current->files->open_fds.fds_bits+n; + open_fds = current->files->open_fds->fds_bits+n; max = 0; if (set) { set &= BITS(fds, n); @@ -271,8 +271,8 @@ if (n < 0) goto out_nofds; - if (n > KFDS_NR) - n = KFDS_NR; + if (n > current->files->max_fdset) + n = current->files->max_fdset; /* * We need 6 bitmaps (in/out/ex for both incoming and outgoing), @@ -383,7 +383,7 @@ lock_kernel(); /* Do a sanity check on nfds ... */ err = -EINVAL; - if (nfds > NR_OPEN) + if (nfds > current->files->max_fds) goto out; if (timeout) { diff -urN 2.2.11/include/asm-alpha/resource.h 2.2.11-large-fd-set/include/asm-alpha/resource.h --- 2.2.11/include/asm-alpha/resource.h Mon Jan 18 02:27:22 1999 +++ 2.2.11-large-fd-set/include/asm-alpha/resource.h Thu Aug 12 03:16:29 1999 @@ -28,7 +28,7 @@ {_STK_LIM, _STK_LIM}, /* RLIMIT_STACK */ \ { 0, LONG_MAX}, /* RLIMIT_CORE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_RSS */ \ - { NR_OPEN, NR_OPEN}, /* RLIMIT_NOFILE */ \ + {INR_OPEN, INR_OPEN}, /* RLIMIT_NOFILE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, /* RLIMIT_NPROC */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_MEMLOCK */ \ diff -urN 2.2.11/include/asm-arm/resource.h 2.2.11-large-fd-set/include/asm-arm/resource.h --- 2.2.11/include/asm-arm/resource.h Mon Jan 18 02:27:40 1999 +++ 2.2.11-large-fd-set/include/asm-arm/resource.h Thu Aug 12 03:16:29 1999 @@ -29,7 +29,7 @@ { 0, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ { MAX_TASKS_PER_USER, MAX_TASKS_PER_USER }, \ - { NR_OPEN, NR_OPEN }, \ + { INR_OPEN, INR_OPEN }, \ { LONG_MAX, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ } diff -urN 2.2.11/include/asm-i386/resource.h 2.2.11-large-fd-set/include/asm-i386/resource.h --- 2.2.11/include/asm-i386/resource.h Mon Jan 18 02:27:15 1999 +++ 2.2.11-large-fd-set/include/asm-i386/resource.h Thu Aug 12 03:16:29 1999 @@ -29,7 +29,7 @@ { 0, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ { MAX_TASKS_PER_USER, MAX_TASKS_PER_USER }, \ - { NR_OPEN, NR_OPEN }, \ + { INR_OPEN, INR_OPEN }, \ { LONG_MAX, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ } diff -urN 2.2.11/include/asm-m68k/resource.h 2.2.11-large-fd-set/include/asm-m68k/resource.h --- 2.2.11/include/asm-m68k/resource.h Mon Jan 18 02:27:23 1999 +++ 2.2.11-large-fd-set/include/asm-m68k/resource.h Thu Aug 12 03:16:29 1999 @@ -29,7 +29,7 @@ { 0, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ - {NR_OPEN, NR_OPEN}, \ + {INR_OPEN, INR_OPEN}, \ {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX} \ } diff -urN 2.2.11/include/asm-mips/resource.h 2.2.11-large-fd-set/include/asm-mips/resource.h --- 2.2.11/include/asm-mips/resource.h Thu Aug 12 02:32:33 1999 +++ 2.2.11-large-fd-set/include/asm-mips/resource.h Thu Aug 12 03:17:52 1999 @@ -34,7 +34,7 @@ {LONG_MAX, LONG_MAX}, \ {_STK_LIM, _STK_LIM}, \ { 0, LONG_MAX}, \ - {NR_OPEN, NR_OPEN}, \ + {INR_OPEN, INR_OPEN}, \ {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ diff -urN 2.2.11/include/asm-ppc/resource.h 2.2.11-large-fd-set/include/asm-ppc/resource.h --- 2.2.11/include/asm-ppc/resource.h Mon Jan 18 02:27:33 1999 +++ 2.2.11-large-fd-set/include/asm-ppc/resource.h Thu Aug 12 03:16:29 1999 @@ -25,7 +25,7 @@ { 0, LONG_MAX}, /* RLIMIT_CORE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_RSS */ \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, /* RLIMIT_NPROC */ \ - { NR_OPEN, NR_OPEN}, /* RLIMIT_NOFILE */ \ + {INR_OPEN, INR_OPEN}, /* RLIMIT_NOFILE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_MEMLOCK */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \ } diff -urN 2.2.11/include/asm-sparc/resource.h 2.2.11-large-fd-set/include/asm-sparc/resource.h --- 2.2.11/include/asm-sparc/resource.h Wed Mar 24 01:50:57 1999 +++ 2.2.11-large-fd-set/include/asm-sparc/resource.h Thu Aug 12 03:16:29 1999 @@ -31,7 +31,7 @@ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, {_STK_LIM, LONG_MAX}, \ { 0, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ - {NR_OPEN, NR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ + {INR_OPEN, INR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX} \ } diff -urN 2.2.11/include/asm-sparc64/resource.h 2.2.11-large-fd-set/include/asm-sparc64/resource.h --- 2.2.11/include/asm-sparc64/resource.h Wed Mar 24 01:51:21 1999 +++ 2.2.11-large-fd-set/include/asm-sparc64/resource.h Thu Aug 12 03:16:29 1999 @@ -30,7 +30,7 @@ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, {_STK_LIM, LONG_MAX}, \ { 0, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ - {NR_OPEN, NR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ + {INR_OPEN, INR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \ {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX} \ } diff -urN 2.2.11/include/linux/fs.h 2.2.11-large-fd-set/include/linux/fs.h --- 2.2.11/include/linux/fs.h Thu Aug 12 02:32:33 1999 +++ 2.2.11-large-fd-set/include/linux/fs.h Thu Aug 12 03:16:29 1999 @@ -27,9 +27,10 @@ /* - * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix - * that later. Anyway, now the file code is no longer dependent - * on bitmaps in unsigned longs, but uses the new fd_set structure.. + * It's silly to have NR_OPEN bigger than NR_FILE, but you can change + * the file limit at runtime and only root can increase the per-process + * nr_file rlimit, so it's safe to set up a ridiculously high absolute + * upper limit on files-per-process. * * Some programs (notably those using select()) may have to be * recompiled to take full advantage of the new limits.. @@ -37,7 +38,8 @@ /* Fixed constants first: */ #undef NR_OPEN -#define NR_OPEN 1024 +#define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */ +#define INR_OPEN 1024 /* Initial setting for nfile rlimits */ #define BLOCK_SIZE_BITS 10 #define BLOCK_SIZE (1<pid, nr); +#endif + + if (nr >= files->max_fdset) { + expand = 1; + if ((err = expand_fdset(files, nr))) + goto out; + } + if (nr >= files->max_fds) { + expand = 1; + if ((err = expand_fd_array(files, nr))) + goto out; + } + err = expand; + out: +#ifdef FDSET_DEBUG + if (err) + printk (KERN_ERR __FUNCTION__ " %d: return %d\n", current->pid, err); +#endif + return err; +} extern int copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); extern void flush_thread(void); diff -urN 2.2.11/kernel/exit.c 2.2.11-large-fd-set/kernel/exit.c --- 2.2.11/kernel/exit.c Tue Jul 13 00:33:10 1999 +++ 2.2.11-large-fd-set/kernel/exit.c Thu Aug 12 03:16:29 1999 @@ -159,11 +159,11 @@ j = 0; for (;;) { - unsigned long set = files->open_fds.fds_bits[j]; + unsigned long set; i = j * __NFDBITS; - j++; - if (i >= files->max_fds) + if (i >= files->max_fdset || i >= files->max_fds) break; + set = files->open_fds->fds_bits[j++]; while (set) { if (set & 1) { struct file * file = files->fd[i]; @@ -189,12 +189,14 @@ if (atomic_dec_and_test(&files->count)) { close_files(files); /* - * Free the fd array as appropriate ... + * Free the fd and fdset arrays if we expanded them. */ - if (NR_OPEN * sizeof(struct file *) == PAGE_SIZE) - free_page((unsigned long) files->fd); - else - kfree(files->fd); + if (files->fd != &files->fd_array[0]) + free_fd_array(files->fd, files->max_fds); + if (files->max_fdset > __FD_SETSIZE) { + free_fdset(files->open_fds, files->max_fdset); + free_fdset(files->close_on_exec, files->max_fdset); + } kmem_cache_free(files_cachep, files); } } diff -urN 2.2.11/kernel/fork.c 2.2.11-large-fd-set/kernel/fork.c --- 2.2.11/kernel/fork.c Thu Aug 12 02:32:33 1999 +++ 2.2.11-large-fd-set/kernel/fork.c Thu Aug 12 03:16:29 1999 @@ -414,32 +414,11 @@ return 0; } -/* - * Copy a fd_set and compute the maximum fd it contains. - */ -static inline int __copy_fdset(unsigned long *d, unsigned long *src) -{ - int i; - unsigned long *p = src; - unsigned long *max = src; - - for (i = __FDSET_LONGS; i; --i) { - if ((*d++ = *p++) != 0) - max = p; - } - return (max - src)*sizeof(long)*8; -} - -static inline int copy_fdset(fd_set *dst, fd_set *src) -{ - return __copy_fdset(dst->fds_bits, src->fds_bits); -} - static int copy_files(unsigned long clone_flags, struct task_struct * tsk) { struct files_struct *oldf, *newf; struct file **old_fds, **new_fds; - int size, i, error = 0; + int nfds, size, i, error = 0; /* * A background process may not have any files ... @@ -459,25 +438,74 @@ if (!newf) goto out; - /* - * Allocate the fd array, using get_free_page() if possible. - * Eventually we want to make the array size variable ... - */ - size = NR_OPEN * sizeof(struct file *); - if (size == PAGE_SIZE) - new_fds = (struct file **) __get_free_page(GFP_KERNEL); - else - new_fds = (struct file **) kmalloc(size, GFP_KERNEL); - if (!new_fds) - goto out_release; + size = oldf->max_fdset; + nfds = NR_OPEN_DEFAULT; +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ " size = %d/%d\n", + oldf->max_fds, oldf->max_fdset); +#endif atomic_set(&newf->count, 1); - newf->max_fds = NR_OPEN; - newf->fd = new_fds; - newf->close_on_exec = oldf->close_on_exec; - i = copy_fdset(&newf->open_fds, &oldf->open_fds); + newf->next_fd = 0; + newf->max_fds = NR_OPEN_DEFAULT; + newf->max_fdset = __FD_SETSIZE; + newf->close_on_exec = &newf->close_on_exec_init; + newf->open_fds = &newf->open_fds_init; + newf->fd = &newf->fd_array[0]; + + /* Even if the old fdset gets grown here, we'll only copy "size" fds */ + if (size > __FD_SETSIZE) { + newf->max_fdset = 0; + error = expand_fdset(newf, size); + if (error) + goto out_release; + } + memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, size/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; + int start = size / (8 * sizeof(unsigned long)); + + memset(&newf->open_fds->fds_bits[start], 0, left); + memset(&newf->close_on_exec->fds_bits[start], 0, left); + } + + /* Find the last open fd */ + for (i = size/(8*sizeof(long)); i > 0; ) { + if (newf->open_fds->fds_bits[--i]) + break; + } + i = (i+1) * 8 * sizeof(long); + +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ " first-free = %d/%d\n", i, size); +#endif + + /* Do a sanity check ... */ + if (i > oldf->max_fds) + printk(KERN_ERR + "copy_files: pid %d, open files %d exceeds max %d!\n", + current->pid, i, oldf->max_fds); + + /* + * Check whether we need to allocate a larger fd array. + * Note: we're not a clone task, so the open count won't + * change. + */ + if (i > NR_OPEN_DEFAULT) { + newf->max_fds = 0; + error = expand_fd_array(newf, i); + if (error) + goto out_release; + nfds = newf->max_fds; + } + + /* compute the remainder to be cleared */ + size = (nfds - i) * sizeof(struct file *); old_fds = oldf->fd; + new_fds = newf->fd; + for (; i != 0; i--) { struct file *f = *old_fds++; *new_fds = f; @@ -486,14 +514,20 @@ new_fds++; } /* This is long word aligned thus could use a optimized version */ - memset(new_fds, 0, (char *)newf->fd + size - (char *)new_fds); + memset(new_fds, 0, size); tsk->files = newf; error = 0; out: +#ifdef FDSET_DEBUG + if (error) + printk (KERN_ERR "copy_files: return %d\n", error); +#endif return error; out_release: + free_fdset (newf->close_on_exec, newf->max_fdset); + free_fdset (newf->open_fds, newf->max_fdset); kmem_cache_free(files_cachep, newf); goto out; }