diff -Nur linux-2.4.7/fs/proc/Makefile linux/fs/proc/Makefile
--- linux-2.4.7/fs/proc/Makefile	Sat Jul 21 10:58:21 2001
+++ linux/fs/proc/Makefile	Tue Jun  5 00:06:34 2001
@@ -11,7 +11,7 @@
 
 export-objs := root.o
 
-obj-y    := inode.o root.o base.o generic.o array.o \
+obj-y    := inode.o root.o base.o generic.o array.o onevalue.o \
 		kmsg.o proc_tty.o proc_misc.o kcore.o
 
 ifeq ($(CONFIG_PROC_DEVICETREE),y)
diff -Nur linux-2.4.7/fs/proc/base.c linux/fs/proc/base.c
--- linux-2.4.7/fs/proc/base.c	Sat Jul 21 10:58:21 2001
+++ linux/fs/proc/base.c	Sat Jul 21 09:58:26 2001
@@ -30,9 +30,13 @@
  * inumbers of the rest of procfs (currently those are in 0x0000--0xffff).
  * As soon as we'll get a separate superblock we will be able to forget
  * about magical ranges too.
+ * TJ (June 4th 2001): As the onevalue extensions needs a very large number of
+ * inodes i reduced the number of inodes per process to 4096 (instead of 
+ * 65536). This reduces the number of fd that can be exposed from 32768 to
+ * 2048. This will also change all inumbers.
  */
 
-#define fake_ino(pid,ino) (((pid)<<16)|(ino))
+#define fake_ino(pid,ino) (((pid)<<12)|(ino))
 
 ssize_t proc_pid_read_maps(struct task_struct*,struct file*,char*,size_t,loff_t*);
 int proc_pid_stat(struct task_struct*,char*);
@@ -520,7 +524,7 @@
 	PROC_PID_STATM,
 	PROC_PID_MAPS,
 	PROC_PID_CPU,
-	PROC_PID_FD_DIR = 0x8000,	/* 0x8000-0xffff */
+	PROC_PID_FD_DIR = 0x800	/* 0x800-0xfff */
 };
 
 #define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
diff -Nur linux-2.4.7/fs/proc/generic.c linux/fs/proc/generic.c
--- linux-2.4.7/fs/proc/generic.c	Sat Jul 21 10:58:21 2001
+++ linux/fs/proc/generic.c	Tue Jul 17 11:44:58 2001
@@ -14,10 +14,22 @@
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#include <linux/list.h>
+#include <linux/init.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <asm/bitops.h>
 
+/* size for context stacks */
+#define CONTEXT_STACK_SIZE (PROC_OV_MAX_CONTEXT_DEPTH+1)
+
+struct inode_range {
+	struct list_head free_inodes;
+	unsigned int first, end;
+};
+static LIST_HEAD(free_inodes);
+
+
 static ssize_t proc_file_read(struct file * file, char * buf,
 			      size_t nbytes, loff_t *ppos);
 static ssize_t proc_file_write(struct file * file, const char * buffer,
@@ -33,6 +45,103 @@
 	return !memcmp(name, de->name, len);
 }
 
+static void *enter_context_pde(const struct dentry *dentry,
+	                       struct proc_dir_entry *npde,
+			       void **context_stack) 
+{
+	void *c;
+	struct proc_dir_entry *pde;
+
+	if (!dentry) {
+		*context_stack = NULL;
+		return NULL;
+	}
+	
+	if (npde)
+		pde = npde;
+	else
+		pde = dentry->d_inode->u.proc_ov_i.entry;
+	
+	if ((!pde) || 
+	    ((pde->type != PROC_OV_DIR) &&
+	     (pde->type != PROC_OV_DYNAMIC_DIR))) {
+		*context_stack = NULL;
+		return NULL;
+	}
+
+	c = enter_context_pde(dentry->d_parent, NULL, context_stack + 1);
+
+	if (pde->type == PROC_OV_DIR) {
+		struct proc_ov_dir *ov = (struct proc_ov_dir *) pde;
+		if (ov->enter) 
+			c = ov->enter(c, 
+				      pde->data);
+	}
+	else {
+		struct proc_ov_dynamic_dir *ov = 
+			(struct proc_ov_dynamic_dir *) pde;
+                if (ov->get_context)
+			c = ov->get_context(dentry->d_inode->u.proc_ov_i.dir_index, 
+					    c,
+					    pde->data);
+	}
+
+	*context_stack = c;
+	return c;
+}
+
+static void *enter_context(const struct dentry *dentry,
+			   void **context_stack) 
+{
+	enter_context_pde(dentry, NULL, context_stack);
+}
+
+static void leave_context_pde(const struct dentry *dentry,
+			      struct proc_dir_entry *npde,
+			      void **context_stack) 
+{
+	struct proc_dir_entry *pde;
+
+	if (!dentry)
+		return;
+
+	if (npde)
+		pde = npde;
+	else
+		pde = dentry->d_inode->u.proc_ov_i.entry;
+
+	if ((!pde) || 
+	    ((pde->type != PROC_OV_DIR) &&
+	     (pde->type != PROC_OV_DYNAMIC_DIR)))
+		return;
+
+	if (pde->type == PROC_OV_DIR) {
+		struct proc_ov_dir *ov = (struct proc_ov_dir *) pde;
+		if (ov->leave)
+			ov->leave(context_stack[1], 
+				  *context_stack,
+				  pde->data);
+	}
+	else {
+		struct proc_ov_dynamic_dir *ov = 
+			(struct proc_ov_dynamic_dir *) pde;
+		if (ov->leave)
+			ov->leave(context_stack[1], 
+				  *context_stack,
+				  pde->data);
+	}
+
+	leave_context(dentry->d_parent, context_stack+1);
+}
+
+static void *leave_context(const struct dentry *dentry,
+			   void **context_stack) 
+{
+	leave_context_pde(dentry, NULL, context_stack);
+}
+
+
+
 static struct file_operations proc_file_operations = {
 	llseek:		proc_file_lseek,
 	read:		proc_file_read,
@@ -43,8 +152,61 @@
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
-/* buffer size is one page but our output routines use some slack for overruns */
-#define PROC_BLOCK_SIZE	(PAGE_SIZE - 1024)
+static ssize_t
+proc_file_ov_read(struct file *file, 
+		  char *page, 
+		  struct proc_dir_entry *dp)
+{
+	void *context_stack[CONTEXT_STACK_SIZE];
+	void *context;
+	struct proc_ov_value_enum *ove;
+	ssize_t n = 0;
+	int r = 0;
+	int value;
+	unsigned long ulvalue;
+
+	context = enter_context(file->f_dentry->d_parent, 
+				context_stack);
+	switch(dp->type) {
+	case PROC_OV_STRING:
+		r = ((struct proc_ov_value_string*)dp)
+			->get_string(page, context, dp->data);
+		if (r >= 0) {
+			n = r + 1;
+			page[n-1] = '\n';
+			page[n] = 0;					
+		}
+		break;
+	case PROC_OV_INT:
+		r = ((struct proc_ov_value_int*)dp)
+			->get_int(&value, context, dp->data);
+		if (r >= 0)
+			n = sprintf(page, "%d\n", value);
+		break;
+	case PROC_OV_ULONG:
+		r = ((struct proc_ov_value_ulong*)dp)
+			->get_ulong(&ulvalue, context, dp->data);
+		if (r >= 0)
+			n = sprintf(page, "%0lx\n", ulvalue);
+		break;
+	case PROC_OV_ENUM:
+		ove = (struct proc_ov_value_enum*)dp;
+		r = ove->get_enum(&value, context, dp->data);
+		if (r >= 0) {
+			strcpy(page, ove->enum_values[value]);
+			n = strlen(page) + 1;
+			page[n-1] = '\n';
+			page[n] = 0;
+		}
+		break;
+	default:
+		r = -EISDIR;
+	}
+	leave_context(file->f_dentry->d_parent, context_stack);
+	if (r < 0)
+		return r;
+	return n;
+}
 
 static ssize_t
 proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
@@ -57,9 +219,10 @@
 	char	*start;
 	struct proc_dir_entry * dp;
 
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	dp = inode->u.proc_ov_i.entry;
 	if (!(page = (char*) __get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
+	n = 0;
 
 	while ((nbytes > 0) && !eof)
 	{
@@ -77,9 +240,16 @@
 		} else if (dp->read_proc) {
 			n = dp->read_proc(page, &start, *ppos,
 					  count, &eof, dp->data);
+		} else if (dp->type != PROC_STATIC_ENTRY) {
+			n = proc_file_ov_read(file, page, dp);
 		} else
 			break;
 
+		if (n < 0) {
+			if (retval == 0)
+				retval = n;
+			break;
+		}
 		if (!start) {
 			/*
 			 * For proc files that are less than 4k
@@ -93,11 +263,6 @@
 		}
 		if (n == 0)
 			break;	/* End of file */
-		if (n < 0) {
-			if (retval == 0)
-				retval = n;
-			break;
-		}
 		
 		/* This is a hack to allow mangling of file pos independent
  		 * of actual bytes read.  Simply place the data at page,
@@ -127,7 +292,7 @@
 	struct inode *inode = file->f_dentry->d_inode;
 	struct proc_dir_entry * dp;
 	
-	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	dp = inode->u.proc_ov_i.entry;
 
 	if (!dp->write_proc)
 		return -EIO;
@@ -162,6 +327,7 @@
  * This function parses a name such as "tty/driver/serial", and
  * returns the struct proc_dir_entry for "/proc/tty/driver", and
  * returns "serial" in residual.
+ * Does not find dynamic entries (type == PROC_OV_DYNAMIC_DIR)
  */
 static int xlate_proc_name(const char *name,
 			   struct proc_dir_entry **ret, const char **residual)
@@ -190,35 +356,112 @@
 	return 0;
 }
 
-static unsigned long proc_alloc_map[(PROC_NDYNAMIC + BITS_PER_LONG - 1) / BITS_PER_LONG];
 
-spinlock_t proc_alloc_map_lock = SPIN_LOCK_UNLOCKED;
 
-static int make_inode_number(void)
+static unsigned int allocate_inode_range(unsigned int n) 
 {
-	int i;
-	spin_lock(&proc_alloc_map_lock);
-	i = find_first_zero_bit(proc_alloc_map, PROC_NDYNAMIC);
-	if (i < 0 || i >= PROC_NDYNAMIC) {
-		i = -1;
-		goto out;
+	struct list_head *pos;
+	struct list_head h;
+	struct inode_range *r, *prev, *next;
+	unsigned i = 0;
+
+	list_for_each(pos, &free_inodes) {
+		r = list_entry(pos, struct inode_range, free_inodes);
+
+		if ((r->end - r->first) < n)
+			continue;
+		i = r->first;
+		r->first += n;
+		if (r->first != r->end) 
+			break;
+
+		h = *pos;
+		list_del(pos);
+		kfree(r);
+
+		if ((h.prev == &free_inodes) ||
+		    (h.next == &free_inodes))
+			break;
+		prev = list_entry(h.prev, struct inode_range, free_inodes);
+		next = list_entry(h.next, struct inode_range, free_inodes); 
+		if (prev->end != next->first)
+			break;
+		next->first = prev->first;
+		list_del(h.prev);
+		kfree(prev);
+		break;
 	}
-	set_bit(i, proc_alloc_map);
-	i += PROC_DYNAMIC_FIRST;
-out:
-	spin_unlock(&proc_alloc_map_lock);
+
+	if (!i)
+		printk(KERN_ERR "proc: out of inodes\n");
 	return i;
 }
 
+static struct list_head *_prepend_inode_range(struct list_head *l, 
+					      unsigned int ino, 
+					      unsigned int n) {
+	struct inode_range *r;
+
+	r = kmalloc(sizeof(*r), GFP_KERNEL);
+	if (!r)
+		return NULL;
+	r->first = ino;
+	r->end = ino + n;
+	list_add_tail(&r->free_inodes, l);
+	return &r->free_inodes;
+}
+static void _join_inode_ranges(struct list_head *center) {
+	struct inode_range *p, *c, *n;
+	c = list_entry(center, struct inode_range, free_inodes);
+
+	if (center->prev != &free_inodes) {
+		p = list_entry(center->prev, struct inode_range, free_inodes);
+		if (p->end == c->first) {
+			c->first = p->first;
+			list_del(center->prev);
+			kfree(p);
+		}
+	}
+
+	if (center->next != &free_inodes) {
+		n = list_entry(center->next, struct inode_range, free_inodes);
+		if (c->end == n->first) {
+			c->end = n->end;
+			list_del(center->next);
+			kfree(n);
+		}
+	}	
+}
+static int free_inode_range(unsigned int ino, unsigned int n) 
+{
+	struct list_head *pos;
+	struct list_head *c;
+
+	list_for_each(pos, &free_inodes) {
+		struct inode_range *r;
+		r = list_entry(pos, struct inode_range, free_inodes);
+		if (ino < r->first)
+			break;
+	}
+	
+	c = _prepend_inode_range(pos, ino, n);
+	if(!c)
+		return -1;
+
+	_join_inode_ranges(c);
+	return 0;
+}
+
+
 static int proc_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
-	char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data;
+	char *s=(dentry->d_inode->u.proc_ov_i.entry)->data;
 	return vfs_readlink(dentry, buffer, buflen, s);
 }
 
 static int proc_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char *s=((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data;
+	char *s=(dentry->d_inode->u.proc_ov_i.entry)->data;
 	return vfs_follow_link(nd, s);
 }
 
@@ -243,6 +486,178 @@
 	d_delete:	proc_delete_dentry,
 };
 
+static unsigned int get_inode_space(struct proc_dir_entry *p) 
+{
+	if ((!p) || (p->type == PROC_STATIC_ENTRY))
+		return 1;
+	if (p->type == PROC_OV_DIR)
+		return ((struct proc_ov_dir*)p)->ino_space;
+	if (p->type == PROC_OV_DYNAMIC_DIR)
+		return ((struct proc_ov_dynamic_dir*)p)->ino_space;
+      	return get_inode_space(p->parent);
+}
+
+static unsigned int get_ino_index(struct inode *parent_inode, 
+				  struct proc_dir_entry *de,
+				  int index) 
+{
+	unsigned int ino;
+	if (de->type == PROC_STATIC_ENTRY)
+		return 0;
+	if ((!de->parent) || (de->parent->type == PROC_STATIC_ENTRY))
+		ino = 0;
+	else
+		ino = parent_inode->u.proc_ov_i.inode_index;
+
+	if (de->type == PROC_OV_DYNAMIC_DIR) {
+		ino *= ((struct proc_ov_dynamic_dir *)de)->max_size; 
+		ino += index;
+	}
+	return ino;
+}
+
+static int get_dyndir_links(struct proc_dir_entry *de,
+			    struct dentry *dentry)
+{
+	struct proc_ov_dynamic_dir *dd;
+	int nlinks = 0;
+	void *context_stack[CONTEXT_STACK_SIZE];
+	void *context;
+
+	dd = de->dyndir;
+	
+	context = enter_context_pde(dentry, de, context_stack);
+	while (dd) {
+		nlinks += dd->get_num(context, dd->super.data);
+		dd = (struct proc_ov_dynamic_dir*)dd->super.next;
+	}
+	leave_context_pde(dentry, de, context_stack);
+	
+	return nlinks;
+}
+
+static struct inode *_lookup_static_inode(struct proc_dir_entry *parent,
+					  struct inode *dir,
+					  struct dentry *dentry,
+					  int *error) 
+{
+	struct proc_dir_entry *de;
+	struct inode *inode = NULL;
+	unsigned int ino;
+
+	for (de = parent->subdir; de ; de = de->next) {
+		if (!de || !de->low_ino)
+			continue;
+		if (de->namelen != dentry->d_name.len)
+			continue;
+		if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
+			*error = -EINVAL;
+			ino = get_ino_index(dir, de, 0);
+
+			inode = proc_get_inode(dir->i_sb, 
+					       ino + de->low_ino, 
+					       de);
+			inode->u.proc_ov_i.inode_index = ino;
+			inode->u.proc_ov_i.dir_index = -1;
+			if (de->dyndir)
+				inode->i_nlink += get_dyndir_links(de, dentry);
+
+			break;
+		}
+	}
+	return inode;
+}
+
+static int index_number_name(int index, 
+			     void *context, 
+			     void *data,
+			     char *name_buf)
+{
+	return sprintf(name_buf, "%d", index);
+}
+
+static int _match_regular_name(struct proc_ov_dynamic_dir *ov,
+			       void *context, 
+			       int n,
+			       struct dentry *dentry)
+{
+	int nlen, i;
+	char namebuf[NAME_MAX];
+	for (i = 0; i < n; i++) {
+		nlen = ov->get_name(i, 
+				    context, 
+				    ov->super.data,
+				    namebuf);
+		if ((nlen == dentry->d_name.len) &&
+		    !strcmp(dentry->d_name.name, namebuf)) 
+			return i;
+	}
+	return -1;
+}
+static int _match_number_name(int n, struct dentry *dentry)
+{
+	int r = 0;
+	int l = dentry->d_name.len;
+	const char *name = dentry->d_name.name;
+	char c;
+
+	while (l > 0) {
+		c = *(name++);
+		if ((c < '0') || (c > '9'))
+			return -1;
+		if ((c == '0') && (r == 0) && (*name != '\0'))
+			return -1;
+		r *= 10;
+		r += c - '0';
+		l--;
+	}
+
+	if (n > r)
+		return r;
+	return -1;
+}
+static struct inode *_lookup_dynamic_inode(struct proc_dir_entry *de,
+					   struct inode *dir,
+					   struct dentry *dentry,
+					   int *error) 
+{
+	struct proc_ov_dynamic_dir *ov;
+	struct inode *inode = NULL;
+	unsigned int ino;
+	int n, i;
+	void *context_stack[CONTEXT_STACK_SIZE];
+	void *context;
+
+	ov = de->dyndir;
+	if (!ov)
+		return NULL;
+
+	context = enter_context(dentry->d_parent, context_stack);
+	while (ov) {
+		n = ov->get_num(context, ov->super.data);
+		if (n > ov->max_size) {
+			printk(KERN_WARNING "proc: not enough inodes reserved "
+			       "for dynamic dir (max_size=%d)\n", ov->max_size);
+			n = ov->max_size;
+		}
+
+		if ((ov->get_name && ((i = _match_regular_name(ov, context, n, dentry)) >= 0)) ||
+		    ((!ov->get_name) && ((i = _match_number_name(n, dentry)) >= 0))) {
+			*error = -EINVAL;
+			ino = get_ino_index(dir, &ov->super, i);
+			inode = proc_get_inode(dir->i_sb, 
+					       ino + ov->super.low_ino, 
+					       &ov->super);
+			inode->u.proc_ov_i.inode_index = ino;
+			inode->u.proc_ov_i.dir_index = i;
+			break;
+		}
+		ov = (struct proc_ov_dynamic_dir*) ov->super.next;
+	}
+	leave_context(dentry->d_parent, context_stack);
+	return inode;
+}
+
 /*
  * Don't create negative dentries here, return -ENOENT by hand
  * instead.
@@ -250,26 +665,18 @@
 struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry)
 {
 	struct inode *inode;
-	struct proc_dir_entry * de;
+	struct proc_dir_entry *de;
 	int error;
 
 	error = -ENOENT;
 	inode = NULL;
-	de = (struct proc_dir_entry *) dir->u.generic_ip;
-	if (de) {
-		for (de = de->subdir; de ; de = de->next) {
-			if (!de || !de->low_ino)
-				continue;
-			if (de->namelen != dentry->d_name.len)
-				continue;
-			if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
-				int ino = de->low_ino;
-				error = -EINVAL;
-				inode = proc_get_inode(dir->i_sb, ino, de);
-				break;
-			}
-		}
-	}
+	de = dir->u.proc_ov_i.entry;
+	if (!de) 
+		return ERR_PTR(error);
+
+	inode = _lookup_static_inode(de, dir, dentry, &error);
+	if (!inode) 
+		inode = _lookup_dynamic_inode(de, dir, dentry, &error);
 
 	if (inode) {
 		dentry->d_op = &proc_dentry_operations;
@@ -279,6 +686,80 @@
 	return ERR_PTR(error);
 }
 
+static int _read_static_dirs(struct proc_dir_entry *de, 
+			     int *skip, 
+			     struct file *filp,
+			     void *dirent, 
+			     filldir_t filldir)
+{
+	while (de && *skip) {
+		de = de->next;
+		(*skip)--;
+	}
+	
+	while (de) {
+		if (filldir(dirent, de->name, de->namelen, filp->f_pos,
+			    get_ino_index(filp->f_dentry->d_inode, 
+					  de, 
+					  0) + de->low_ino, 
+			    de->mode >> 12) < 0)
+			return 1;
+		filp->f_pos++;
+		de = de->next;
+	}
+	return 0;
+}
+
+static int _read_dynamic_dirs(struct proc_ov_dynamic_dir *de, 
+			      int *skip, 
+			      struct file *filp,
+			      void *dirent, 
+			      filldir_t filldir)
+{
+	char namebuf[NAME_MAX];
+	void *context_stack[CONTEXT_STACK_SIZE];
+	int n, j, l;
+	void *context;
+
+	if (!de)
+		return 0;
+
+	context = enter_context(filp->f_dentry, 
+				context_stack);
+	while (de) {
+		n = de->get_num(context, de->super.data);
+		if (n > de->max_size) {
+			printk(KERN_WARNING "proc: not enough inodes reserved "
+			       "for dynamic dir (max_size=%d)\n", de->max_size);
+			n = de->max_size;
+		}
+		for (j = *skip; j < n; j++) {
+			if (de->get_name)
+				l = de->get_name(j, context, de->super.data, namebuf);
+			else
+				l = sprintf(namebuf, "%d", j);
+
+			if ( (l<=0) ||
+			     (filldir(dirent, namebuf, l, 
+				      filp->f_pos, 
+				      get_ino_index(filp->f_dentry->d_inode, 
+						    &de->super,
+						    j) + de->super.low_ino, 
+				      de->super.mode >> 12) < 0)) {
+				leave_context(filp->f_dentry, context_stack);
+				return 1;
+			}
+			filp->f_pos++;
+		}
+		*skip -= n;
+		if (*skip < 0)
+			*skip = 0;
+		de = (struct proc_ov_dynamic_dir*) de->super.next;
+	}
+	leave_context(filp->f_dentry, context_stack);
+	return 0;
+}
+
 /*
  * This returns non-zero if at EOF, so that the /proc
  * root directory can use this and check if it should
@@ -291,13 +772,13 @@
 int proc_readdir(struct file * filp,
 	void * dirent, filldir_t filldir)
 {
-	struct proc_dir_entry * de;
+	struct proc_dir_entry *de;
 	unsigned int ino;
 	int i;
 	struct inode *inode = filp->f_dentry->d_inode;
 
 	ino = inode->i_ino;
-	de = (struct proc_dir_entry *) inode->u.generic_ip;
+	de = inode->u.proc_ov_i.entry;
 	if (!de)
 		return -EINVAL;
 	i = filp->f_pos;
@@ -317,24 +798,21 @@
 			filp->f_pos++;
 			/* fall through */
 		default:
-			de = de->subdir;
 			i -= 2;
-			for (;;) {
-				if (!de)
-					return 1;
-				if (!i)
-					break;
-				de = de->next;
-				i--;
-			}
 
-			do {
-				if (filldir(dirent, de->name, de->namelen, filp->f_pos,
-					    de->low_ino, de->mode >> 12) < 0)
-					return 0;
-				filp->f_pos++;
-				de = de->next;
-			} while (de);
+			if(_read_static_dirs(de->subdir, 
+					     &i, 
+					     filp, 
+					     dirent, 
+					     filldir))
+				return 0;
+
+			if (_read_dynamic_dirs(de->dyndir,
+					       &i,
+					       filp,
+					       dirent,
+					       filldir))
+				return 0;
 	}
 	return 1;
 }
@@ -356,13 +834,25 @@
 	lookup:		proc_lookup,
 };
 
-static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
+/* for onevalue.c */
+int proc_init_dyn_dir(struct proc_dir_entry *ent, unsigned int ino_space)
 {
-	int	i;
-	
-	i = make_inode_number();
-	if (i < 0)
+	unsigned int ino;
+	ent->proc_fops = &proc_dir_operations;
+	ent->proc_iops = &proc_dir_inode_operations;	
+	ino = allocate_inode_range(ino_space);
+	ent->low_ino = ino;
+	return ino != 0;
+}
+
+static int proc_register_ino(struct proc_dir_entry * dir, 
+			     struct proc_dir_entry * dp,
+			     unsigned int inos)
+{
+	unsigned int i = allocate_inode_range(inos);
+	if (!i)
 		return -EAGAIN;
+
 	dp->low_ino = i;
 	dp->next = dir->subdir;
 	dp->parent = dir;
@@ -383,6 +873,11 @@
 	return 0;
 }
 
+static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) 
+{
+	return proc_register_ino(dir, dp, 1);
+}
+
 /*
  * Kill an inode that got unregistered..
  */
@@ -406,7 +901,7 @@
 		if (dentry->d_op != &proc_dentry_operations)
 			continue;
 		inode = dentry->d_inode;
-		if (inode->u.generic_ip != de)
+		if (inode->u.proc_ov_i.entry != de)
 			continue;
 		fops_put(filp->f_op);
 		filp->f_op = NULL;
@@ -414,10 +909,14 @@
 	file_list_unlock();
 }
 
+/*
+ * Does not find dynamic entries (type == PROC_OV_DYNAMIC_DIR)
+ */
 static struct proc_dir_entry *proc_create(struct proc_dir_entry **parent,
 					  const char *name,
 					  mode_t mode,
-					  nlink_t nlink)
+					  nlink_t nlink,
+					  unsigned int structlen)
 {
 	struct proc_dir_entry *ent = NULL;
 	const char *fn = name;
@@ -430,12 +929,12 @@
 		goto out;
 	len = strlen(fn);
 
-	ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
-	if (!ent) goto out;
-
-	memset(ent, 0, sizeof(struct proc_dir_entry));
-	memcpy(((char *) ent) + sizeof(struct proc_dir_entry), fn, len + 1);
-	ent->name = ((char *) ent) + sizeof(*ent);
+	ent = kmalloc(structlen + len + 1, GFP_KERNEL);
+	if (!ent)
+		goto out;
+	memset(ent, 0, structlen);
+	memcpy(((char *) ent) + structlen, fn, len + 1);
+	ent->name = ((char *) ent) + structlen;
 	ent->namelen = len;
 	ent->mode = mode;
 	ent->nlink = nlink;
@@ -443,13 +942,17 @@
 	return ent;
 }
 
+/*
+ * Does not find dynamic entries (type == PROC_OV_DYNAMIC_DIR)
+ */
 struct proc_dir_entry *proc_symlink(const char *name,
 		struct proc_dir_entry *parent, const char *dest)
 {
 	struct proc_dir_entry *ent;
 
 	ent = proc_create(&parent,name,
-			  (S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO),1);
+			  (S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO),1,
+			  sizeof(struct proc_dir_entry));
 
 	if (ent) {
 		ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL);
@@ -461,15 +964,18 @@
 			ent = NULL;
 		}
 	}
-	return ent;
-}
+  	return ent;
+  }
 
+/*
+ * Does not find dynamic entries (type == PROC_OV_DYNAMIC_DIR)
+ */
 struct proc_dir_entry *proc_mknod(const char *name, mode_t mode,
 		struct proc_dir_entry *parent, kdev_t rdev)
 {
 	struct proc_dir_entry *ent;
-
-	ent = proc_create(&parent,name,mode,1);
+  
+	ent = proc_create(&parent,name,mode,1,sizeof(struct proc_dir_entry));
 	if (ent) {
 		ent->rdev = rdev;
 		proc_register(parent, ent);
@@ -477,40 +983,50 @@
 	return ent;
 }
 
+/*
+ * Does not find dynamic entries (type == PROC_OV_DYNAMIC_DIR)
+ */
 struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent)
 {
 	struct proc_dir_entry *ent;
-
+  
 	ent = proc_create(&parent,name,
-			  (S_IFDIR | S_IRUGO | S_IXUGO),2);
+			  (S_IFDIR | S_IRUGO | S_IXUGO),2, 
+			  sizeof(struct proc_dir_entry));
 	if (ent) {
 		ent->proc_fops = &proc_dir_operations;
 		ent->proc_iops = &proc_dir_inode_operations;
-
+  
 		proc_register(parent, ent);
 	}
 	return ent;
 }
 
-struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
-					 struct proc_dir_entry *parent)
+/*
+ * For onevalue.c: create_proc_entry that allows larger structs
+ */
+struct proc_dir_entry *create_proc_entry_common(const char *name, 
+						mode_t mode,
+						int structlen, 
+						struct proc_dir_entry *parent,
+						unsigned int inos)
 {
 	struct proc_dir_entry *ent;
 	nlink_t nlink;
-
-	if (S_ISDIR(mode)) {
-		if ((mode & S_IALLUGO) == 0)
+  
+  	if (S_ISDIR(mode)) {
+  		if ((mode & S_IALLUGO) == 0)
 			mode |= S_IRUGO | S_IXUGO;
 		nlink = 2;
-	} else {
-		if ((mode & S_IFMT) == 0)
-			mode |= S_IFREG;
-		if ((mode & S_IALLUGO) == 0)
-			mode |= S_IRUGO;
+  	} else {
+  		if ((mode & S_IFMT) == 0)
+  			mode |= S_IFREG;
+  		if ((mode & S_IALLUGO) == 0)
+  			mode |= S_IRUGO;
 		nlink = 1;
-	}
-
-	ent = proc_create(&parent,name,mode,nlink);
+  	}
+ 
+	ent = proc_create(&parent,name,mode,nlink,structlen);
 	if (ent) {
 		if (S_ISDIR(mode)) {
 			ent->proc_fops = &proc_dir_operations;
@@ -518,24 +1034,49 @@
 		}
 		proc_register(parent, ent);
 	}
-	return ent;
+  	return ent;
 }
 
-void free_proc_entry(struct proc_dir_entry *de)
+struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
+					 struct proc_dir_entry *parent)
 {
-	int ino = de->low_ino;
+	return create_proc_entry_common(name, 
+					mode, 
+					sizeof(struct proc_dir_entry), 
+					parent, 
+					1);
+}
 
+void free_proc_entry(struct proc_dir_entry *de, unsigned int ino)
+{
 	if (ino < PROC_DYNAMIC_FIRST ||
-	    ino >= PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
+		 ino >= PROC_DYNAMIC_FIRST+PROC_NDYNAMIC)
 		return;
 	if (S_ISLNK(de->mode) && de->data)
 		kfree(de->data);
 	kfree(de);
 }
 
+void proc_unregister_entry(struct proc_dir_entry *de)
+{
+	if (S_ISDIR(de->mode))
+		de->parent->nlink--;
+	free_inode_range(de->low_ino, get_inode_space(de));
+	proc_kill_inodes(de);
+	de->nlink = 0;
+	if (!atomic_read(&de->count))
+		free_proc_entry(de, de->low_ino);
+	else {
+		de->deleted = 1;
+		printk("remove_proc_entry: %s/%s busy, count=%d\n",
+		       de->parent->name, de->name, atomic_read(&de->count));
+	}
+}
+
 /*
  * Remove a /proc entry and free it if it's not currently in use.
  * If it is in use, we set the 'deleted' flag.
+ * Cannot be used to delete dynamic proc entries.
  */
 void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
 {
@@ -553,21 +1094,22 @@
 		de = *p;
 		*p = de->next;
 		de->next = NULL;
-		if (S_ISDIR(de->mode))
-			parent->nlink--;
-		clear_bit(de->low_ino - PROC_DYNAMIC_FIRST,
-			  proc_alloc_map);
-		proc_kill_inodes(de);
-		de->nlink = 0;
-		if (!atomic_read(&de->count))
-			free_proc_entry(de);
-		else {
-			de->deleted = 1;
-			printk("remove_proc_entry: %s/%s busy, count=%d\n",
-				parent->name, de->name, atomic_read(&de->count));
-		}
+		proc_unregister_entry(de);
 		break;
 	}
 out:
 	return;
+}
+
+void __init proc_generic_init(void) 
+{
+	struct inode_range *r = kmalloc(sizeof(*r), GFP_KERNEL);
+	if (!r) {
+		printk(KERN_ERR "proc: failure allocating memory"
+		       " at initialization!");
+		return;
+	}
+	r->first = PROC_DYNAMIC_FIRST;
+	r->end = r->first + PROC_NDYNAMIC;
+	list_add(&r->free_inodes, &free_inodes);
 }
diff -Nur linux-2.4.7/fs/proc/inode.c linux/fs/proc/inode.c
--- linux-2.4.7/fs/proc/inode.c	Sat Jul 21 10:58:21 2001
+++ linux/fs/proc/inode.c	Sun Jul 15 13:12:20 2001
@@ -20,7 +20,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-extern void free_proc_entry(struct proc_dir_entry *);
+extern void free_proc_entry(struct proc_dir_entry *, int ino);
 
 struct proc_dir_entry * de_get(struct proc_dir_entry *de)
 {
@@ -32,9 +32,9 @@
 /*
  * Decrements the use count and checks for deferred deletion.
  */
-void de_put(struct proc_dir_entry *de)
+void de_put(struct proc_dir_entry *de, struct inode *inode)
 {
-	if (de) {	
+	if (de) {
 		lock_kernel();		
 		if (!atomic_read(&de->count)) {
 			printk("de_put: entry %s already free!\n", de->name);
@@ -46,7 +46,7 @@
 			if (de->deleted) {
 				printk("de_put: deferred delete of %s\n",
 					de->name);
-				free_proc_entry(de);
+				free_proc_entry(de, inode->i_ino);
 			}
 		}		
 		unlock_kernel();
@@ -58,7 +58,7 @@
  */
 static void proc_delete_inode(struct inode *inode)
 {
-	struct proc_dir_entry *de = inode->u.generic_ip;
+	struct proc_dir_entry *de = inode->u.proc_ov_i.entry;
 
 	inode->i_state = I_CLEAR;
 
@@ -69,7 +69,7 @@
 	if (de) {
 		if (de->owner)
 			__MOD_DEC_USE_COUNT(de->owner);
-		de_put(de);
+		de_put(de, inode);
 	}
 }
 
@@ -128,7 +128,7 @@
 	return 1;
 }
 
-struct inode * proc_get_inode(struct super_block * sb, int ino,
+struct inode * proc_get_inode(struct super_block * sb, unsigned int ino,
 				struct proc_dir_entry * de)
 {
 	struct inode * inode;
@@ -147,7 +147,7 @@
 	if (!inode)
 		goto out_fail;
 	
-	inode->u.generic_ip = (void *) de;
+	inode->u.proc_ov_i.entry = de;
 	if (de) {
 		if (de->mode) {
 			inode->i_mode = de->mode;
@@ -174,7 +174,7 @@
 	return inode;
 
 out_fail:
-	de_put(de);
+	de_put(de, inode);
 	goto out;
 }			
 
diff -Nur linux-2.4.7/fs/proc/onevalue.c linux/fs/proc/onevalue.c
--- linux-2.4.7/fs/proc/onevalue.c	Thu Jan  1 01:00:00 1970
+++ linux/fs/proc/onevalue.c	Wed Jul 18 13:50:39 2001
@@ -0,0 +1,358 @@
+/*
+ * fs/proc/onevalue.c --- one-value-per-file proc api
+ *
+ * Contains API implementations for "one-value-per-file" in the /proc
+ * filesystem. Makes it possible to create directories dynamically
+ * (like the per-process dirs /proc/<number>/). 
+ *
+ * When using this API, do not mix static entries that have been created 
+ * with the old API with those created by the proc_ov functions, otherwise
+ * the allocation of inode numbers may not work. It is ok to put ov files or
+ * directories into static directories, but you do not insert static entries 
+ * into ov directories.
+ * As all kmalloc invocations use GFP_KERNEL you must not use the proc_ov
+ * functions at interrupt time (hard or soft).
+ */
+
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+
+/**
+ * proc_ov_get_entry - Returns the entry for the given path.
+ * @path: The path of the entry (may begin with "/proc", a relative path
+ *        is interpreted as relative to "/proc/").
+ * 
+ * Returns a pointer to the corresponding struct proc_dir_entry, or %NULL if 
+ * not found.
+ */
+struct proc_dir_entry *
+proc_ov_get_entry(const char *path)
+{
+	const char *n;
+	const char *name = path;
+	struct proc_dir_entry *e = &proc_root;
+	
+	if (strstr(name, "/proc") == name)
+		name += strlen("/proc");
+	if (name[0] == '/')
+		name++;
+	if (!strlen(name))
+		return e;
+
+	while(1) {
+		n = strchr(name, '/');
+		if (!n)
+			n = &name[strlen(name)];
+
+		for (e = e->subdir; e; e = e->next) 
+			if (proc_match(n - name, name, e))
+				break;
+		if (!e)
+			return NULL;
+		if (!(n[0] && n[1]))
+			break;
+		name = &n[1];
+	}
+	return e;
+}
+
+static int _get_ino_space(struct proc_dir_entry *p) 
+{
+	if (p->type == PROC_OV_DIR)
+		return ((struct proc_ov_dir*)p)->ino_space;
+	if (p->type == PROC_OV_DYNAMIC_DIR)
+		return ((struct proc_ov_dynamic_dir*)p)->ino_space;
+      	return 1;
+}
+
+/**
+ * proc_ov_register_string - Adds a file containing a string.
+ * @parent: The parent directory of the new file, use %NULL for root.
+ * @name: The name of the new file.
+ * @cb: The callback function to generate the file's string.
+ * 
+ * The parent must have been created using proc_ov_register_dir() or 
+ * proc_ov_register_dynamic_dir().
+ * Returns a pointer to the created struct proc_dir_entry, or %NULL if 
+ * the creation failed or CONFIG_PROC_FS in not enabled.
+ */
+struct proc_dir_entry *
+proc_ov_register_string(struct proc_dir_entry *parent, 
+			const char *name,
+			proc_ov_get_string_t cb) 
+{
+	struct proc_ov_value_string * ov;
+
+	if (!parent)
+		parent = &proc_root;
+
+	ov = (struct proc_ov_value_string*) 
+		create_proc_entry_common(name, 
+					 0, 
+					 sizeof(struct proc_ov_value_string),
+					 parent,
+					 _get_ino_space(parent));
+	if (!ov)
+		return NULL;
+
+	ov->super.type = PROC_OV_STRING;
+	ov->get_string = cb;
+	return &ov->super;
+}
+
+/**
+ * proc_ov_register_int - Adds a file containing an integer.
+ * @parent: The parent directory of the new file. Use %NULL for root.
+ * @name: The name of the new file.
+ * @cb: The callback function to generate the file's integer.
+ * 
+ * The parent must have been created using proc_ov_register_dir() or 
+ * proc_ov_register_dynamic_dir().
+ * Returns a pointer to the created struct proc_dir_entry, or %NULL if 
+ * the creation failed or CONFIG_PROC_FS in not enabled.
+ */
+struct proc_dir_entry *
+proc_ov_register_int(struct proc_dir_entry *parent, 
+		     const char *name,
+		     proc_ov_get_int_t cb)
+{
+	struct proc_ov_value_int * ov;
+
+	if (!parent)
+		parent = &proc_root;
+
+	ov = (struct proc_ov_value_int*) 
+		create_proc_entry_common(name, 
+					 0, 
+					 sizeof(struct proc_ov_value_int),
+					 parent,
+					 _get_ino_space(parent));
+	if (!ov)
+		return NULL;
+
+	ov->super.type = PROC_OV_INT;
+	ov->get_int = cb;
+	return &ov->super;	
+}
+
+/**
+ * proc_ov_register_ulong - Adds a file containing an unsingned long.
+ * @parent: The parent directory of the new file. Use %NULL for root.
+ * @name: The name of the new file.
+ * @cb: The callback function to generate the file's integer.
+ * 
+ * The parent must have been created using proc_ov_register_dir() or 
+ * proc_ov_register_dynamic_dir().
+ * Returns a pointer to the created struct proc_dir_entry, or %NULL if 
+ * the creation failed or CONFIG_PROC_FS in not enabled.
+ */
+struct proc_dir_entry *
+proc_ov_register_ulong(struct proc_dir_entry *parent, 
+		       const char *name,
+		       proc_ov_get_ulong_t cb)
+{
+	struct proc_ov_value_ulong * ov;
+
+	if (!parent)
+		parent = &proc_root;
+
+	ov = (struct proc_ov_value_ulong*) 
+		create_proc_entry_common(name, 
+					 0, 
+					 sizeof(struct proc_ov_value_ulong),
+					 parent,
+					 _get_ino_space(parent));
+	if (!ov)
+		return NULL;
+
+	ov->super.type = PROC_OV_ULONG;
+	ov->get_ulong = cb;
+	return &ov->super;	
+}
+
+
+/**
+ * proc_ov_register_enum - Adds a file containing an enum.
+ * @parent: The parent directory of the new file. Use %NULL for the root 
+ * directory.
+ * @name: The name of the new file.
+ * @enum_values: A string array containing the possible values. Must be valid
+ *               as long as the file is registered and NULL-terminated.
+ * @cb: The callback function to generate the file's value.
+ * 
+ * The parent must have been created using proc_ov_register_dir() or 
+ * proc_ov_register_dynamic_dir().
+ * Returns a pointer to the created struct proc_dir_entry, or %NULL if 
+ * the creation failed or CONFIG_PROC_FS in not enabled.
+ */
+struct proc_dir_entry *
+proc_ov_register_enum(struct proc_dir_entry *parent, 
+		      const char *name,
+		      const char **enum_values,
+		      proc_ov_get_enum_t cb)
+{
+	struct proc_ov_value_enum * ov;
+
+	if (!parent)
+		parent = &proc_root;
+
+	ov = (struct proc_ov_value_enum*) 
+		create_proc_entry_common(name, 
+					 0, 
+					 sizeof(struct proc_ov_value_enum),
+					 parent,
+					 _get_ino_space(parent));
+	if (!ov) 
+		return NULL;
+
+	ov->super.type = PROC_OV_ENUM;
+	ov->get_enum = cb;
+	ov->enum_values = enum_values;
+	return &ov->super;
+}
+
+/**
+ * proc_ov_register_dir - Adds a directory to the proc filesystem (with context support). 
+ * @parent: The parent directory of the new dir. Use %NULL for the root directory.
+ * @name: The name of the directory.
+ * @denter: The callback function to generate the directory's context, and/or do
+ *          things like locking. Can be %NULL.
+ * @dleave: The callback function to do context-related cleanup work 
+ *          (e.g. unlocking). Can be %NULL.
+ * 
+ * Returns a pointer to the created struct proc_dir_entry, or %NULL if 
+ * the creation failed or CONFIG_PROC_FS in not enabled.
+ */
+struct proc_dir_entry * 
+proc_ov_register_dir(struct proc_dir_entry *parent, 
+		     const char *name,
+		     proc_ov_dir_enter_t denter,
+		     proc_ov_dir_leave_t dleave)
+{
+	struct proc_ov_dir * ov;
+	int inos;
+
+	if (!parent)
+		parent = &proc_root;
+
+	inos = _get_ino_space(parent);
+
+	ov = (struct proc_ov_dir*) 
+		create_proc_entry_common(name, 
+					 S_IFDIR | S_IRUGO | S_IXUGO, 
+					 sizeof(struct proc_ov_dir),
+					 parent,
+					 inos);
+	if (!ov)
+		return NULL;
+
+	ov->super.type = PROC_OV_DIR;
+	ov->enter = denter;
+	ov->leave = dleave;
+	ov->ino_space = inos;
+	return &ov->super;
+}
+
+
+/**
+ * proc_ov_register_dynamic_dir - Adds dynamic directories to a proc dir.
+ * @parent: The parent directory of the dynamic directories. It is not 
+ *          possible to add a dynamic dir to the root directory.
+ * @size: The maximum number of entries in this directory. 
+ * @dnum: A function that returns the number of directories.
+ * @dname: A function that writes the name of the entry into the NAME_MAX long
+ *         buffer. Can be %NULL, then the index number is the name.
+ * @denter: The function to generate the directory's context, and/or 
+ *          do things like locking. Can be %NULL.
+ * @dleave: The function to do context-related cleanup work (e.g. unlocking). 
+ *          Can be %NULL.
+ * 
+ * Returns a pointer to the created struct proc_dir_entry, or %NULL if 
+ * the creation failed or CONFIG_PROC_FS in not enabled.
+ */
+struct proc_dir_entry *
+proc_ov_register_dynamic_dir(struct proc_dir_entry *parent,
+			     unsigned int size, 
+			     proc_ov_dir_num_t dnum,
+			     proc_ov_dir_name_t dname,
+			     proc_ov_dir_context_t denter,
+			     proc_ov_dir_leave_t dleave)
+{
+	int ino_space;
+	struct proc_dir_entry *ent;
+	struct proc_ov_dynamic_dir *ov;
+
+	ov = (struct proc_ov_dynamic_dir*) 
+		kmalloc(sizeof(struct proc_ov_dynamic_dir), GFP_KERNEL);
+	if (!ov)
+		return NULL;
+	memset(ov, 0, sizeof(*ov));
+
+	ino_space = _get_ino_space(parent) * size;
+
+	ent = &ov->super;
+	ent->type = PROC_OV_DYNAMIC_DIR;
+	ent->name = "(dynamic dir stub)";
+	ent->namelen = 0;
+	ent->nlink = 2;
+	ent->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+	if (!proc_init_dyn_dir(ent, ino_space)) {
+		kfree(ov);
+		return NULL;
+	}
+
+	ov->get_num = dnum;
+	ov->get_name = dname;
+	ov->get_context = denter;
+	ov->leave = dleave;
+	ov->max_size = size;
+	ov->ino_space = ino_space;
+
+	ent->parent = parent;
+	ent->next = &parent->dyndir->super;
+	parent->dyndir = ov;
+	return ent;
+}
+
+static void remove_level(struct proc_dir_entry *first)
+{
+	struct proc_dir_entry *e = first;
+
+	while (e) {
+		proc_ov_remove(e);
+		e = e->next;
+	}
+}
+
+/**
+ * proc_ov_register_remove - Removes the given entry, including its
+ * children.
+ *
+ * @e: The entry to remove. Can be %NULL, will be ignored then.
+ */
+void proc_ov_remove(struct proc_dir_entry *e)
+{
+	struct proc_dir_entry **i = NULL;
+
+	if (!e)
+		return;
+
+	remove_level(e->subdir);
+	remove_level(&e->dyndir->super);
+
+	if (e->type == PROC_OV_DYNAMIC_DIR) 
+		i = (struct proc_dir_entry**) &e->parent->dyndir;
+	else
+		i = &e->parent->subdir;
+
+	while (i && *i) {
+		if (*i == e) {
+			*i = (*i)->next;
+			break;
+		}
+		i = &((*i)->next);
+	}
+	
+	proc_unregister_entry(e);
+}
+
diff -Nur linux-2.4.7/fs/proc/root.c linux/fs/proc/root.c
--- linux-2.4.7/fs/proc/root.c	Sat Jul 21 10:58:21 2001
+++ linux/fs/proc/root.c	Tue Jun  5 00:22:02 2001
@@ -27,15 +27,17 @@
 
 void __init proc_root_init(void)
 {
-	int err = register_filesystem(&proc_fs_type);
-	if (err)
-		return;
-	proc_mnt = kern_mount(&proc_fs_type);
-	err = PTR_ERR(proc_mnt);
-	if (IS_ERR(proc_mnt)) {
-		unregister_filesystem(&proc_fs_type);
-		return;
-	}
+ 	int err = register_filesystem(&proc_fs_type);
+ 	if (err)
+ 		return;
+ 	proc_mnt = kern_mount(&proc_fs_type);
+ 	err = PTR_ERR(proc_mnt);
+ 	if (IS_ERR(proc_mnt)) {
+ 		unregister_filesystem(&proc_fs_type);
+ 		return;
+ 	}
+
+	proc_generic_init();
 	proc_misc_init();
 	proc_net = proc_mkdir("net", 0);
 #ifdef CONFIG_SYSVIPC
@@ -135,3 +137,11 @@
 EXPORT_SYMBOL(proc_net);
 EXPORT_SYMBOL(proc_bus);
 EXPORT_SYMBOL(proc_root_driver);
+
+EXPORT_SYMBOL(proc_ov_get_entry);
+EXPORT_SYMBOL(proc_ov_register_string);
+EXPORT_SYMBOL(proc_ov_register_int);
+EXPORT_SYMBOL(proc_ov_register_enum);
+EXPORT_SYMBOL(proc_ov_register_dir);
+EXPORT_SYMBOL(proc_ov_register_dynamic_dir);
+EXPORT_SYMBOL(proc_ov_remove);
diff -Nur linux-2.4.7/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.7/include/linux/fs.h	Sat Jul 21 10:58:22 2001
+++ linux/include/linux/fs.h	Sat Jul 21 11:56:11 2001
@@ -482,6 +482,7 @@
 		struct udf_inode_info		udf_i;
 		struct ncp_inode_info		ncpfs_i;
 		struct proc_inode_info		proc_i;
+		struct proc_ov_inode_info       proc_ov_i;
 		struct socket			socket_i;
 		struct usbdev_inode_info        usbdev_i;
 		void				*generic_ip;
diff -Nur linux-2.4.7/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- linux-2.4.7/include/linux/proc_fs.h	Sat Jul 21 10:58:22 2001
+++ linux/include/linux/proc_fs.h	Sat Jul 21 11:56:11 2001
@@ -24,11 +24,17 @@
 
 /* Finally, the dynamically allocatable proc entries are reserved: */
 
-#define PROC_DYNAMIC_FIRST 4096
-#define PROC_NDYNAMIC      4096
+#define PROC_DYNAMIC_FIRST 0x10000000
+#define PROC_NDYNAMIC      0x0fffffff
 
 #define PROC_SUPER_MAGIC 0x9fa0
 
+/* buffer size is one page but our output routines use some slack for overruns */
+#define PROC_BLOCK_SIZE	(PAGE_SIZE - 1024)
+
+/* Maximum number of stacked contexts */
+#define PROC_OV_MAX_CONTEXT_DEPTH 16
+
 /*
  * This is not completely implemented yet. The idea is to
  * create an in-memory tree (like the actual /proc filesystem
@@ -50,8 +56,84 @@
 			   unsigned long count, void *data);
 typedef int (get_info_t)(char *, char **, off_t, int);
 
+
+/*
+ * These callbacks can be registered using proc_ov_register_(string|int|enum)
+ * and write the content of a single file in the /proc hierarchy. As the files
+ * can be contained in dynamic directories and to avoid duplicate code each
+ * functions gets a context that can help it to generate the content. The
+ * context is set by the callbacks of the proc_ov_register_dir() and
+ * proc_ov_register_dynamic_dir(), in a normal static directory that has been 
+ * created by create_proc_entry() function the context is NULL. The callbacks
+ * must be prepared that the context can be NULL (because of race conditions). 
+ * If it is and they dont expect the NULL they should return an error code.
+ * All functions must return a positive value for success or a negative error 
+ * code. They will be called in user context.
+ * 
+ * - proc_ov_get_string_t writes a string into buf. The size of the buffer is 
+ *   PROC_BLOC_SIZE. The return value is the length of the string.
+ * - proc_ov_get_int_t writes a single integer value to the buffer.
+ * - proc_ov_get_ulong_t writes a unsigned long value to the buffer.
+ * - proc_ov_get_enum_t writes the integer index of one of the string that have 
+ *   been specified by proc_ov_register_enum().
+ */
+typedef int (proc_ov_get_string_t)(char *buf, 
+				   void *context,
+				   void *data);
+typedef int (proc_ov_get_int_t)(int *value, 
+				void *context,
+				void *data);
+typedef int (proc_ov_get_ulong_t)(unsigned long *value, 
+				  void *context,
+				  void *data);
+typedef int (proc_ov_get_enum_t)(int *value, 
+				 void *context,
+				 void *data);
+
+/*
+ * These callbacks create the context for the proc_ov_get_* functions and
+ * the names of the subdirectories of a dynamic directory.
+ * They will be called in user context.
+ * 
+ * - proc_ov_dir_enter_t returns the context of a directory. The argument 
+ *   old_config is the context of the parent director (NULL if there is no
+ *   parent directory) The function can also be used for acquire locks.
+ *
+ * - proc_ov_dir_leave_t is called when a directory is left. The argument
+ *   old_config contains the context of the parent context, new_context
+ *   contains the context created by the matching proc_ov_dir_enter_t or 
+ *   proc_ov_dir_context_t. 
+ *
+ * - proc_ov_dir_num_t is called in dynamic directories and returns the 
+ *   number of subdirectories.
+ *
+ * - proc_ov_dir_name_t writes the name of the directory with the given 
+ *   index into the given buffer (size: NAME_MAX) and returns the length
+ *   of the string, or a negative value for failure. Must be prepared
+ *   that index may be out-of-range, and then return an error.
+ *
+ * - proc_ov_dir_context_t returns the context of the directory with the 
+ *   given index or NULL for failure.Must be prepared that index may be 
+ *   out-of-range, and then return NULL.
+ */
+typedef void *(proc_ov_dir_enter_t)(void *old_context,
+				    void *data);
+typedef void (proc_ov_dir_leave_t)(void *old_context,
+				   void *new_context,
+				   void *data);
+
+typedef int (proc_ov_dir_num_t)(void *context,
+				void *data);
+typedef int (proc_ov_dir_name_t)(int index,
+				 void *context,
+				 void *data,
+				 char *name_buf);
+typedef void *(proc_ov_dir_context_t)(int index,
+				      void *old_context,
+				      void *data);
+
 struct proc_dir_entry {
-	unsigned short low_ino;
+	unsigned int low_ino;
 	unsigned short namelen;
 	const char *name;
 	mode_t mode;
@@ -64,15 +146,64 @@
 	get_info_t *get_info;
 	struct module *owner;
 	struct proc_dir_entry *next, *parent, *subdir;
+	struct proc_ov_dynamic_dir *dyndir;
 	void *data;
 	read_proc_t *read_proc;
 	write_proc_t *write_proc;
 	atomic_t count;		/* use count */
 	int deleted;		/* delete flag */
 	kdev_t	rdev;
+	enum {
+		PROC_STATIC_ENTRY = 0,
+		PROC_OV_DIR,
+		PROC_OV_DYNAMIC_DIR,
+		PROC_OV_STRING,
+		PROC_OV_INT,
+		PROC_OV_ULONG,
+		PROC_OV_ENUM
+	} type;
+};
+
+struct proc_ov_dir {
+	struct proc_dir_entry super;
+	proc_ov_dir_enter_t *enter;
+	proc_ov_dir_leave_t *leave;
+	int ino_space;
+};
+
+struct proc_ov_dynamic_dir {
+	struct proc_dir_entry super;
+	proc_ov_dir_context_t *get_context;
+	proc_ov_dir_leave_t *leave; 
+	proc_ov_dir_num_t *get_num;
+	proc_ov_dir_name_t *get_name;
+	int max_size;
+	int ino_space;
 };
 
-#define PROC_INODE_PROPER(inode) ((inode)->i_ino & ~0xffff)
+struct proc_ov_value_string {
+	struct proc_dir_entry super;
+	proc_ov_get_string_t *get_string;
+};
+
+struct proc_ov_value_int {
+	struct proc_dir_entry super;
+	proc_ov_get_int_t *get_int;
+};
+
+struct proc_ov_value_ulong {
+	struct proc_dir_entry super;
+	proc_ov_get_ulong_t *get_ulong;
+};
+
+struct proc_ov_value_enum {
+	struct proc_dir_entry super;
+	proc_ov_get_enum_t *get_enum;
+	const char **enum_values;
+};
+
+#define PROC_INODE_PROPER(inode) (((inode)->i_ino > 0xfff) && \
+                                  ((inode)->i_ino < PROC_DYNAMIC_FIRST))
 
 #ifdef CONFIG_PROC_FS
 
@@ -84,6 +215,7 @@
 extern struct proc_dir_entry *proc_root_kcore;
 
 extern void proc_root_init(void);
+extern void proc_generic_init(void);
 extern void proc_misc_init(void);
 
 struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry);
@@ -96,7 +228,7 @@
 
 extern struct vfsmount *proc_mnt;
 extern struct super_block *proc_read_super(struct super_block *,void *,int);
-extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *);
+extern struct inode * proc_get_inode(struct super_block *, unsigned int, struct proc_dir_entry *);
 
 extern int proc_match(int, const char *,struct proc_dir_entry *);
 
@@ -115,6 +247,57 @@
 extern struct file_operations ppc_htab_operations;
 
 /*
+ * onevalue.c
+ */
+extern struct proc_dir_entry *
+proc_ov_get_entry(const char *path);
+
+extern struct proc_dir_entry *
+proc_ov_register_string(struct proc_dir_entry *parent, 
+			const char *name,
+			proc_ov_get_string_t *cb);
+
+extern struct proc_dir_entry *
+proc_ov_register_int(struct proc_dir_entry *parent, 
+		     const char *name,
+		     proc_ov_get_int_t *cb);
+
+extern struct proc_dir_entry *
+proc_ov_register_ulong(struct proc_dir_entry *parent, 
+		       const char *name,
+		       proc_ov_get_ulong_t *cb);
+
+extern struct proc_dir_entry *
+proc_ov_register_enum(struct proc_dir_entry *parent, 
+		      const char *name,
+		      const char **enum_values,
+		      proc_ov_get_enum_t *cb);
+
+extern struct proc_dir_entry * 
+proc_ov_register_dir(struct proc_dir_entry *parent, 
+		     const char *name,
+		     proc_ov_dir_enter_t *denter,
+		     proc_ov_dir_leave_t *dleave);
+
+extern struct proc_dir_entry *
+proc_ov_register_dynamic_dir(struct proc_dir_entry *parent,
+			     unsigned int size, 
+			     proc_ov_dir_num_t *dnum,
+			     proc_ov_dir_name_t *dname,
+			     proc_ov_dir_context_t *denter,
+			     proc_ov_dir_leave_t *dleave);
+
+extern void proc_ov_remove(struct proc_dir_entry *e);
+
+/*
+ * helper from generic.c for onevalue.c
+ */
+extern int proc_init_dyn_dir(struct proc_dir_entry *, unsigned int);
+extern struct proc_dir_entry *
+create_proc_entry_common(const char *, mode_t, int, struct proc_dir_entry *, unsigned int);
+extern void proc_unregister_entry(struct proc_dir_entry *);
+
+/*
  * proc_tty.c
  */
 struct tty_driver;
@@ -200,6 +383,31 @@
 static inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
 
 extern struct proc_dir_entry proc_root;
+
+static inline struct proc_dir_entry *proc_ov_get_entry(const char *path) 
+{ return NULL; }
+static inline struct proc_dir_entry *proc_ov_register_string(
+	struct proc_dir_entry *parent, const char *name, 
+	proc_ov_get_string_t *cb) { return NULL; }
+static inline struct proc_dir_entry *proc_ov_register_int(
+	struct proc_dir_entry *parent, const char *name, 
+	proc_ov_get_int_t *cb) { return NULL; }
+static inline struct proc_dir_entry *proc_ov_register_ulong(
+	struct proc_dir_entry *parent, const char *name, 
+	proc_ov_get_ulong_t *cb) { return NULL; }
+static inline struct proc_dir_entry *proc_ov_register_enum(
+	struct proc_dir_entry *parent, const char *name, 
+	const char **enum_values, proc_ov_get_enum_t *cb) { return NULL; }
+static inline struct proc_dir_entry *proc_ov_register_dir(
+	struct proc_dir_entry *parent, const char *name, 
+	proc_ov_dir_enter_t *denter, proc_ov_dir_leave_t *dleave)
+{ return NULL; }
+static inline struct proc_dir_entry *proc_ov_register_dynamic_dir(
+	struct proc_dir_entry *parent, unsigned int size, 
+	proc_ov_dir_num_t *dnum, proc_ov_dir_name_t *dmatch, 
+	proc_ov_dir_context_t *denter, proc_ov_dir_leave_t *dleave) 
+{ return NULL; }
+static inline void proc_ov_remove(struct proc_dir_entry *e) {}
 
 #endif /* CONFIG_PROC_FS */
 
diff -Nur linux-2.4.7/include/linux/proc_fs_i.h linux/include/linux/proc_fs_i.h
--- linux-2.4.7/include/linux/proc_fs_i.h	Sat Jul 21 10:58:22 2001
+++ linux/include/linux/proc_fs_i.h	Mon Jun  4 17:10:39 2001
@@ -7,3 +7,12 @@
 	} op;
 	struct file *file;
 };
+
+struct proc_ov_inode_info {
+	/* entry must be first so it is exchangable with inode's generic_ip */
+	struct proc_dir_entry *entry;
+        /* directory index for dynamic dirs or negative for all others */
+	int dir_index; 
+	/* inode index for children*/
+	unsigned int inode_index;
+};
