diff -Nur linux-2.4.4/fs/proc/Makefile linux/fs/proc/Makefile
--- linux-2.4.4/fs/proc/Makefile	Mon May 14 17:31:03 2001
+++ linux/fs/proc/Makefile	Mon May 14 20:40:40 2001
@@ -11,7 +11,7 @@
 
 export-objs := procfs_syms.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 procfs_syms.o
 
 ifeq ($(CONFIG_PROC_DEVICETREE),y)
diff -Nur linux-2.4.4/fs/proc/generic.c linux/fs/proc/generic.c
--- linux-2.4.4/fs/proc/generic.c	Mon May 14 17:31:03 2001
+++ linux/fs/proc/generic.c	Mon May 14 18:22:24 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;
+	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,74 @@
 	return !memcmp(name, de->name, len);
 }
 
+static void *enter_context(const struct dentry *dentry,
+			   void **context_stack) 
+{
+	void *c;
+	struct proc_dir_entry *pde;
+
+	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;
+	}
+
+	if (dentry->d_parent) {
+		c = enter_context(dentry->d_parent,
+				  context_stack + 1);
+	} else {
+		c = NULL;
+		*(context_stack+1) = NULL;
+	}
+
+	if (pde->type == PROC_OV_DIR) {
+		struct proc_ov_dir *ov = (struct proc_ov_dir *) pde;
+		if (ov->enter) 
+			c = ov->enter(c);
+	}
+	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);
+	}
+
+	*context_stack = c;
+	return c;
+}
+
+static void leave_context(const struct dentry *dentry,
+			  void **context_stack) 
+{
+	struct proc_dir_entry *pde;
+	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);
+	}
+	else {
+		struct proc_ov_dynamic_dir *ov = 
+			(struct proc_ov_dynamic_dir *) pde;
+		if (ov->leave)
+			ov->leave(context_stack[1], *context_stack);
+	}
+
+        if (dentry->d_parent) 
+                leave_context(dentry->d_parent, context_stack+1);
+}
+
+
 static struct file_operations proc_file_operations = {
 	llseek:		proc_file_lseek,
 	read:		proc_file_read,
@@ -43,9 +123,6 @@
 #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_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
 {
@@ -56,10 +133,12 @@
 	ssize_t	n, count;
 	char	*start;
 	struct proc_dir_entry * dp;
+	void *context_stack[CONTEXT_STACK_SIZE];
 
-	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,6 +156,47 @@
 		} else if (dp->read_proc) {
 			n = dp->read_proc(page, &start, *ppos,
 					  count, &eof, dp->data);
+		} else if (dp->type != PROC_STATIC_ENTRY) {
+			struct proc_ov_value_enum *ove;
+			void *context;
+			int value, r;
+			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);
+				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);
+				if (r >= 0)
+					n = sprintf(page, "%d\n", value);
+				break;
+			case PROC_OV_ENUM:
+				ove = (struct proc_ov_value_enum*)dp;
+				r = ove->get_enum(&value, context);
+				if (r >= 0) {
+					strcpy(page, ove->enum_values[value]);
+					n = strlen(page) + 1;
+					page[n-1] = '\n';
+					page[n] = 0;
+				}
+				break;
+			default:
+				r = -EISDIR;
+			}
+			start = NULL;
+			leave_context(file->f_dentry->d_parent, context_stack);
+			if (r < 0) {
+				retval = r;
+				break;
+			}
 		} else
 			break;
 
@@ -127,7 +247,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 +282,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,26 +311,112 @@
 	return 0;
 }
 
-static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8];
 
-static int make_inode_number(void)
+
+static int allocate_inode_range(int n) 
+{
+	struct list_head *pos;
+	struct list_head h;
+	struct inode_range *r, *prev, *next;
+	int i = -1;
+
+	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;
+	}
+
+	if (i < 0)
+		printk(KERN_ERR "proc: out of inodes\n");
+	return i;
+}
+
+static struct list_head *_prepend_inode_range(struct list_head *l, 
+					      int ino, 
+					      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(int ino, int n) 
 {
-	int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
-	if (i<0 || i>=PROC_NDYNAMIC) 
+	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;
-	set_bit(i, (void *) proc_alloc_map);
-	return PROC_DYNAMIC_FIRST + i;
+
+	_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);
 }
 
@@ -234,6 +441,100 @@
 	d_delete:	proc_delete_dentry,
 };
 
+static 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 int get_ino_index(struct inode *parent_inode, 
+			 struct proc_dir_entry *de,
+			 int index) 
+{
+	int ino;
+	if (de->type == PROC_STATIC_ENTRY)
+		return 0;
+	ino = parent_inode->u.proc_ov_i.inode_index;
+	if (ino < 0)
+		return 0;
+	
+	if (de->parent->type == PROC_OV_DYNAMIC_DIR)
+		ino += ((struct proc_ov_dynamic_dir *)de->parent)->max_size * 
+			index;
+	return ino;
+}
+
+static struct inode *_lookup_static_inode(struct proc_dir_entry *de,
+					  struct inode *dir,
+					  struct dentry *dentry,
+					  int *error) 
+{
+	struct inode *inode = NULL;
+	int ino;
+	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)) {
+			*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;
+			break;
+		}
+	}
+	return inode;
+}
+
+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;
+	void *context_stack[CONTEXT_STACK_SIZE];
+	void *context;
+	char namebuf[NAME_MAX];
+	int ino, i, nlen, n;
+
+	ov = de->dyndir;
+	if (!ov)
+		return NULL;
+
+	context = enter_context(dentry->d_parent, context_stack);
+	while (ov) {
+		n = ov->get_num(context);
+		for (i = 0; i < n; i++) {
+			nlen = ov->get_name(i, context, namebuf);
+			if ((nlen != dentry->d_name.len) || 
+			    strcmp(dentry->d_name.name, namebuf)) 
+				continue;
+			
+			*error = -EINVAL;
+			ino = get_ino_index(dir, &ov->super, i);
+			inode = proc_get_inode(dir->i_sb, 
+					       ino + ov->super.low_ino, 
+					       ov);
+			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.
@@ -241,26 +542,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;
@@ -270,6 +563,71 @@
 	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);
+		for (j = *skip; j < n; j++) {
+			l = de->get_name(j, context, namebuf);
+			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
@@ -282,13 +640,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;
@@ -308,24 +666,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;
 }
@@ -347,13 +702,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, int ino_space)
 {
-	int	i;
-	
-	i = make_inode_number();
+	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,
+			     int inos)
+{
+	int i = allocate_inode_range(inos);
 	if (i < 0)
 		return -EAGAIN;
+
 	dp->low_ino = i;
 	dp->next = dir->subdir;
 	dp->parent = dir;
@@ -374,6 +741,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..
  */
@@ -397,7 +769,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;
@@ -405,6 +777,9 @@
 	file_list_unlock();
 }
 
+/*
+ * 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)
 {
@@ -438,6 +813,9 @@
 	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)
 {
@@ -466,6 +844,9 @@
 	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 = NULL;
@@ -494,8 +875,14 @@
 	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,
+						int inos)
 {
 	struct proc_dir_entry *ent = NULL;
 	const char *fn = name;
@@ -505,12 +892,12 @@
 		goto out;
 	len = strlen(fn);
 
-	ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
+	ent = kmalloc(structlen + len + 1, GFP_KERNEL);
 	if (!ent)
 		goto out;
-	memset(ent, 0, sizeof(struct proc_dir_entry));
-	memcpy(((char *) ent) + sizeof(*ent), fn, len + 1);
-	ent->name = ((char *) ent) + sizeof(*ent);
+	memset(ent, 0, structlen);
+	memcpy(((char *) ent) + structlen, fn, len + 1);
+	ent->name = ((char *) ent) + structlen;
 	ent->namelen = len;
 
 	if (S_ISDIR(mode)) {
@@ -528,27 +915,52 @@
 	}
 	ent->mode = mode;
 
-	proc_register(parent, ent);
+	proc_register_ino(parent, ent, inos);
 	
 out:
 	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, 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)
 {
@@ -566,21 +978,22 @@
 		de = *p;
 		*p = de->next;
 		de->next = NULL;
-		if (S_ISDIR(de->mode))
-			parent->nlink--;
-		clear_bit(de->low_ino-PROC_DYNAMIC_FIRST,
-				(void *) 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.4/fs/proc/inode.c linux/fs/proc/inode.c
--- linux-2.4.4/fs/proc/inode.c	Mon May 14 17:31:03 2001
+++ linux/fs/proc/inode.c	Mon May 14 18:01:48 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);
 	}
 }
 
@@ -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.4/fs/proc/onevalue.c linux/fs/proc/onevalue.c
--- linux-2.4.4/fs/proc/onevalue.c	Thu Jan  1 01:00:00 1970
+++ linux/fs/proc/onevalue.c	Mon May 14 19:45:59 2001
@@ -0,0 +1,296 @@
+/*
+ * 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.
+ * 
+ * Returns a pointer to the created struct proc_dir_entry, or %NULL if 
+ * the creation failed or CONFIG_PROC_FS is not selected.
+ */
+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.
+ * 
+ * Returns a pointer to the created struct proc_dir_entry, or %NULL if 
+ * the creation failed or CONFIG_PROC_FS is not selected.
+ */
+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_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.
+ * @cb: The callback function to generate the file's value.
+ * 
+ * Returns a pointer to the created struct proc_dir_entry, or %NULL if 
+ * the creation failed or CONFIG_PROC_FS is not selected.
+ */
+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 is not selected.
+ */
+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;
+
+	if (!parent)
+		parent = &proc_root;
+
+	ov = (struct proc_ov_dir*) 
+		create_proc_entry_common(name, 
+					 S_IFDIR | S_IRUGO | S_IXUGO, 
+					 sizeof(struct proc_ov_dir),
+					 parent,
+					 _get_ino_space(parent));
+	if (!ov)
+		return NULL;
+
+	ov->super.type = PROC_OV_DIR;
+	ov->enter = denter;
+	ov->leave = dleave;
+	ov->ino_space = _get_ino_space(parent);
+	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
+ * @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 is not selected.
+ */
+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 = 3;
+	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;
+}
+
+/*
+ * proc_ov_register_remove - Removes the given entry. Does not work 
+ * recursively.
+ *
+ * @e: The entry to remove.
+ */
+void proc_ov_remove(struct proc_dir_entry *e)
+{
+	struct proc_dir_entry **i = NULL;
+
+	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.4/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c
--- linux-2.4.4/fs/proc/procfs_syms.c	Mon May 14 17:31:03 2001
+++ linux/fs/proc/procfs_syms.c	Tue May  1 17:50:25 2001
@@ -20,6 +20,14 @@
 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);
+
 static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, FS_SINGLE);
 
 static int __init init_proc_fs(void)
diff -Nur linux-2.4.4/fs/proc/root.c linux/fs/proc/root.c
--- linux-2.4.4/fs/proc/root.c	Mon May 14 17:31:03 2001
+++ linux/fs/proc/root.c	Fri May 11 16:15:33 2001
@@ -24,6 +24,7 @@
 
 void __init proc_root_init(void)
 {
+	proc_generic_init();
 	proc_misc_init();
 	proc_net = proc_mkdir("net", 0);
 #ifdef CONFIG_SYSVIPC
diff -ur linux-2.4.4/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.4/include/linux/fs.h	Mon May 14 17:31:10 2001
+++ linux/include/linux/fs.h	Mon May 14 20:10:07 2001
@@ -459,6 +459,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 -ur linux-2.4.4/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- linux-2.4.4/include/linux/proc_fs.h	Mon May 14 17:31:10 2001
+++ linux/include/linux/proc_fs.h	Mon May 14 20:10:07 2001
@@ -25,10 +25,16 @@
 /* Finally, the dynamically allocatable proc entries are reserved: */
 
 #define PROC_DYNAMIC_FIRST 4096
-#define PROC_NDYNAMIC      4096
+#define PROC_NDYNAMIC      0x7fffefff
 
 #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,7 +56,80 @@
 			   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_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);
+typedef int (proc_ov_get_int_t)(int *value, 
+				void *context);
+typedef int (proc_ov_get_enum_t)(int *value, 
+				 void *context);
+
+/*
+ * 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);
+typedef void (proc_ov_dir_leave_t)(void *old_context,
+				   void *new_context);
+
+typedef int (proc_ov_dir_num_t)(void *context);
+typedef int (proc_ov_dir_name_t)(int index,
+				 void *context,
+				 char *name_buf);
+typedef void *(proc_ov_dir_context_t)(int index,
+				      void *old_context);
+
 struct proc_dir_entry {
+	enum {
+		PROC_STATIC_ENTRY = 0,
+		PROC_OV_DIR,
+		PROC_OV_DYNAMIC_DIR,
+		PROC_OV_STRING,
+		PROC_OV_INT,
+		PROC_OV_ENUM
+	} type;
 	unsigned short low_ino;
 	unsigned short namelen;
 	const char *name;
@@ -64,6 +143,7 @@
 	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;
@@ -72,6 +152,39 @@
 	kdev_t	rdev;
 };
 
+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;
+};
+
+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_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 & ~0xffff)
 
 #ifdef CONFIG_PROC_FS
@@ -84,6 +197,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);
@@ -115,6 +229,52 @@
 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_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 *dmatch,
+			     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 *, int);
+extern struct proc_dir_entry *
+create_proc_entry_common(const char *, mode_t, int, struct proc_dir_entry *, int);
+extern void proc_unregister_entry(struct proc_dir_entry *);
+
+/*
  * proc_tty.c
  */
 struct tty_driver;
@@ -193,6 +353,28 @@
 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_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 -ur linux-2.4.4/include/linux/proc_fs_i.h linux/include/linux/proc_fs_i.h
--- linux-2.4.4/include/linux/proc_fs_i.h	Mon May 14 17:31:14 2001
+++ linux/include/linux/proc_fs_i.h	Fri May 11 15:36:38 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*/
+	int inode_index;
+};
