PATCH: combo 30,000fd, 2Gig swap, dynamic superblock, async I/O patch

Alan Cox (alan@lxorguk.ukuu.org.uk)
Mon, 27 Jul 98 15:41 BST


This is the stuff I've been using and other folks have been beating on for
a while. Its a combination of

Stephen Tweedies 2Gig swap support (and the 127 reference fix)
Stephen Tweedies asynchronous I/O code
My patches to the above to fix all the bus mice
Bill Hawes 30,000 file handle support patch
[unknown]'s dentry optimisation/fragmentation reducer - putting short names
in the entry itself
Stephen Tweedies dynamic support blocks

I've not split this up because I think Im more likely to break it trying to
split them from each other than just from the other diffs in my tree.

I'd appreciate it if folks can test this a bit to make sure I've split it
down ok from my main tree before I send a final edition of the patch to
Linus

Alan

diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- linux.vanilla/drivers/char/adbmouse.c Mon Jul 6 16:18:51 1998
+++ linux/drivers/char/adbmouse.c Sun Jul 26 00:42:37 1998
@@ -144,11 +144,11 @@

}

-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;

- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -156,7 +156,7 @@

static int release_mouse(struct inode *inode, struct file *file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;

diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c
--- linux.vanilla/drivers/char/amigamouse.c Sat Mar 21 19:06:17 1998
+++ linux/drivers/char/amigamouse.c Sun Jul 26 00:42:37 1998
@@ -159,10 +159,10 @@
AMI_MSE_INT_ON();
}

-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -174,7 +174,7 @@

static int release_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
free_irq(IRQ_AMIGA_VERTB, mouse_interrupt);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c
--- linux.vanilla/drivers/char/atarimouse.c Fri Feb 27 03:58:52 1998
+++ linux/drivers/char/atarimouse.c Sun Jul 26 00:42:37 1998
@@ -54,10 +54,10 @@
/* ikbd_mouse_rel_pos(); */
}

-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -65,7 +65,7 @@

static int release_mouse(struct inode *inode, struct file *file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
ikbd_mouse_disable();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c
--- linux.vanilla/drivers/char/atixlmouse.c Fri Feb 27 03:59:02 1998
+++ linux/drivers/char/atixlmouse.c Sun Jul 26 00:42:37 1998
@@ -95,10 +95,10 @@
ATIXL_MSE_ENABLE_UPDATE();
}

-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &mouse.fasync);
+ retval = fasync_helper(fd, filp, on, &mouse.fasync);
if (retval < 0)
return retval;
return 0;
@@ -106,7 +106,7 @@

static int release_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- linux.vanilla/drivers/char/busmouse.c Fri Feb 27 03:59:20 1998
+++ linux/drivers/char/busmouse.c Sun Jul 26 00:42:37 1998
@@ -106,11 +106,11 @@
MSE_INT_ON();
}

-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;

- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -122,7 +122,7 @@

static int close_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
MSE_INT_OFF();
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/macmouse.c linux/drivers/char/macmouse.c
--- linux.vanilla/drivers/char/macmouse.c Sat Mar 21 19:06:17 1998
+++ linux/drivers/char/macmouse.c Sun Jul 26 00:42:38 1998
@@ -150,11 +150,11 @@

}

-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;

- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -162,7 +162,7 @@

static int release_mouse(struct inode *inode, struct file *file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;

diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c
--- linux.vanilla/drivers/char/msbusmouse.c Fri Feb 27 03:59:43 1998
+++ linux/drivers/char/msbusmouse.c Sun Jul 26 00:42:38 1998
@@ -89,11 +89,11 @@
}
}

-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;

- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -101,7 +101,7 @@

static int release_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
MS_MSE_INT_OFF();

diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c
--- linux.vanilla/drivers/char/pc110pad.c Fri Feb 27 03:59:56 1998
+++ linux/drivers/char/pc110pad.c Sun Jul 26 00:42:38 1998
@@ -474,11 +474,11 @@



-static int fasync_pad(struct file *filp, int on)
+static int fasync_pad(int fd, struct file *filp, int on)
{
int retval;

- retval = fasync_helper(filp, on, &asyncptr);
+ retval = fasync_helper(fd, filp, on, &asyncptr);
if (retval < 0)
return retval;
return 0;
@@ -490,7 +490,7 @@
*/
static int close_pad(struct inode * inode, struct file * file)
{
- fasync_pad(file, 0);
+ fasync_pad(-1, file, 0);
if (--active)
return 0;
outb(0x30, current_params.io+2); /* switch off digitiser */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/drivers/char/psaux.c linux/drivers/char/psaux.c
--- linux.vanilla/drivers/char/psaux.c Fri Feb 27 03:54:02 1998
+++ linux/drivers/char/psaux.c Sun Jul 26 00:42:38 1998
@@ -105,11 +105,11 @@
return queue->head == queue->tail;
}

-static int fasync_aux(struct file *filp, int on)
+static int fasync_aux(int fd, struct file *filp, int on)
{
int retval;

- retval = fasync_helper(filp, on, &queue->fasync);
+ retval = fasync_helper(fd, filp, on, &queue->fasync);
if (retval < 0)
return retval;
return 0;
@@ -242,7 +242,7 @@

static int release_aux(struct inode * inode, struct file * file)
{
- fasync_aux(file, 0);
+ fasync_aux(-1, file, 0);
if (--aux_count)
return 0;
aux_start_atomic();
@@ -390,7 +390,7 @@
{
unsigned char status;

- fasync_aux(file, 0);
+ fasync_aux(-1, file, 0);
if (!--qp_count) {
if (!poll_qp_status())
printk("Warning: Mouse device busy in release_qp()\n");

diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/dcache.c linux/fs/dcache.c
--- linux.vanilla/fs/dcache.c Sat Jul 25 23:36:27 1998
+++ linux/fs/dcache.c Sun Jul 26 01:05:01 1998
@@ -17,6 +17,7 @@
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/init.h>

#include <asm/uaccess.h>
@@ -29,6 +30,8 @@
extern int inodes_stat[];
#define nr_inodes (inodes_stat[0])

+kmem_cache_t *dentry_cache;
+
/*
* This is the single most critical data structure when it comes
* to the dcache: the hashtable for lookups. Somebody should try
@@ -56,8 +59,9 @@
{
if (dentry->d_op && dentry->d_op->d_release)
dentry->d_op->d_release(dentry);
- kfree(dentry->d_name.name);
- kfree(dentry);
+ if (dname_external(dentry))
+ kfree(dentry->d_name.name);
+ kmem_cache_free(dentry_cache, dentry);
}

/*
@@ -498,15 +502,18 @@
free_inode_memory(8);
}

- dentry = kmalloc(sizeof(struct dentry), GFP_KERNEL);
+ dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);
if (!dentry)
return NULL;

- str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL);
- if (!str) {
- kfree(dentry);
- return NULL;
- }
+ if (name->len > DNAME_INLINE_LEN-1) {
+ str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL);
+ if (!str) {
+ kmem_cache_free(dentry_cache, dentry);
+ return NULL;
+ }
+ } else
+ str = dentry->d_iname;

memcpy(str, name->name, name->len);
str[name->len] = 0;
@@ -636,9 +643,10 @@
* Special case: local mount points don't live in
* the hashes, so we search the super blocks.
*/
- struct super_block *sb = super_blocks + 0;
+ struct super_block *sb = sb_entry(super_blocks.next);

- for (; sb < super_blocks + NR_SUPER; sb++) {
+ for (; sb != sb_entry(&super_blocks);
+ sb = sb_entry(sb->s_list.next)) {
if (!sb->s_dev)
continue;
if (sb->s_root == dentry)
@@ -691,6 +699,15 @@
__typeof__ (x) __tmp = x; \
x = y; y = __tmp; } while (0)

+void memswap(char *a, char *b, int len)
+{
+ while (len-- > 0) {
+ do_switch(*a, *b);
+ a++;
+ b++;
+ }
+}
+
/*
* We cannibalize "target" when moving dentry on top of it,
* because it's going to be thrown away anyway. We could be more
@@ -723,8 +740,17 @@
list_del(&target->d_child);

/* Switch the parents and the names.. */
- do_switch(dentry->d_parent, target->d_parent);
+
+ /* Could do a longword copy when it is sufficiently aligned,
+ * but I'm not sure if it is worth the optimization. */
+ memswap(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN);
do_switch(dentry->d_name.name, target->d_name.name);
+ if (target->d_name.name == dentry->d_iname)
+ target->d_name.name = target->d_iname;
+ if (dentry->d_name.name == target->d_iname)
+ dentry->d_name.name = dentry->d_iname;
+
+ do_switch(dentry->d_parent, target->d_parent);
do_switch(dentry->d_name.len, target->d_name.len);
do_switch(dentry->d_name.hash, target->d_name.hash);
list_add(&target->d_child, &target->d_parent->d_subdirs);
@@ -884,6 +910,22 @@
{
int i;
struct list_head *d = dentry_hashtable;
+
+ /*
+ * A constructor could be added for stable state like the lists,
+ * but it is probably not worth it because of the cache nature
+ * of the dcache.
+ * If fragmentation is too bad then the SLAB_HWCACHE_ALIGN
+ * flag could be removed here, to hint to the allocator that
+ * it should not try to get multiple page regions.
+ */
+ dentry_cache = kmem_cache_create("dentry_cache",
+ sizeof(struct dentry),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!dentry_cache)
+ panic("Cannot create dentry cache");

i = D_HASHSIZE;
do {
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/fcntl.c linux/fs/fcntl.c
--- linux.vanilla/fs/fcntl.c Mon Jul 6 16:36:28 1998
+++ linux/fs/fcntl.c Sun Jul 26 00:42:39 1998
@@ -20,14 +20,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 in_arg)
{
struct files_struct * files = current->files;
struct file * file;
+ unsigned int arg;
int error;

error = -EINVAL;
- if (arg >= NR_OPEN)
+ if (in_arg >= NR_OPEN)
goto out;

error = -EBADF;
@@ -35,10 +36,21 @@
if (!file)
goto out;

+repeat:
error = -EMFILE;
- arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg);
+ arg = find_next_zero_bit(&files->open_fds, NR_OPEN, in_arg);
if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur)
goto out_putf;
+ /*
+ * Check whether we need to expand the fd array.
+ */
+ if (arg >= files->max_fds) {
+ error = expand_fd_array(files);
+ if (!error)
+ goto repeat;
+ goto out_putf;
+ }
+
FD_SET(arg, &files->open_fds);
FD_CLR(arg, &files->close_on_exec);
fd_install(arg, file);
@@ -58,12 +70,12 @@
lock_kernel();
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 */

sys_close(newfd);
err = dupfd(oldfd, newfd);
@@ -84,7 +96,7 @@

#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC)

-static int setfl(struct file * filp, unsigned long arg)
+static int setfl(int fd, struct file * filp, unsigned long arg)
{
struct inode * inode = filp->f_dentry->d_inode;

@@ -98,7 +110,7 @@
/* Did FASYNC state change? */
if ((arg ^ filp->f_flags) & FASYNC) {
if (filp->f_op->fasync)
- filp->f_op->fasync(filp, (arg & FASYNC) != 0);
+ filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
}

/* required for strict SunOS emulation */
@@ -119,6 +131,7 @@
filp = fget(fd);
if (!filp)
goto out;
+
err = 0;
switch (cmd) {
case F_DUPFD:
@@ -137,7 +150,7 @@
err = filp->f_flags;
break;
case F_SETFL:
- err = setfl(filp, arg);
+ err = setfl(fd, filp, arg);
break;
case F_GETLK:
err = fcntl_getlk(fd, (struct flock *) arg);
@@ -159,19 +172,28 @@
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;
if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
err = sock_fcntl (filp, F_SETOWN, arg);
break;
+ case F_GETSIG:
+ err = filp->f_owner.signum;
+ break;
+ case F_SETSIG:
+ if (arg <= 0 || arg > _NSIG) {
+ err = -EINVAL;
+ break;
+ }
+ err = 0;
+ filp->f_owner.signum = arg;
+ 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);
@@ -180,10 +202,13 @@
return err;
}

-static void send_sigio(int pid, uid_t uid, uid_t euid)
+static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
{
struct task_struct * p;
-
+ int pid = fown->pid;
+ uid_t uid = fown->uid;
+ uid_t euid = fown->euid;
+
read_lock(&tasklist_lock);
for_each_task(p) {
int match = p->pid;
@@ -195,7 +220,25 @@
(euid ^ p->suid) && (euid ^ p->uid) &&
(uid ^ p->suid) && (uid ^ p->uid))
continue;
- send_sig(SIGIO, p, 1);
+ if (!fown->signum)
+ send_sig(SIGIO, p, 1);
+ else {
+ /* Queue a rt signal with the appropriate fd as its
+ value. We use SI_SIGIO as the source, not
+ SI_KERNEL, since kernel signals always get
+ delivered even if we can't queue. Failure to
+ queue in this case _should_ be reported; we fall
+ back to SIGIO in that case. --sct */
+ siginfo_t si;
+ si.si_signo = fown->signum;
+ si.si_errno = 0;
+ si.si_code = SI_SIGIO;
+ si.si_pid = pid;
+ si.si_uid = uid;
+ si.si_fd = fa->fa_fd;
+ if (send_sig_info(fown->signum, &si, p))
+ send_sig(SIGIO, p, 1);
+ }
if (p->state == TASK_INTERRUPTIBLE && signal_pending(p))
wake_up_process(p);
}
@@ -213,7 +256,7 @@
}
fown = &fa->fa_file->f_owner;
if (fown->pid)
- send_sigio(fown->pid, fown->uid, fown->euid);
+ send_sigio(fown, fa);
fa = fa->fa_next;
}
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/file_table.c linux/fs/file_table.c
--- linux.vanilla/fs/file_table.c Mon Jul 6 16:16:30 1998
+++ linux/fs/file_table.c Sun Jul 26 00:42:39 1998
@@ -12,6 +12,7 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
+#include <linux/init.h>

/* SLAB cache for filp's. */
static kmem_cache_t *filp_cache;
@@ -44,8 +45,7 @@
file->f_pprev = &inuse_filps;
}

-/* N.B. This should be an __initfunc ... */
-void file_table_init(void)
+__initfunc(void file_table_init(void))
{
filp_cache = kmem_cache_create("filp", sizeof(struct file),
0,
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/inode.c linux/fs/inode.c
--- linux.vanilla/fs/inode.c Sat Jul 25 23:36:27 1998
+++ linux/fs/inode.c Sun Jul 26 00:42:39 1998
@@ -8,6 +8,7 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/dcache.h>
+#include <linux/init.h>
#include <linux/quotaops.h>

/*
@@ -177,14 +178,13 @@
*/
void sync_inodes(kdev_t dev)
{
- struct super_block * sb = super_blocks + 0;
- int i;
+ struct super_block * sb = sb_entry(super_blocks.next);

/*
* Search the super_blocks array for the device(s) to sync.
*/
spin_lock(&inode_lock);
- for (i = NR_SUPER ; i-- ; sb++) {
+ for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) {
if (!sb->s_dev)
continue;
if (dev && sb->s_dev != dev)
@@ -735,11 +735,11 @@

/*
* Initialize the hash tables and default
- * value for max inodes..
+ * value for mx inodes
*/
#define MAX_INODE (8192)

-void inode_init(void)
+__initfunc(void inode_init(void))
{
int i, max;
struct list_head *head = inode_hashtable;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/open.c linux/fs/open.c
--- linux.vanilla/fs/open.c Mon Jul 6 16:17:05 1998
+++ linux/fs/open.c Sun Jul 26 00:42:39 1998
@@ -689,6 +689,7 @@
struct files_struct * files = current->files;
int fd, error;

+repeat:
error = -EMFILE;
fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
/*
@@ -697,8 +698,15 @@
*/
if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
goto out;
-
- /* Check here for fd > files->max_fds to do dynamic expansion */
+ /*
+ * Check whether we need to expand the fd array.
+ */
+ if (fd >= files->max_fds) {
+ error = expand_fd_array(files);
+ if (!error)
+ goto repeat;
+ goto out;
+ }

FD_SET(fd, &files->open_fds);
FD_CLR(fd, &files->close_on_exec);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/fs/super.c linux/fs/super.c
--- linux.vanilla/fs/super.c Tue Jul 21 14:19:29 1998
+++ linux/fs/super.c Sun Jul 26 00:42:39 1998
@@ -68,7 +68,10 @@
/* this is initialized in init/main.c */
kdev_t ROOT_DEV;

-struct super_block super_blocks[NR_SUPER];
+int nr_super_blocks = 0;
+int max_super_blocks = NR_SUPER;
+LIST_HEAD(super_blocks);
+
static struct file_system_type *file_systems = (struct file_system_type *) NULL;
struct vfsmount *vfsmntlist = (struct vfsmount *) NULL;
static struct vfsmount *vfsmnttail = (struct vfsmount *) NULL,
@@ -446,7 +449,9 @@
{
struct super_block * sb;

- for (sb = super_blocks + 0 ; sb < super_blocks + NR_SUPER ; sb++) {
+ for (sb = sb_entry(super_blocks.next);
+ sb != sb_entry(&super_blocks);
+ sb = sb_entry(sb->s_list.next)) {
if (!sb->s_dev)
continue;
if (dev && sb->s_dev != dev)
@@ -471,15 +476,15 @@
if (!dev)
return NULL;
restart:
- s = 0+super_blocks;
- while (s < NR_SUPER+super_blocks)
+ s = sb_entry(super_blocks.next);
+ while (s != sb_entry(&super_blocks))
if (s->s_dev == dev) {
wait_on_super(s);
if (s->s_dev == dev)
return s;
goto restart;
} else
- s++;
+ s = sb_entry(s->s_list.next);
return NULL;
}

@@ -519,16 +524,28 @@
*/
static struct super_block *get_empty_super(void)
{
- struct super_block *s = 0+super_blocks;
+ struct super_block *s;

- for (; s < NR_SUPER+super_blocks; s++) {
+ for (s = sb_entry(super_blocks.next);
+ s != sb_entry(&super_blocks);
+ s = sb_entry(s->s_list.next)) {
if (s->s_dev)
continue;
if (!s->s_lock)
return s;
printk("VFS: empty superblock %p locked!\n", s);
}
- return NULL;
+ /* Need a new one... */
+ if (nr_super_blocks >= max_super_blocks)
+ return NULL;
+ s = kmalloc(sizeof(struct super_block), GFP_USER);
+ nr_super_blocks++;
+ if (s) {
+ memset(s, 0, sizeof(struct super_block));
+ INIT_LIST_HEAD(&s->s_dirty);
+ list_add (&s->s_list, super_blocks.prev);
+ }
+ return s;
}

static struct super_block * read_super(kdev_t dev,const char *name,int flags,
@@ -1102,7 +1119,7 @@
goto dput_and_out;
}

-__initfunc(static void do_mount_root(void))
+__initfunc(void mount_root(void))
{
struct file_system_type * fs_type;
struct super_block * sb;
@@ -1110,7 +1127,7 @@
struct inode * d_inode = NULL;
struct file filp;
int retval;
-
+
#ifdef CONFIG_ROOT_NFS
if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
ROOT_DEV = 0;
@@ -1197,22 +1214,6 @@
}


-__initfunc(void mount_root(void))
-{
- struct super_block * sb = super_blocks;
- int i;
-
- memset(super_blocks, 0, sizeof(super_blocks));
- /*
- * Initialize the dirty inode list headers for the super blocks
- */
- for (i = NR_SUPER ; i-- ; sb++)
- INIT_LIST_HEAD(&sb->s_dirty);
-
- do_mount_root();
-}
-
-
#ifdef CONFIG_BLK_DEV_INITRD

extern int initmem_freed;
@@ -1232,7 +1233,7 @@
return -EBUSY;
}
ROOT_DEV = new_root_dev;
- do_mount_root();
+ mount_root();
dput(old_root);
dput(old_pwd);
#if 1
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/fcntl.h linux/include/asm-alpha/fcntl.h
--- linux.vanilla/include/asm-alpha/fcntl.h Sun Sep 22 07:41:32 1996
+++ linux/include/asm-alpha/fcntl.h Sun Jul 26 00:42:39 1998
@@ -29,6 +29,8 @@

#define F_SETOWN 5 /* for sockets. */
#define F_GETOWN 6 /* for sockets. */
+#define F_SETSIG 10 /* for sockets. */
+#define F_GETSIG 11 /* for sockets. */

/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-alpha/siginfo.h linux/include/asm-alpha/siginfo.h
--- linux.vanilla/include/asm-alpha/siginfo.h Wed Dec 3 00:26:07 1997
+++ linux/include/asm-alpha/siginfo.h Sun Jul 26 00:42:39 1998
@@ -86,6 +86,7 @@
#define SI_TIMER -2 /* sent by timer expiration */
#define SI_MESGQ -3 /* sent by real time mesq state change */
#define SI_ASYNCIO -4 /* sent by AIO completion */
+#define SI_SIGIO -5 /* sent by queued SIGIO */

#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/fcntl.h linux/include/asm-arm/fcntl.h
--- linux.vanilla/include/asm-arm/fcntl.h Wed Jan 21 00:39:42 1998
+++ linux/include/asm-arm/fcntl.h Sun Jul 26 00:42:39 1998
@@ -28,6 +28,8 @@

#define F_SETOWN 8 /* for sockets. */
#define F_GETOWN 9 /* for sockets. */
+#define F_SETSIG 10 /* for sockets. */
+#define F_GETSIG 11 /* for sockets. */

/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-arm/siginfo.h linux/include/asm-arm/siginfo.h
--- linux.vanilla/include/asm-arm/siginfo.h Wed Jan 21 00:39:43 1998
+++ linux/include/asm-arm/siginfo.h Sun Jul 26 00:42:39 1998
@@ -86,6 +86,7 @@
#define SI_TIMER -2 /* sent by timer expiration */
#define SI_MESGQ -3 /* sent by real time mesq state change */
#define SI_ASYNCIO -4 /* sent by AIO completion */
+#define SI_SIGIO -5 /* sent by queued SIGIO */

#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/fcntl.h linux/include/asm-i386/fcntl.h
--- linux.vanilla/include/asm-i386/fcntl.h Sun Sep 22 07:41:32 1996
+++ linux/include/asm-i386/fcntl.h Sun Jul 26 00:42:39 1998
@@ -28,6 +28,8 @@

#define F_SETOWN 8 /* for sockets. */
#define F_GETOWN 9 /* for sockets. */
+#define F_SETSIG 10 /* for sockets. */
+#define F_GETSIG 11 /* for sockets. */

/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-i386/siginfo.h linux/include/asm-i386/siginfo.h
--- linux.vanilla/include/asm-i386/siginfo.h Thu Apr 2 02:30:30 1998
+++ linux/include/asm-i386/siginfo.h Sun Jul 26 00:48:59 1998
@@ -86,6 +86,7 @@
#define SI_TIMER -2 /* sent by timer expiration */
#define SI_MESGQ -3 /* sent by real time mesq state change */
#define SI_ASYNCIO -4 /* sent by AIO completion */
+#define SI_SIGIO -5 /* sent by queued SIGIO */

#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-m68k/fcntl.h linux/include/asm-m68k/fcntl.h
--- linux.vanilla/include/asm-m68k/fcntl.h Sun Sep 22 07:41:32 1996
+++ linux/include/asm-m68k/fcntl.h Sun Jul 26 00:42:39 1998
@@ -28,6 +28,8 @@

#define F_SETOWN 8 /* for sockets. */
#define F_GETOWN 9 /* for sockets. */
+#define F_SETSIG 10 /* for sockets. */
+#define F_GETSIG 11 /* for sockets. */

/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-m68k/siginfo.h linux/include/asm-m68k/siginfo.h
--- linux.vanilla/include/asm-m68k/siginfo.h Fri Feb 13 00:30:13 1998
+++ linux/include/asm-m68k/siginfo.h Sun Jul 26 00:42:39 1998
@@ -86,6 +86,7 @@
#define SI_TIMER -2 /* sent by timer expiration */
#define SI_MESGQ -3 /* sent by real time mesq state change */
#define SI_ASYNCIO -4 /* sent by AIO completion */
+#define SI_SIGIO -5 /* sent by queued SIGIO */

#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-mips/fcntl.h linux/include/asm-mips/fcntl.h
--- linux.vanilla/include/asm-mips/fcntl.h Thu Jun 26 20:33:39 1997
+++ linux/include/asm-mips/fcntl.h Sun Jul 26 00:42:39 1998
@@ -29,6 +29,8 @@

#define F_SETOWN 24 /* for sockets. */
#define F_GETOWN 23 /* for sockets. */
+#define F_SETSIG 10 /* for sockets. */
+#define F_GETSIG 11 /* for sockets. */

/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-mips/siginfo.h linux/include/asm-mips/siginfo.h
--- linux.vanilla/include/asm-mips/siginfo.h Tue Dec 16 20:46:14 1997
+++ linux/include/asm-mips/siginfo.h Sun Jul 26 00:42:39 1998
@@ -86,6 +86,7 @@
#define SI_TIMER -2 /* sent by timer expiration */
#define SI_MESGQ -3 /* sent by real time mesq state change */
#define SI_ASYNCIO -4 /* sent by AIO completion */
+#define SI_SIGIO -5 /* sent by queued SIGIO */

#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/fcntl.h linux/include/asm-ppc/fcntl.h
--- linux.vanilla/include/asm-ppc/fcntl.h Wed Dec 18 08:54:09 1996
+++ linux/include/asm-ppc/fcntl.h Sun Jul 26 00:42:40 1998
@@ -28,6 +28,8 @@

#define F_SETOWN 8 /* for sockets. */
#define F_GETOWN 9 /* for sockets. */
+#define F_SETSIG 10 /* for sockets. */
+#define F_GETSIG 11 /* for sockets. */

/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-ppc/siginfo.h linux/include/asm-ppc/siginfo.h
--- linux.vanilla/include/asm-ppc/siginfo.h Mon Jan 12 23:18:13 1998
+++ linux/include/asm-ppc/siginfo.h Sun Jul 26 00:42:40 1998
@@ -86,6 +86,7 @@
#define SI_TIMER -2 /* sent by timer expiration */
#define SI_MESGQ -3 /* sent by real time mesq state change */
#define SI_ASYNCIO -4 /* sent by AIO completion */
+#define SI_SIGIO -5 /* sent by queued SIGIO */

#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h
--- linux.vanilla/include/asm-sparc/fcntl.h Mon Mar 17 22:54:31 1997
+++ linux/include/asm-sparc/fcntl.h Sun Jul 26 00:42:40 1998
@@ -28,6 +28,8 @@
#define F_GETLK 7
#define F_SETLK 8
#define F_SETLKW 9
+#define F_SETSIG 10 /* for sockets. */
+#define F_GETSIG 11 /* for sockets. */

/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc/siginfo.h linux/include/asm-sparc/siginfo.h
--- linux.vanilla/include/asm-sparc/siginfo.h Mon Jan 12 23:15:54 1998
+++ linux/include/asm-sparc/siginfo.h Sun Jul 26 00:42:40 1998
@@ -90,6 +90,7 @@
#define SI_TIMER -2 /* sent by timer expiration */
#define SI_MESGQ -3 /* sent by real time mesq state change */
#define SI_ASYNCIO -4 /* sent by AIO completion */
+#define SI_SIGIO -5 /* sent by queued SIGIO */

#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc64/fcntl.h linux/include/asm-sparc64/fcntl.h
--- linux.vanilla/include/asm-sparc64/fcntl.h Thu Apr 24 03:01:28 1997
+++ linux/include/asm-sparc64/fcntl.h Sun Jul 26 00:42:40 1998
@@ -28,6 +28,8 @@
#define F_GETLK 7
#define F_SETLK 8
#define F_SETLKW 9
+#define F_SETSIG 10 /* for sockets. */
+#define F_GETSIG 11 /* for sockets. */

/* for F_[GET|SET]FL */
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/asm-sparc64/siginfo.h linux/include/asm-sparc64/siginfo.h
--- linux.vanilla/include/asm-sparc64/siginfo.h Mon Jan 12 23:15:58 1998
+++ linux/include/asm-sparc64/siginfo.h Sun Jul 26 00:42:40 1998
@@ -149,6 +149,7 @@
#define SI_TIMER -2 /* sent by timer expiration */
#define SI_MESGQ -3 /* sent by real time mesq state change */
#define SI_ASYNCIO -4 /* sent by AIO completion */
+#define SI_SIGIO -5 /* sent by queued SIGIO */

#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/dcache.h linux/include/linux/dcache.h
--- linux.vanilla/include/linux/dcache.h Sat Jul 25 23:36:28 1998
+++ linux/include/linux/dcache.h Sun Jul 26 00:42:40 1998
@@ -50,6 +50,8 @@
return end_name_hash(hash);
}

+#define DNAME_INLINE_LEN 16
+
struct dentry {
int d_count;
unsigned int d_flags;
@@ -68,6 +70,7 @@
struct super_block * d_sb; /* The root of the dentry tree */
unsigned long d_reftime; /* last time referenced */
void * d_fsdata; /* fs-specific data */
+ unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
};

struct dentry_operations {
@@ -112,6 +115,11 @@
{
list_del(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_hash);
+}
+
+static __inline__ int dname_external(struct dentry *d)
+{
+ return d->d_name.name != d->d_iname;
}

/*
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/fs.h linux/include/linux/fs.h
--- linux.vanilla/include/linux/fs.h Sat Jul 25 23:36:28 1998
+++ linux/include/linux/fs.h Sun Jul 26 00:48:59 1998
@@ -39,16 +39,17 @@
#undef NR_OPEN
#define NR_OPEN 1024

-#define NR_SUPER 64
#define BLOCK_SIZE_BITS 10
#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)

/* And dynamically-tunable limits and defaults: */
extern int max_inodes;
extern int max_files, nr_files, nr_free_files;
+extern int max_super_blocks, nr_super_blocks;

#define NR_FILE 4096 /* this can well be larger on a larger system */
#define NR_RESERVED_FILES 10 /* reserved for root */
+#define NR_SUPER 256

#define MAY_EXEC 1
#define MAY_WRITE 2
@@ -400,6 +401,7 @@
struct fown_struct {

int pid; /* pid or -pgrp where SIGIO should be sent */
uid_t uid, euid; /* uid/euid of process setting the owner */
+ int signum; /* posix.1b rt signal to be delivered on IO */
};

struct file {
@@ -509,13 +511,14 @@

struct fasync_struct {
int magic;
+ int fa_fd;
struct fasync_struct *fa_next; /* singly linked list */
struct file *fa_file;
};

#define FASYNC_MAGIC 0x4601

-extern int fasync_helper(struct file *, int, struct fasync_struct **);
+extern int fasync_helper(int, struct file *, int, struct fasync_struct **);

#include <linux/minix_fs_sb.h>
#include <linux/ext2_fs_sb.h>
@@ -532,7 +535,11 @@
#include <linux/hfs_fs_sb.h>
#include <linux/adfs_fs_sb.h>

+extern struct list_head super_blocks;
+
+#define sb_entry(list) list_entry((list), struct super_block, s_list)
struct super_block {
+ struct list_head s_list; /* Keep this first */
kdev_t s_dev;
unsigned long s_blocksize;
unsigned char s_blocksize_bits;
@@ -591,7 +598,7 @@
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *);
- int (*fasync) (struct file *, int);
+ int (*fasync) (int, struct file *, int);
int (*check_media_change) (kdev_t dev);
int (*revalidate) (kdev_t dev);
int (*lock) (struct file *, int, struct file_lock *);
@@ -704,7 +711,6 @@
extern int fs_may_mount(kdev_t dev);

extern struct file *inuse_filps;
-extern struct super_block super_blocks[NR_SUPER];

extern void refile_buffer(struct buffer_head * buf);
extern void set_writetime(struct buffer_head * buf, int flag);

diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sched.h linux/include/linux/sched.h
--- linux.vanilla/include/linux/sched.h Tue Jul 21 14:19:31 1998
+++ linux/include/linux/sched.h Sun Jul 26 00:48:59 1998
@@ -122,6 +122,7 @@

asmlinkage void schedule(void);

+#define NR_OPEN_DEFAULT BITS_PER_LONG

/*
* Open file table structure
@@ -132,6 +133,7 @@
struct file ** fd; /* current fd array */
fd_set close_on_exec;
fd_set open_fds;
+ struct file * fd_array[NR_OPEN_DEFAULT];
};

#define INIT_FILES { \
@@ -139,7 +141,8 @@
NR_OPEN, \
&init_fd_array[0], \
{ { 0, } }, \
- { { 0, } } \
+ { { 0, } }, \
+ { NULL, } \
}

struct fs_struct {
@@ -602,6 +609,13 @@
mm->count++;
}
extern void mmput(struct mm_struct *);
+
+/*
+ * Routines for handling the fd arrays
+ */
+extern struct file ** alloc_fd_array(int);
+extern int expand_fd_array(struct files_struct *);
+extern void free_fd_array(struct file **, int);

extern int copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
extern void flush_thread(void);
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/swap.h linux/include/linux/swap.h
--- linux.vanilla/include/linux/swap.h Fri Jul 17 02:12:17 1998
+++ linux/include/linux/swap.h Sun Jul 26 00:42:40 1998
@@ -7,6 +7,23 @@

#define MAX_SWAPFILES 8

+union swap_header {
+ struct
+ {
+ char reserved[PAGE_SIZE - 10];
+ char magic[10];
+ } magic;
+ struct
+ {
+ char bootbits[1024]; /* Space for disklabel etc. */
+ unsigned int version;
+ unsigned int last_page;
+ unsigned int nr_badpages;
+ unsigned int padding[125];
+ unsigned int badpages[1];
+ } info;
+};
+
#ifdef __KERNEL__

#undef DEBUG_SWAP
@@ -18,11 +35,14 @@

#define SWAP_CLUSTER_MAX 32

+#define SWAP_MAP_MAX 0x7fff
+#define SWAP_MAP_BAD 0x8000
+
struct swap_info_struct {
unsigned int flags;
kdev_t swap_device;
struct dentry * swap_file;
- unsigned char * swap_map;
+ unsigned short * swap_map;
unsigned char * swap_lockmap;
unsigned int lowest_bit;
unsigned int highest_bit;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/include/linux/sysctl.h linux/include/linux/sysctl.h
--- linux.vanilla/include/linux/sysctl.h Mon Jul 6 16:18:55 1998
+++ linux/include/linux/sysctl.h Sun Jul 26 00:42:40 1998
@@ -365,6 +365,8 @@
FS_MAXDQUOT, /* int: maximum number of dquots that can be allocated */
FS_NRFILE, /* int: current number of allocated filedescriptors */
FS_MAXFILE, /* int: maximum number of filedescriptors that can be allocated */
+ FS_NRSUPER, /* int: current number of allocated super_blocks */
+ FS_MAXSUPER, /* int: maximum number of super_blocks that can be allocated */
FS_DENTRY,
};

diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/exit.c linux/kernel/exit.c
--- linux.vanilla/kernel/exit.c Mon Jul 6 16:16:36 1998
+++ linux/kernel/exit.c Sun Jul 26 00:42:40 1998
@@ -191,12 +192,10 @@
if (!--files->count) {
close_files(files);
/*
- * Free the fd array as appropriate ...
+ * Free the fd array if we expanded it.
*/
- 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);
kmem_cache_free(files_cachep, files);
}
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/fork.c linux/kernel/fork.c
--- linux.vanilla/kernel/fork.c Fri Jul 17 02:12:18 1998
+++ linux/kernel/fork.c Sun Jul 26 00:42:40 1998
@@ -380,11 +381,74 @@
return __copy_fdset(dst->fds_bits, src->fds_bits);
}

+/*
+ * Allocate an fd array, using get_free_page() if possible.
+ */
+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 **) __get_free_page(GFP_KERNEL);
+ else
+ new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
+ if (new_fds)
+ memset((void *) new_fds, 0, size);
+ return new_fds;
+}
+
+/*
+ * Expand the fd array in the files_struct.
+ */
+int expand_fd_array(struct files_struct *files)
+{
+ struct file **new_fds;
+ int error, nfds;
+
+ error = -EMFILE;
+ if (files->max_fds >= NR_OPEN)
+ goto out;
+
+ /* Expand to the max in one step */
+ nfds = NR_OPEN;
+
+ 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) {
+ int i;
+ for (i = files->max_fds; i--; )
+ new_fds[i] = files->fd[i];
+ files->fd = new_fds;
+ files->max_fds = nfds;
+ } else {
+ /* Somebody expanded the array while we slept ... */
+ free_fd_array(new_fds, nfds);
+ }
+ error = 0;
+out:
+ return error;
+}
+
+void free_fd_array(struct file **array, int num)
+{
+ int size = num * sizeof(struct file *);
+
+ if (size == PAGE_SIZE)
+ free_page((unsigned long) array);
+ else
+ kfree(array);
+}
+
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, i, error = 0;

/*
* A background process may not have any files ...
@@ -404,24 +468,31 @@
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;
- memset((void *) new_fds, 0, size);
-
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);
+#if 1
+ /* Do a sanity check ... */
+ if (i > oldf->max_fds)
+ printk("copy_files: pid %d, open files %d exceeds max %d!\n",
+ current->pid, i, oldf->max_fds);
+#endif
+
+ /*
+ * Check whether we need to allocate a larger fd array.
+ * Note: we're not a clone task, so the open count won't
+ * change.
+ */
+ new_fds = &newf->fd_array[0];
+ nfds = NR_OPEN_DEFAULT;
+ if (i > nfds) {
+ nfds = NR_OPEN;
+ new_fds = alloc_fd_array(nfds);
+ if (!new_fds)
+ goto out_release;
+ }
+ newf->max_fds = nfds;
+ newf->fd = new_fds;

old_fds = oldf->fd;
for (; i != 0; i--) {
@@ -580,6 +654,9 @@
p->counter = current->counter;

if(p->pid) {
+ /* Forks being debugged get parked */
+ if (p->flags & PF_PTRACED)
+ send_sig(SIGSTOP, p, 1);
wake_up_process(p); /* do this last, just in case */
} else {
p->state = TASK_RUNNING;

diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/signal.c linux/kernel/signal.c
--- linux.vanilla/kernel/signal.c Sat Jul 25 23:36:29 1998
+++ linux/kernel/signal.c Sun Jul 26 00:42:41 1998
@@ -18,6 +18,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/slab.h>
+#include <linux/init.h>

#include <asm/uaccess.h>

@@ -35,8 +36,7 @@

static kmem_cache_t *signal_queue_cachep;

-void
-signals_init(void)
+__initfunc(void signals_init(void))
{
signal_queue_cachep =
kmem_cache_create("signal_queue",
@@ -50,6 +50,9 @@
* Flush all pending signals for a task.
*/

+static int nr_queued_signals;
+static int max_queued_signals = 1024;
+
void
flush_signals(struct task_struct *t)
{
@@ -64,6 +67,7 @@
while (q) {
n = q->next;
kmem_cache_free(signal_queue_cachep, q);
+ nr_queued_signals--;
q = n;
}
}
@@ -160,7 +164,8 @@
current->sigqueue_tail = pp;
*info = q->info;
kmem_cache_free(signal_queue_cachep,q);
-
+ nr_queued_signals--;
+
/* then see if this signal is still pending. */
q = *pp;
while (q) {
@@ -300,9 +305,14 @@
make sure at least one signal gets delivered and don't
pass on the info struct. */

- struct signal_queue *q = (struct signal_queue *)
- kmem_cache_alloc(signal_queue_cachep, GFP_KERNEL);
+ struct signal_queue *q = 0;

+ if (nr_queued_signals < max_queued_signals) {
+ q = (struct signal_queue *)
+ kmem_cache_alloc(signal_queue_cachep, GFP_KERNEL);
+ nr_queued_signals++;
+ }
+
if (q) {
q->next = NULL;
*t->sigqueue_tail = q;
@@ -809,9 +819,8 @@

if (k->sa.sa_handler == SIG_IGN
|| (k->sa.sa_handler == SIG_DFL
- && (sig == SIGCONT ||
- sig == SIGCHLD ||
- sig == SIGWINCH))) {
+ && (sig == SIGCONT || sig == SIGCHLD
+ || sig == SIGWINCH || sig == SIGURG))) {
/* So dequeue any that might be pending.
XXX: process-wide signals? */
if (sig >= SIGRTMIN &&
@@ -825,6 +834,7 @@
else {
*pp = q->next;
kmem_cache_free(signal_queue_cachep, q);
+ nr_queued_signals--;
}
q = *pp;
}
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/kernel/sysctl.c linux/kernel/sysctl.c
--- linux.vanilla/kernel/sysctl.c Mon Jul 6 16:18:56 1998
+++ linux/kernel/sysctl.c Sun Jul 26 00:42:41 1998
@@ -25,6 +25,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
+#include <linux/fs.h>

#include <asm/bitops.h>
#include <asm/uaccess.h>
@@ -225,6 +226,10 @@
{FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
0444, NULL, &proc_dointvec},
{FS_MAXFILE, "file-max", &max_files, sizeof(int),
+ 0644, NULL, &proc_dointvec},
+ {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
+ 0444, NULL, &proc_dointvec},
+ {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
0644, NULL, &proc_dointvec},
{FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
0444, NULL, &proc_dointvec},
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/swapfile.c linux/mm/swapfile.c
--- linux.vanilla/mm/swapfile.c Mon Jul 6 16:35:28 1998
+++ linux/mm/swapfile.c Sun Jul 26 00:42:41 1998
@@ -116,10 +116,7 @@
}
}

-/*
- * If the swap count overflows (swap_map[] == 127), the entry is considered
- * "permanent" and can't be reclaimed until the swap device is closed.
- */
+
void swap_free(unsigned long entry)
{
struct swap_info_struct * p;
@@ -147,7 +144,7 @@
p->highest_bit = offset;
if (!p->swap_map[offset])
goto bad_free;
- if (p->swap_map[offset] < 127) {
+ if (p->swap_map[offset] < SWAP_MAP_MAX) {
if (!--p->swap_map[offset])
nr_swap_pages++;
}
@@ -309,7 +306,7 @@
* Find a swap page in use and read it in.
*/
for (i = 1 , entry = 0; i < si->max ; i++) {
- if (si->swap_map[i] > 0 && si->swap_map[i] != 0x80) {
+ if (si->swap_map[i] > 0 && si->swap_map[i] != SWAP_MAP_BAD) {
entry = SWP_ENTRY(type, i);
break;
}
@@ -334,7 +331,7 @@
delete_from_swap_cache(page_map);
free_page(page);
if (si->swap_map[i] != 0) {
- if (si->swap_map[i] != 127)
+ if (si->swap_map[i] != SWAP_MAP_MAX)
printk("try_to_unuse: entry %08lx "
"not in use\n", entry);
si->swap_map[i] = 0;
@@ -425,7 +422,7 @@
p->swap_device = 0;
vfree(p->swap_map);
p->swap_map = NULL;
- free_page((long) p->swap_lockmap);
+ vfree(p->swap_lockmap);
p->swap_lockmap = NULL;
p->flags = 0;
err = 0;
@@ -458,7 +455,7 @@
usedswap = 0;
for (j = 0; j < ptr->max; ++j)
switch (ptr->swap_map[j]) {
- case 128:
+ case SWAP_MAP_BAD:
case 0:
continue;
default:
@@ -486,7 +483,12 @@
int error = -EPERM;
struct file filp;
static int least_priority = 0;
-
+ union swap_header *swap_header = 0;
+ int swap_header_version;
+ int lock_map_size = PAGE_SIZE;
+ int nr_good_pages = 0;
+ char tmp_lock_map = 0;
+
lock_kernel();
if (!capable(CAP_SYS_ADMIN))
goto out;
@@ -546,54 +548,114 @@
}
} else if (!S_ISREG(swap_dentry->d_inode->i_mode))
goto bad_swap;
- p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER);
- if (!p->swap_lockmap) {
+ swap_header = (void *) __get_free_page(GFP_USER);
+ if (!swap_header) {
printk("Unable to start swapping: out of memory :-)\n");
error = -ENOMEM;
goto bad_swap;
}
- rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) p->swap_lockmap);
- if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) {
+
+ p->swap_lockmap = &tmp_lock_map;
+ rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) swap_header);
+ p->swap_lockmap = 0;
+
+ if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10))
+ swap_header_version = 1;
+ else if (!memcmp("SWAPSPACE2",swap_header->magic.magic,10))
+ swap_header_version = 2;
+ else {
printk("Unable to find swap-space signature\n");
error = -EINVAL;
goto bad_swap;
}
- memset(p->swap_lockmap+PAGE_SIZE-10,0,10);
- j = 0;
- p->lowest_bit = 0;
- p->highest_bit = 0;
- for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
- if (test_bit(i,p->swap_lockmap)) {
- if (!p->lowest_bit)
- p->lowest_bit = i;
- p->highest_bit = i;
- p->max = i+1;
- j++;
+
+ switch (swap_header_version) {
+ case 1:
+ memset(((char *) swap_header)+PAGE_SIZE-10,0,10);
+ j = 0;
+ p->lowest_bit = 0;
+ p->highest_bit = 0;
+ for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
+ if (test_bit(i,(char *) swap_header)) {
+ if (!p->lowest_bit)
+ p->lowest_bit = i;
+ p->highest_bit = i;
+ p->max = i+1;
+ j++;
+ }
+ }
+ nr_good_pages = j;
+ p->swap_map = vmalloc(p->max * sizeof(short));
+ if (!p->swap_map) {
+ error = -ENOMEM;
+ goto bad_swap;
}
+ for (i = 1 ; i < p->max ; i++) {
+ if (test_bit(i,(char *) swap_header))
+ p->swap_map[i] = 0;
+ else
+ p->swap_map[i] = SWAP_MAP_BAD;
+ }
+ break;
+
+ case 2:
+ /* Check the swap header's sub-version and the size of
+ the swap file and bad block lists */
+ if (swap_header->info.version != 1) {
+ printk(KERN_WARNING
+ "Unable to handle swap header version %d\n",
+ swap_header->info.version);
+ error = -EINVAL;
+ goto bad_swap;
+ }
+
+ p->lowest_bit = 1;
+ p->highest_bit = swap_header->info.last_page - 1;
+ p->max = swap_header->info.last_page;
+
+ if (p->max >= 0x7fffffffL/PAGE_SIZE ||
+ (void *) &swap_header->info.badpages[swap_header->info.nr_badpages-1] >= (void *) swap_header->magic.magic) {
+ error = -EINVAL;
+ goto bad_swap;
+ }
+
+ /* OK, set up the swap map and apply the bad block list */
+ if (!(p->swap_map = vmalloc (p->max * sizeof(short)))) {
+ error = -ENOMEM;
+ goto bad_swap;
+ }
+
+ error = 0;
+ memset(p->swap_map, 0, p->max * sizeof(short));
+ for (i=0; i<swap_header->info.nr_badpages; i++) {
+ int page = swap_header->info.badpages[i];
+ if (page <= 0 || page >= swap_header->info.last_page)
+ error = -EINVAL;
+ else
+ p->swap_map[page] = SWAP_MAP_BAD;
+ }
+ nr_good_pages = swap_header->info.last_page - i;
+ lock_map_size = (p->max + 7) / 8;
+ if (error)
+ goto bad_swap;
}
- if (!j) {
- printk("Empty swap-file\n");
+
+ if (!nr_good_pages) {
+ printk(KERN_WARNING "Empty swap-file\n");
error = -EINVAL;
goto bad_swap;
}
- p->swap_map = (unsigned char *) vmalloc(p->max);
- if (!p->swap_map) {
+ p->swap_map[0] = SWAP_MAP_BAD;
+ if (!(p->swap_lockmap = vmalloc (lock_map_size))) {
error = -ENOMEM;
goto bad_swap;
}
- for (i = 1 ; i < p->max ; i++) {
- if (test_bit(i,p->swap_lockmap))
- p->swap_map[i] = 0;
- else
- p->swap_map[i] = 0x80;
- }
- p->swap_map[0] = 0x80;
- memset(p->swap_lockmap,0,PAGE_SIZE);
+ memset(p->swap_lockmap,0,lock_map_size);
p->flags = SWP_WRITEOK;
- p->pages = j;
- nr_swap_pages += j;
+ p->pages = nr_good_pages;
+ nr_swap_pages += nr_good_pages;
printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n",
- j<<(PAGE_SHIFT-10), p->prio);
+ nr_good_pages<<(PAGE_SHIFT-10), p->prio);

/* insert swap space into swap_list: */
prev = -1;
@@ -615,8 +677,10 @@
if(filp.f_op && filp.f_op->release)
filp.f_op->release(filp.f_dentry->d_inode,&filp);
bad_swap_2:
- free_page((long) p->swap_lockmap);
- vfree(p->swap_map);
+ if (p->swap_lockmap)
+ vfree(p->swap_lockmap);
+ if (p->swap_map)
+ vfree(p->swap_map);
dput(p->swap_file);
p->swap_device = 0;
p->swap_file = NULL;
@@ -624,6 +688,8 @@
p->swap_lockmap = NULL;
p->flags = 0;
out:
+ if (swap_header)
+ free_page((long) swap_header);
unlock_kernel();
return error;
}
@@ -638,7 +704,7 @@
continue;
for (j = 0; j < swap_info[i].max; ++j)
switch (swap_info[i].swap_map[j]) {
- case 128:
+ case SWAP_MAP_BAD:
continue;
case 0:
++val->freeswap;
diff -u --new-file --recursive --exclude-from ../exclude linux.vanilla/mm/vmscan.c linux/mm/vmscan.c
--- linux.vanilla/mm/vmscan.c Tue Jul 21 14:19:31 1998
+++ linux/mm/vmscan.c Sun Jul 26 00:42:41 1998
@@ -24,6 +24,7 @@
#include <linux/dcache.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/init.h>

#include <asm/bitops.h>
#include <asm/pgtable.h>
@@ -491,7 +492,7 @@
* may be printed in the middle of another driver's init
* message). It looks very bad when that happens.
*/
-void kswapd_setup(void)
+__initfunc(void kswapd_setup(void))
{
int i;
char *revision="$Revision: 1.5 $", *s, *e;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html