--- 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<<BLOCK_SIZE_BITS)
@@ -702,7 +704,11 @@
#define __getname() ((char *) __get_free_page(GFP_KERNEL))
#define putname(name) free_page((unsigned long)(name))
+#if 1
extern void kill_fasync(struct fasync_struct *fa, int sig);
+#else
+extern void kill_fasync(struct fasync_struct *fa, int sig, int band);
+#endif
extern int register_blkdev(unsigned int, const char *, struct file_operations *);
extern int unregister_blkdev(unsigned int major, const char * name);
extern int blkdev_open(struct inode * inode, struct file * filp);
--- include/linux/limits.h.~1~ Tue Dec 2 21:44:40 1997
+++ include/linux/limits.h Thu May 27 03:25:49 1999
@@ -1,7 +1,7 @@
#ifndef _LINUX_LIMITS_H
#define _LINUX_LIMITS_H
-#define NR_OPEN 1024
+#define NR_OPEN 1024
#define NGROUPS_MAX 32 /* supplemental group IDs are available */
#define ARG_MAX 131072 /* # bytes of args + environ for exec() */
--- include/linux/sched.h.~1~ Wed May 26 23:57:51 1999
+++ include/linux/sched.h Thu May 27 03:25:49 1999
@@ -124,22 +124,38 @@
asmlinkage void schedule(void);
/*
+ * The default fd array needs to be at least BITS_PER_LONG,
+ * as this is the granularity returned by copy_fdset().
+ */
+#define NR_OPEN_DEFAULT BITS_PER_LONG
+
+/*
* Open file table structure
*/
struct files_struct {
atomic_t count;
int max_fds;
+ int max_fdset;
+ int next_fd;
struct file ** fd; /* current fd array */
- fd_set close_on_exec;
- fd_set open_fds;
+ fd_set *close_on_exec;
+ fd_set *open_fds;
+ fd_set close_on_exec_init;
+ fd_set open_fds_init;
+ struct file * fd_array[NR_OPEN_DEFAULT];
};
#define INIT_FILES { \
ATOMIC_INIT(1), \
- NR_OPEN, \
- &init_fd_array[0], \
+ NR_OPEN_DEFAULT, \
+ __FD_SETSIZE, \
+ 0, \
+ &init_files.fd_array[0], \
+ &init_files.close_on_exec_init, \
+ &init_files.open_fds_init, \
{ { 0, } }, \
- { { 0, } } \
+ { { 0, } }, \
+ { NULL, } \
}
struct fs_struct {
@@ -617,6 +633,45 @@
extern void mmput(struct mm_struct *);
/* Remove the current tasks stale references to the old mm_struct */
extern void mm_release(void);
+
+/*
+ * Routines for handling the fd arrays
+ */
+extern struct file ** alloc_fd_array(int);
+extern int expand_fd_array(struct files_struct *, int nr);
+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);
+
+/* Expand files. Return <0 on error; 0 nothing done; 1 files expanded,
+ * we may have blocked. */
+static inline int expand_files(struct files_struct *files, int nr)
+{
+ int err, expand = 0;
+#ifdef FDSET_DEBUG
+ printk (KERN_ERR __FUNCTION__ " %d: nr = %d\n", current->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;
}