--- arch/alpha/kernel/process.c.~1~ Wed May 12 15:54:11 1999 +++ arch/alpha/kernel/process.c Thu May 27 03:25:47 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; --- arch/i386/kernel/init_task.c.~1~ Sun Sep 13 20:16:22 1998 +++ arch/i386/kernel/init_task.c Thu May 27 03:25:47 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; --- arch/m68k/kernel/process.c.~1~ Wed May 12 15:54:13 1999 +++ arch/m68k/kernel/process.c Thu May 27 03:25:47 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; --- arch/mips/kernel/init_task.c.~1~ Fri May 8 08:13:23 1998 +++ arch/mips/kernel/init_task.c Thu May 27 03:25:47 1999 @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * 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; --- arch/ppc/kernel/process.c.~1~ Wed May 12 15:54:15 1999 +++ arch/ppc/kernel/process.c Thu May 27 03:25:48 1999 @@ -48,7 +48,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; --- arch/sparc/kernel/init_task.c.~1~ Tue Oct 27 17:52:20 1998 +++ arch/sparc/kernel/init_task.c Thu May 27 03:25:48 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; --- arch/sparc64/kernel/init_task.c.~1~ Wed Apr 15 01:44:20 1998 +++ arch/sparc64/kernel/init_task.c Thu May 27 03:25:48 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; --- arch/sparc64/solaris/timod.c.~1~ Wed Apr 15 01:44:21 1998 +++ arch/sparc64/solaris/timod.c Thu May 27 03:25:48 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; --- fs/Makefile.~1~ Mon Aug 31 21:01:35 1998 +++ fs/Makefile Thu May 27 03:25:48 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 \ --- fs/exec.c.~1~ Wed May 12 15:54:22 1999 +++ fs/exec.c Thu May 27 03:25:48 1999 @@ -478,10 +478,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) --- fs/fcntl.c.~1~ Fri Nov 13 18:07:26 1998 +++ fs/fcntl.c Thu May 27 03:25:48 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; } @@ -111,19 +152,20 @@ filp = fget(fd); if (!filp) goto out; + err = 0; switch (cmd) { case F_DUPFD: 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; @@ -151,7 +193,6 @@ err = filp->f_owner.pid; break; case F_SETOWN: - err = 0; filp->f_owner.pid = arg; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; @@ -171,10 +212,9 @@ break; default: /* sockets need a few special fcntls. */ + err = -EINVAL; if (S_ISSOCK (filp->f_dentry->d_inode->i_mode)) err = sock_fcntl (filp, cmd, arg); - else - err = -EINVAL; break; } fput(filp); --- fs/ioctl.c.~1~ Tue Apr 20 22:33:24 1999 +++ fs/ioctl.c Thu May 27 03:25:48 1999 @@ -52,11 +52,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: --- fs/open.c.~1~ Tue Apr 20 22:33:36 1999 +++ fs/open.c Thu May 27 05:56:36 1999 @@ -691,9 +691,13 @@ { 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,7 +847,7 @@ struct files_struct * files = current->files; files->fd[fd] = NULL; put_unused_fd(fd); - FD_CLR(fd, &files->close_on_exec); + FD_CLR(fd, files->close_on_exec); error = filp_close(filp, files); } unlock_kernel(); --- fs/proc/array.c.~1~ Wed May 26 23:55:25 1999 +++ fs/proc/array.c Thu May 27 03:25:48 1999 @@ -725,11 +725,13 @@ "PPid:\t%d\n" "Uid:\t%d\t%d\t%d\t%d\n" "Gid:\t%d\t%d\t%d\t%d\n" + "FDSize:\t%d\n" "Groups:\t", get_task_state(p), p->pid, p->p_pptr->pid, p->uid, p->euid, p->suid, p->fsuid, - p->gid, p->egid, p->sgid, p->fsgid); + p->gid, p->egid, p->sgid, p->fsgid, + p->files ? p->files->max_fds : 0); for (g = 0; g < p->ngroups; g++) buffer += sprintf(buffer, "%d ", p->groups[g]); --- fs/select.c.~1~ Tue Jan 19 18:43:08 1999 +++ fs/select.c Thu May 27 03:25:48 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); @@ -379,7 +379,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) { --- include/asm-alpha/resource.h.~1~ Fri Aug 23 13:30:14 1996 +++ include/asm-alpha/resource.h Thu May 27 03:25:48 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 */ \ --- include/asm-arm/resource.h.~1~ Wed Jan 21 00:39:43 1998 +++ include/asm-arm/resource.h Thu May 27 03:25:48 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 }, \ } --- include/asm-i386/resource.h.~1~ Thu Nov 19 05:06:56 1998 +++ include/asm-i386/resource.h Thu May 27 03:25:48 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 }, \ } --- include/asm-m68k/resource.h.~1~ Tue Jan 5 19:20:43 1999 +++ include/asm-m68k/resource.h Thu May 27 03:25:48 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} \ } --- include/asm-mips/resource.h.~1~ Thu Jun 26 20:33:40 1997 +++ include/asm-mips/resource.h Thu May 27 03:25:48 1999 @@ -35,7 +35,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}, \ --- include/asm-ppc/resource.h.~1~ Mon Dec 21 16:37:24 1998 +++ include/asm-ppc/resource.h Thu May 27 03:25:48 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 */ \ } --- include/asm-sparc/resource.h.~1~ Tue Apr 20 22:33:11 1999 +++ include/asm-sparc/resource.h Thu May 27 03:25:49 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} \ } --- include/asm-sparc64/resource.h.~1~ Tue Apr 20 22:33:12 1999 +++ include/asm-sparc64/resource.h Thu May 27 03:25:49 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} \ } --- include/linux/fs.h.~1~ Wed May 26 23:57:51 1999 +++ include/linux/fs.h Thu May 27 03:25:49 1999 @@ -27,17 +27,19 @@ /* - * 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.. + * recompiled to take full advantage of the new limits.. */ /* 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); --- kernel/exit.c.~1~ Wed May 12 15:54:26 1999 +++ kernel/exit.c Thu May 27 03:25:49 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); } } --- kernel/fork.c.~1~ Tue Apr 20 22:33:37 1999 +++ kernel/fork.c Thu May 27 03:25:49 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; }