linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] 2.5 PROPOSAL: Replacement for current /proc of shit.
@ 2001-11-01 10:32 Rusty Russell
  2001-11-01 10:42 ` Jeff Garzik
                   ` (3 more replies)
  0 siblings, 4 replies; 258+ messages in thread
From: Rusty Russell @ 2001-11-01 10:32 UTC (permalink / raw)
  To: linux-kernel

[Sorry: been wanting to use that phrase here for the longest time]

	This proof-of-concept implementation is pretty poor but the
principle (and interface) is simple:

	int my_foo;

	static int __init initfn(void)
	{
		return proc("net", "foo", my_foo, int, 0644);
	}

	static void __exit exitfn(void)
	{
		unproc("net", "foo");
	}

No kernel-formatted tables: use a directory.  (eg. kernel symbols
become a directory of symbol names, each containing the symbol value).

For cases when you don't want to take the overhead of creating a new
proc entry (eg. tcp socket creation), you can create directories on
demand when a user reads them using:

	proc_dir("net", "subdir", dirfunc, NULL);
	unproc_dir("net", "subdir");

Note that with kbuild 2.5, you can do something like:

	proc(KBUILD_OBJECT, "foo", my_foo, int, 0644);

And with my previous parameter patch:
	PARAM(foo, int, 0444);

declares a boot time parameter "KBUILD_OBJECT.foo=", or a module
parameter "foo=", and places it as readable in
/proc/KBUILD_OBJECT/foo.

I believe that rewriting /proc (and /proc/sys should simply die) is a
better solution than extending the interface, or avoiding it
altogether by using a new filesystem.

Of course, I don't care if it's *NOT* under /proc...
Rusty.
--
Premature optmztion is rt of all evl. --DK

diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.4.13-uml/include/linux/simpleproc.h working-2.4.13-uml-proc/include/linux/simpleproc.h
--- linux-2.4.13-uml/include/linux/simpleproc.h	Thu Jan  1 10:00:00 1970
+++ working-2.4.13-uml-proc/include/linux/simpleproc.h	Thu Nov  1 20:17:42 2001
@@ -0,0 +1,206 @@
+/* Dynamic proc filesystem that doesn't suck.  (C) 2001 Rusty Russell. */
+#ifndef _LINUX_SIMPLE_PROC_H
+#define _LINUX_SIMPLE_PROC_H
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+
+/* Commit the contents of this (NUL-terminated) buffer if possible.
+   -errno indicates error. */
+typedef int (proc_commitfn_t)(const char *dirname,
+			      const char *filename,
+			      const char *buffer,
+			      unsigned int size,
+			      void *arg);
+/* Fetch the contents into buffer: return size used (or needed), or
+   -errno. */
+typedef int (proc_fetchfn_t)(const char *dirname,
+			     const char *filename,
+			     char *buffer,
+			     unsigned int size,
+			     void *arg);
+
+/* If we're a dynamic directory, this routine gets dir contents:
+   returns size used (or needed), or -errno. */
+struct proc_dircontents;
+typedef int (proc_dirfn_t)(const char *dirname,
+			   const char *filename,
+			   struct proc_dircontents *buffer,
+			   unsigned int maxlen,
+			   void *arg);
+
+/* Register a proc entry of the given type. */
+#define proc(dir, fname, var, type, perms)				 \
+	__proc(dir, fname, S_IFREG|(perms),				 \
+	       __new_proc(&var,						 \
+			  ((perms)&S_IRUGO) ? proc_fetch_##type : NULL,	 \
+			  ((perms)&S_IWUGO) ? proc_commit_##type : NULL, \
+			  NULL))
+
+/* Register a proc entry protected by a spinlock. */
+#define proc_spinlock(dir, fname, var, type, lock, p)			   \
+	__proc(dir, fname, S_IFREG|(p),					   \
+	       __new_proc_lock(&var, lock,				   \
+			       ((p)&S_IRUGO) ? proc_fetch_##type : NULL,   \
+			       ((p)&S_IWUGO) ? proc_commit_##type : NULL))
+
+/* Register a proc entry protected by a semaphore. */
+#define proc_sem(dir, fname, var, type, sem, p)				  \
+	__proc(dir, fname, S_IFREG|(p),					  \
+	       __new_proc_sem(&var, sem,				  \
+			      ((p)&S_IRUGO) ? proc_fetch_##type : NULL,	  \
+			      ((p)&S_IWUGO) ? proc_commit_##type : NULL))
+
+/* These exist, believe me */
+struct semaphore;
+struct proc_data;
+
+#ifdef CONFIG_SIMPLE_PROC_FS
+/* Low level functions */
+int __proc(const char *dirname, const char *fname, int mode,
+	   struct proc_data *pdata);
+struct proc_data *__new_proc(void *arg, proc_fetchfn_t *, proc_commitfn_t *,
+			     proc_dirfn_t *);
+struct proc_data *__new_proc_lock(void *arg, spinlock_t *lock,
+				  proc_fetchfn_t *, proc_commitfn_t *);
+struct proc_data *__new_proc_sem(void *arg, struct semaphore *sem,
+				 proc_fetchfn_t *, proc_commitfn_t *);
+
+/* Register a whole dynamic directory */
+static inline int proc_dir(const char *dir, const char *dirname,
+			   proc_dirfn_t *dirfunc, void *arg)
+{
+	return __proc(dir, dirname, S_IFDIR|0555, 
+		      __new_proc(arg, NULL, NULL, dirfunc));
+}
+
+/* Release a dynamic proc directory */
+void unproc_dir(const char *dir, const char *fname);
+
+/* Release a proc entry */
+void unproc(const char *dir, const char *fname);
+
+#else
+static inline int proc_dir(const char *dir, const char *dirname,
+			   proc_dirfn_t *dirfunc, void *arg)
+{
+	return 0;
+}
+
+static inline void unproc(const char *dir, const char *fname)
+{
+}
+
+static inline void unproc_dir(const char *dir, const char *fname)
+{
+}
+
+static inline int __proc(const char *dirname, const char *fname, int mode,
+			 struct proc_data *pdata)
+{
+	return 0;
+}
+
+struct proc_data *__new_proc(void *arg,
+			     proc_fetchfn_t *fetch,
+			     proc_commitfn_t *commit,
+			     proc_dirfn_t *dir)
+{
+	return (struct proc_data *)-1;
+}
+struct proc_data *__new_proc_lock(void *arg, spinlock_t *lock,
+				  proc_fetchfn_t *fetch,
+				  proc_commitfn_t *commit)
+{
+	return (struct proc_data *)-1;
+}
+struct proc_data *__new_proc_sem(void *arg, struct semaphore *sem,
+				 proc_fetchfn_t *fetch,
+				 proc_commitfn_t *commit)
+{
+	return (struct proc_data *)-1;
+}
+#endif /*CONFIG_PROC_FS*/
+
+/* Helper parsing routines.  You can write your own, too. */
+proc_fetchfn_t proc_fetch_short;
+proc_fetchfn_t proc_fetch_ushort;
+proc_fetchfn_t proc_fetch_int;
+proc_fetchfn_t proc_fetch_uint;
+proc_fetchfn_t proc_fetch_long;
+proc_fetchfn_t proc_fetch_ulong;
+proc_fetchfn_t proc_fetch_bool;
+
+proc_commitfn_t proc_commit_short;
+proc_commitfn_t proc_commit_ushort;
+proc_commitfn_t proc_commit_int;
+proc_commitfn_t proc_commit_uint;
+proc_commitfn_t proc_commit_long;
+proc_commitfn_t proc_commit_ulong;
+proc_commitfn_t proc_commit_bool;
+
+/* Filled in by dir functions */
+struct proc_dircontents
+{
+	/* Mode of file.  0 terminates list. */
+	int mode;
+
+	/* Fetch, commit and dir functions for entry. */
+	proc_fetchfn_t *fetch;
+	proc_commitfn_t *commit;
+	proc_dirfn_t *dir;
+
+	/* Arg */
+	void *arg;
+
+	/* Name is nul-terminated, and padded to alignof this struct */
+	char name[0];
+};
+
+/* Helper to add another dircontents to the list, return updated "used" */
+static inline unsigned int proc_add_dircontents(struct proc_dircontents *pd,
+						unsigned int used,
+						unsigned int maxlen,
+						int mode,
+						proc_fetchfn_t *fetch,
+						proc_commitfn_t *commit,
+						proc_dirfn_t *dir,
+						void *arg,
+						const char *name)
+{
+	unsigned int thislen;
+
+	thislen = sizeof(*pd) + strlen(name) + 1;
+	thislen = (thislen + __alignof__(*pd) - 1) & ~(__alignof__(*pd) - 1);
+	if (used + thislen <= maxlen) {
+		pd = (void *)pd + used;
+		pd->mode = mode;
+		pd->fetch = fetch;
+		pd->commit = commit;
+		pd->dir = dir;
+		pd->arg = arg;
+		strcpy(pd->name, name);
+	}
+	return used + thislen;
+}
+
+static inline unsigned int proc_end_dircontents(struct proc_dircontents *pd,
+						unsigned int used,
+						unsigned int maxlen)
+{
+	return proc_add_dircontents(pd, used, maxlen, 0,
+				    NULL, NULL, NULL, NULL, "");
+}
+
+/* Internal use */
+struct proc_data
+{
+	/* User-defined argument for routines */
+	void *arg;
+
+	proc_dirfn_t *dir;
+	proc_commitfn_t *commit;
+	proc_fetchfn_t *fetch;
+};
+#endif /* _LINUX_SIMPLE_PROC_H */
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.4.13-uml/fs/Config.in working-2.4.13-uml-proc/fs/Config.in
--- linux-2.4.13-uml/fs/Config.in	Thu Oct 25 11:29:49 2001
+++ working-2.4.13-uml-proc/fs/Config.in	Tue Oct 30 12:47:11 2001
@@ -50,7 +50,10 @@
 
 tristate 'OS/2 HPFS file system support' CONFIG_HPFS_FS
 
-bool '/proc file system support' CONFIG_PROC_FS
+bool 'Simple /proc file system support (EXPERIMENTAL)' CONFIG_SIMPLE_PROC_FS
+if [ "$CONFIG_SIMPLE_PROC_FS" != y ]; then
+   bool '/proc file system support' CONFIG_PROC_FS
+fi
 
 dep_bool '/dev file system support (EXPERIMENTAL)' CONFIG_DEVFS_FS $CONFIG_EXPERIMENTAL
 dep_bool '  Automatically mount at boot' CONFIG_DEVFS_MOUNT $CONFIG_DEVFS_FS
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.4.13-uml/fs/Makefile working-2.4.13-uml-proc/fs/Makefile
--- linux-2.4.13-uml/fs/Makefile	Thu Oct 25 11:29:49 2001
+++ working-2.4.13-uml-proc/fs/Makefile	Tue Oct 30 12:47:11 2001
@@ -23,6 +23,7 @@
 endif
 
 subdir-$(CONFIG_PROC_FS)	+= proc
+subdir-$(CONFIG_SIMPLE_PROC_FS)	+= simpleproc
 subdir-y			+= partitions
 
 # Do not add any filesystems before this line
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.4.13-uml/fs/proc/simple_proc.c working-2.4.13-uml-proc/fs/proc/simple_proc.c
--- linux-2.4.13-uml/fs/proc/simple_proc.c	Thu Jan  1 10:00:00 1970
+++ working-2.4.13-uml-proc/fs/proc/simple_proc.c	Tue Oct 30 12:47:11 2001
@@ -0,0 +1,517 @@
+/* Those of you who read this, give quiet thanks that you did not
+   suffer the endless frustration of dealing with the old /proc
+   interface.
+
+   Copyright (C) 2001 Rusty Russell.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <linux/proc.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+/* Simplistic approach: semaphore protects all proc accesses. */
+static DECLARE_MUTEX(simple_proc_sem);
+
+/* FIXME: Use reference counts and "dead" marker to return -ENOENT if
+   unregistered while open -RR */
+struct proc_data
+{
+	void *arg;
+	int (*get)(void *, char *, int);
+	int (*set)(void *, const char *);
+
+	/* FIXME: Belongs in struct file --RR */
+	int readlen, maxreadlen, writelen, maxwritelen;
+	char *readdata, *writedata;
+};
+
+static int fill_buffer(char **buffer,
+			int *maxlen,
+			struct proc_data *pdata)
+{
+	int len;
+
+	for (;;) {
+		len = pdata->get(pdata->arg, *buffer, *maxlen);
+		/* Need more room? */
+		if (len > *maxlen) {
+			/* We need some restriction here, to avoid
+			   DoS.  fs/proc/generic.c wants this, but we
+			   should make one or two pages eventually. */
+			if (len > PAGE_SIZE - 1024)
+				BUG();
+			kfree(*buffer);
+			*buffer = kmalloc(len, GFP_KERNEL);
+			if (!*buffer) return -ENOMEM;
+			*maxlen = len;
+		} else
+			return len;
+	}
+}
+
+/* FIXME: Get the struct file, and we can use ->private_data to store
+   this per file descriptor, rather than per file --RR */
+static int simple_read(char *page, char **start, off_t off, int count, 
+		       int *eof, void *data)
+{
+	struct proc_data *pdata = data;
+	int ret;
+
+	/* Start of read?  Get fresh buffer */
+	if (off == 0) {
+		int readlen, maxreadlen;
+		char *buffer;
+
+		maxreadlen = pdata->maxreadlen;
+		buffer = kmalloc(maxreadlen, GFP_KERNEL);
+		if (!buffer) {
+			*eof = 1;
+			return -ENOMEM;
+		}
+		readlen = fill_buffer(&buffer, &maxreadlen, pdata);
+		if (readlen < 0) {
+			*eof = 1;
+			kfree(buffer);
+			return readlen;
+		}
+
+		/* Substitute buffer */
+		if (down_interruptible(&simple_proc_sem) != 0) {
+			*eof = 1;
+			kfree(buffer);
+			return -EINTR;
+		}
+		kfree(pdata->readdata);
+		pdata->maxreadlen = maxreadlen;
+		pdata->readlen = readlen;
+		pdata->readdata = buffer;
+		up(&simple_proc_sem);
+	}
+
+	/* Serve from buffer */
+	if (down_interruptible(&simple_proc_sem) != 0) {
+		*eof = 1;
+		return -EINTR;
+	}
+
+	if (off <= pdata->readlen) {
+		ret = pdata->readlen - off;
+		memcpy(page + off, pdata->readdata + off, ret);
+	} else {
+		*eof = 1;
+		ret = 0;
+	}
+	up(&simple_proc_sem);
+
+	return ret;
+}
+
+/* FIXME: Don't share the write buffer: use file->private_data */
+static int simple_write(struct file *file,
+			const char *userbuffer,
+			unsigned long count, 
+			void *data)
+{
+	struct proc_data *pdata = data;
+
+	/* FIXME: commit the write(s) on close or seek.  We don't have
+	   that control under the current proc system, so simply
+	   terminate on \n. --RR */
+	if (file->f_pos + count > pdata->maxwritelen) {
+		char *newbuffer;
+		int newmax = file->f_pos + count;
+
+		/* As in read, we need some limit, and this is from
+                   fs/proc/generic.c */
+		if (newmax > PAGE_SIZE - 1024)
+			return -ENOSPC;
+
+		newbuffer = kmalloc(newmax, GFP_KERNEL);
+		if (!newbuffer)
+			return -ENOMEM;
+
+		/* Substitute buffer */
+		if (down_interruptible(&simple_proc_sem) != 0) {
+			kfree(newbuffer);
+			return -EINTR;
+		}
+		memcpy(newbuffer, pdata->writedata, pdata->writelen);
+		kfree(pdata->writedata);
+		pdata->maxwritelen = newmax;
+		pdata->writedata = newbuffer;
+		up(&simple_proc_sem);
+	}
+
+	/* Copy into buffer */
+	if (down_interruptible(&simple_proc_sem) != 0)
+		return -EINTR;
+
+	if (copy_from_user(pdata->writedata+file->f_pos, userbuffer, count)
+	    != 0) {
+		up(&simple_proc_sem);
+		return -EFAULT;
+	}
+
+	file->f_pos += count;
+
+	/* If there is now a '\n' at the end of the buffer, commit */
+	if (file->f_pos > 0 && pdata->writedata[file->f_pos-1] == '\n') {
+		int set;
+		pdata->writedata[file->f_pos-1] = '\0';
+		set = pdata->set(pdata->arg, pdata->writedata);
+
+		if (set < 0) {
+			up(&simple_proc_sem);
+			return set;
+		}
+	}
+	up(&simple_proc_sem);
+	return count;
+}
+
+/* This implementation serves only as a demonstration. --RR */
+static int do_register(const char *dir,
+		       const char *fname,
+		       int perms,
+		       struct proc_data *pdata)
+{
+	struct proc_dir_entry *entry;
+	char fullpath[strlen(dir) + 1 + strlen(fname) + 1];
+
+	sprintf(fullpath, "%s/%s", dir, fname);
+	entry = create_proc_entry(fullpath, perms, NULL);
+	if (!entry) return -EINVAL; /* -ERANDOM */
+
+	/* Populate data */
+	entry->data = pdata;
+
+	/* Set up read and write callbacks */
+	if (pdata->set) entry->read_proc = &simple_read;
+	if (pdata->get) entry->write_proc = &simple_write;
+	return 0;
+}
+
+int __register_proc(const char *dir,
+		    const char *fname,
+		    void *arg,
+		    unsigned int perms,
+		    int (*get)(void *arg, char *, int),
+		    int (*set)(void *arg, const char *))
+{
+	struct proc_data *pdata;
+	int ret;
+
+	pdata = kmalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+	
+	pdata->arg = arg;
+	pdata->get = get;
+	pdata->set = set;
+	pdata->writelen = pdata->readlen = 0;
+	pdata->readdata = pdata->writedata = NULL;
+
+	ret = do_register(dir, fname, perms, pdata);
+	if (ret < 0)
+		kfree(pdata);
+	return ret;
+}
+
+/* Wrapper for user's real proc functions */
+struct pdata_wrapper
+{
+	struct proc_data pdata;
+	int (*get)(void *, char *, int);
+	int (*set)(void *, const char *);
+	void *lock;
+	void *userarg;
+};
+
+static struct pdata_wrapper *
+new_pdata_wrapper(void *arg,
+		  int (*userget)(void *, char *, int),
+		  int (*userset)(void *, const char *),
+		  int (*wrapperget)(void *, char *, int),
+		  int (*wrapperset)(void *, const char *),
+		  void *lock)
+{
+	struct pdata_wrapper *pwrap;
+
+	pwrap = kmalloc(sizeof(*pwrap), GFP_KERNEL);
+	if (pwrap) {
+		pwrap->pdata.arg = pwrap;
+		pwrap->pdata.writelen = pwrap->pdata.readlen = 0;
+		pwrap->pdata.readdata = pwrap->pdata.writedata = NULL;
+		pwrap->pdata.get = wrapperget;
+		pwrap->pdata.set = wrapperset;
+		pwrap->lock = lock;
+		pwrap->userarg = arg;
+		pwrap->get = userget;
+		pwrap->set = userset;
+	}
+	return pwrap;
+}
+
+static int do_register_wrap(const char *dir,
+			    const char *fname,
+			    int perms,
+			    void *arg,
+			    int (*userget)(void *, char *, int),
+			    int (*userset)(void *, const char *),
+			    int (*wrapperget)(void *, char *, int),
+			    int (*wrapperset)(void *, const char *),
+			    void *lock)
+{
+	struct pdata_wrapper *pwrap;
+	int ret;
+
+	pwrap = new_pdata_wrapper(arg, userget, userset, wrapperget,
+				  wrapperset, lock);
+	if (!pwrap)
+		return -ENOMEM;
+	ret = do_register(dir, fname, perms, &pwrap->pdata);
+	if (ret < 0)
+		kfree(pwrap);
+	return ret;
+}
+
+static int spinlock_get(void *arg, char *buffer, int size)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	spin_lock_irq(pwrap->lock);
+	ret = pwrap->get(pwrap->userarg, buffer, size);
+	spin_unlock_irq(pwrap->lock);
+
+	return ret;
+}
+
+static int spinlock_set(void *arg, const char *buffer)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	spin_lock_irq(pwrap->lock);
+	ret = pwrap->set(pwrap->userarg, buffer);
+	spin_unlock_irq(pwrap->lock);
+
+	return ret;
+}
+
+int __register_proc_spinlock(const char *dir,
+			     const char *fname,
+			     void *arg,
+			     unsigned int perms,
+			     spinlock_t *lock,
+			     int (*get)(void *arg, char *, int),
+			     int (*set)(void *arg, const char *))
+{
+	return do_register_wrap(dir, fname, perms, arg, get, set,
+				spinlock_get, spinlock_set, lock);
+}
+
+static int rwlock_get(void *arg, char *buffer, int size)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	read_lock_irq(pwrap->lock);
+	ret = pwrap->get(pwrap->userarg, buffer, size);
+	read_unlock_irq(pwrap->lock);
+
+	return ret;
+}
+
+static int rwlock_set(void *arg, const char *buffer)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	write_lock_irq(pwrap->lock);
+	ret = pwrap->set(pwrap->userarg, buffer);
+	write_unlock_irq(pwrap->lock);
+
+	return ret;
+}
+
+int __register_proc_rwlock(const char *dir,
+			   const char *fname,
+			   void *arg,
+			   unsigned int perms,
+			   rwlock_t *lock,
+			   int (*get)(void *arg, char *, int),
+			   int (*set)(void *arg, const char *))
+{
+	return do_register_wrap(dir, fname, perms, arg, get, set,
+				rwlock_get, rwlock_set, lock);
+}
+
+static int semaphore_get(void *arg, char *buffer, int size)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	if (down_interruptible(pwrap->lock) != 0)
+		return -EINTR;
+	ret = pwrap->get(pwrap->userarg, buffer, size);
+	up(pwrap->lock);
+
+	return ret;
+}
+
+static int semaphore_set(void *arg, const char *buffer)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	if (down_interruptible(pwrap->lock) != 0)
+		return -EINTR;
+	ret = pwrap->set(pwrap->userarg, buffer);
+	up(pwrap->lock);
+
+	return ret;
+}
+
+int __register_proc_semaphore(const char *dir,
+			      const char *fname,
+			      void *arg,
+			      unsigned int perms,
+			      struct semaphore *lock,
+			      int (*get)(void *arg, char *, int),
+			      int (*set)(void *arg, const char *))
+{
+	return do_register_wrap(dir, fname, perms, arg, get, set,
+				semaphore_get, semaphore_set, lock);
+}
+	
+static int rwsemaphore_get(void *arg, char *buffer, int size)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	down_read(pwrap->lock);
+	ret = pwrap->get(pwrap->userarg, buffer, size);
+	up_read(pwrap->lock);
+
+	return ret;
+}
+
+static int rwsemaphore_set(void *arg, const char *buffer)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	down_write(pwrap->lock);
+	ret = pwrap->set(pwrap->userarg, buffer);
+	up_write(pwrap->lock);
+
+	return ret;
+}
+
+int __register_proc_rwsemaphore(const char *dir,
+				const char *fname,
+				void *arg,
+				unsigned int perms,
+				struct rw_semaphore *lock,
+				int (*get)(void *arg, char *, int),
+				int (*set)(void *arg, const char *))
+{
+	return do_register_wrap(dir, fname, perms, arg, get, set,
+				rwsemaphore_get, rwsemaphore_set, lock);
+}
+
+int __proc_read_short(void *shortp, char *outbuf, int len)
+{
+	return snprintf(outbuf, len, "%hi", *(short *)shortp);
+}
+
+int __proc_write_short(void *shortp, const char *inbuf)
+{
+	if (sscanf(inbuf, "%hi", (short *)shortp) != 1) return -EINVAL;
+	return 0;
+}
+
+int __proc_read_ushort(void *ushortp, char *outbuf, int len)
+{
+	return snprintf(outbuf, len, "%hu", *(unsigned short *)ushortp);
+}
+
+int __proc_write_ushort(void *ushortp, const char *inbuf)
+{
+	if (sscanf(inbuf, "%hu", (unsigned short *)ushortp) != 1)
+		return -EINVAL;
+	return 0;
+}
+
+int __proc_read_int(void *intp, char *outbuf, int len)
+{
+	return snprintf(outbuf, len, "%i", *(int *)intp);
+}
+
+int __proc_write_int(void *intp, const char *inbuf)
+{
+	if (sscanf(inbuf, "%i", (int *)intp) != 1) return -EINVAL;
+	return 0;
+}
+
+int __proc_read_uint(void *uintp, char *outbuf, int len)
+{
+	return snprintf(outbuf, len, "%u", *(unsigned int *)uintp);
+}
+
+int __proc_write_uint(void *uintp, const char *inbuf)
+{
+	if (sscanf(inbuf, "%u", (unsigned int *)uintp) != 1) return -EINVAL;
+	return 0;
+}
+
+int __proc_read_long(void *longp, char *outbuf, int len)
+{
+	return snprintf(outbuf, len, "%li", *(long *)longp);
+}
+
+int __proc_write_long(void *longp, const char *inbuf)
+{
+	if (sscanf(inbuf, "%li", (long *)longp) != 1) return -EINVAL;
+	return 0;
+}
+
+int __proc_read_ulong(void *ulongp, char *outbuf, int len)
+{
+	return snprintf(outbuf, len, "%lu", *(long *)ulongp);
+}
+
+int __proc_write_ulong(void *ulongp, const char *inbuf)
+{
+	if (sscanf(inbuf, "%lu", (unsigned long *)ulongp) != 1) return -EINVAL;
+	return 0;
+}
+
+int __proc_read_bool(void *boolp, char *outbuf, int len)
+{
+	if (*(int *)boolp) return snprintf(outbuf, len, "y");
+	else return snprintf(outbuf, len, "n");
+}
+
+int __proc_write_bool(void *boolp, const char *inbuf)
+{
+	if (inbuf[0] == 'y' || inbuf[0] == 'Y')
+		*(int *)boolp = 1;
+	else if (inbuf[0] == 'n' || inbuf[0] == 'N')
+		*(int *)boolp = 0;
+	else return __proc_write_int(boolp, inbuf);
+	return 0;
+}
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.4.13-uml/fs/simpleproc/Makefile working-2.4.13-uml-proc/fs/simpleproc/Makefile
--- linux-2.4.13-uml/fs/simpleproc/Makefile	Thu Jan  1 10:00:00 1970
+++ working-2.4.13-uml-proc/fs/simpleproc/Makefile	Tue Oct 30 12:47:11 2001
@@ -0,0 +1,14 @@
+#
+# Makefile for the Linux proc filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile.
+
+O_TARGET := simpleproc.o
+
+obj-y    := inode.o helper.o
+
+include $(TOPDIR)/Rules.make
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.4.13-uml/fs/simpleproc/helper.c working-2.4.13-uml-proc/fs/simpleproc/helper.c
--- linux-2.4.13-uml/fs/simpleproc/helper.c	Thu Jan  1 10:00:00 1970
+++ working-2.4.13-uml-proc/fs/simpleproc/helper.c	Thu Nov  1 20:58:13 2001
@@ -0,0 +1,277 @@
+/* Those of you who read this, give quiet thanks that you did not
+   suffer the endless frustration of dealing with the old /proc
+   interface.
+
+   Copyright (C) 2001 Rusty Russell.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <linux/simpleproc.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/dcache.h>
+#include <linux/init.h>
+
+/* Wrapper for user's real proc functions */
+struct pdata_wrapper
+{
+	struct proc_data pdata;
+	proc_fetchfn_t *fetch;
+	proc_commitfn_t *commit;
+	void *lock;
+	void *userarg;
+};
+
+static struct proc_data *new_wrapper(proc_fetchfn_t *userfetch,
+				     proc_commitfn_t *usercommit,
+				     void *userarg,
+				     proc_fetchfn_t *wrapfetch,
+				     proc_commitfn_t *wrapcommit,
+				     void *lock)
+{
+	struct pdata_wrapper *pwrap;
+
+	pwrap = kmalloc(sizeof(*pwrap), GFP_KERNEL);
+	if (pwrap) {
+		pwrap->pdata.arg = pwrap;
+		pwrap->pdata.fetch = wrapfetch;
+		pwrap->pdata.commit = wrapcommit;
+		pwrap->pdata.dir = NULL;
+		pwrap->fetch = userfetch;
+		pwrap->commit = usercommit;
+		pwrap->lock = lock;
+		pwrap->userarg = userarg;
+	}
+	return &pwrap->pdata;
+}
+
+static int lock_fetch(const char *dirname, const char *fname,
+		      char *buffer, unsigned int size, void *arg)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	spin_lock_irq(pwrap->lock);
+	ret = pwrap->fetch(dirname, fname, pwrap->userarg, size, buffer);
+	spin_unlock_irq(pwrap->lock);
+
+	return ret;
+}
+
+static int lock_commit(const char *dirname, const char *fname,
+		       const char *buffer, unsigned int size, void *arg)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	spin_lock_irq(pwrap->lock);
+	ret = pwrap->commit(dirname, fname, buffer, size, pwrap->userarg);
+	spin_unlock_irq(pwrap->lock);
+
+	return ret;
+}
+
+struct proc_data *__new_proc_lock(void *arg, spinlock_t *lock,
+				  proc_fetchfn_t *fetch,
+				  proc_commitfn_t *commit)
+{
+	return new_wrapper(fetch, commit, arg, lock_fetch, lock_commit, lock);
+}
+
+static int sem_fetch(const char *dirname, const char *fname,
+		     char *buffer, unsigned int size, void *arg)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	if (down_interruptible(pwrap->lock) != 0)
+		return -EINTR;
+	ret = pwrap->fetch(dirname, fname, pwrap->userarg, size, buffer);
+	up(pwrap->lock);
+
+	return ret;
+}
+
+static int sem_commit(const char *dirname, const char *fname,
+		      const char *buffer, unsigned int size, void *arg)
+{
+	struct pdata_wrapper *pwrap = arg;
+	int ret;
+
+	if (down_interruptible(pwrap->lock) != 0)
+		return -EINTR;
+	ret = pwrap->commit(dirname, fname, buffer, size, pwrap->userarg);
+	up(pwrap->lock);
+
+	return ret;
+}
+
+struct proc_data *__new_proc_sem(void *arg, struct semaphore *sem,
+				 proc_fetchfn_t *fetch,
+				 proc_commitfn_t *commit)
+{
+	return new_wrapper(fetch, commit, arg, sem_fetch, sem_commit, sem);
+}
+
+int proc_fetch_short(const char *dir, const char *fname,
+		     char *outbuf, unsigned int size, void *shortp)
+{
+	return snprintf(outbuf, size, "%hi\n", *(short *)shortp);
+}
+
+int proc_commit_short(const char *dir, const char *fname,
+		      const char *inbuf, unsigned int size, void *shortp)
+{
+	if (sscanf(inbuf, "%hi", (short *)shortp) != 1) return -EINVAL;
+	return 0;
+}
+
+int proc_fetch_ushort(const char *dir, const char *fname,
+		      char *outbuf, unsigned int size, void *ushortp)
+{
+	return snprintf(outbuf, size, "%hu\n", *(unsigned short *)ushortp);
+}
+
+int proc_commit_ushort(const char *dir, const char *fname,
+		       const char *inbuf, unsigned int size, void *ushortp)
+{
+	if (sscanf(inbuf, "%hu", (unsigned short *)ushortp) != 1)
+		return -EINVAL;
+	return 0;
+}
+
+int proc_fetch_int(const char *dir, const char *fname,
+		    char *outbuf, unsigned int size, void *intp)
+{
+	return snprintf(outbuf, size, "%i\n", *(int *)intp);
+}
+
+int proc_commit_int(const char *dir, const char *fname,
+		    const char *inbuf, unsigned int size, void *intp)
+{
+	if (sscanf(inbuf, "%i", (int *)intp) != 1) return -EINVAL;
+	return 0;
+}
+
+int proc_fetch_uint(const char *dir, const char *fname,
+		    char *outbuf, unsigned int size, void *uintp)
+{
+	return snprintf(outbuf, size, "%u\n", *(unsigned int *)uintp);
+}
+
+int proc_commit_uint(const char *dir, const char *fname,
+		     const char *inbuf, unsigned int size, void *uintp)
+{
+	if (sscanf(inbuf, "%u", (unsigned int *)uintp) != 1) return -EINVAL;
+	return 0;
+}
+
+int proc_fetch_long(const char *dir, const char *fname,
+		    char *outbuf, unsigned int size, void *longp)
+{
+	return snprintf(outbuf, size, "%li\n", *(long *)longp);
+}
+
+int proc_commit_long(const char *dir, const char *fname,
+		     const char *inbuf, unsigned int size, void *longp)
+{
+	if (sscanf(inbuf, "%li", (long *)longp) != 1) return -EINVAL;
+	return 0;
+}
+
+int proc_fetch_ulong(const char *dir, const char *fname,
+		     char *outbuf, unsigned int size, void *ulongp)
+{
+	return snprintf(outbuf, size, "%lu\n", *(long *)ulongp);
+}
+
+int proc_commit_ulong(const char *dir, const char *fname,
+		      const char *inbuf, unsigned int size, void *ulongp)
+{
+	if (sscanf(inbuf, "%lu", (unsigned long *)ulongp) != 1) return -EINVAL;
+	return 0;
+}
+
+int proc_fetch_bool(const char *dir, const char *fname,
+		    char *outbuf, unsigned int size, void *boolp)
+{
+	if (*(int *)boolp) return snprintf(outbuf, size, "y\n");
+	else return snprintf(outbuf, size, "n\n");
+}
+
+int proc_commit_bool(const char *dir, const char *fname,
+		     const char *inbuf, unsigned int size, void *boolp)
+{
+	if (inbuf[0] == 'y' || inbuf[0] == 'Y')
+		*(int *)boolp = 1;
+	else if (inbuf[0] == 'n' || inbuf[0] == 'N')
+		*(int *)boolp = 0;
+	else return proc_commit_int(dir, fname, inbuf, size, boolp);
+	return 0;
+}
+
+/* Test code: delete me */
+static int number = 7;
+
+static int testfetch(const char *dirname,
+		     const char *filename,
+		     char *buffer,
+		     unsigned int size,
+		     void *arg)
+{
+	/* As an example, each one holds its own name */
+	return snprintf(buffer, size, "%s/%s\n", dirname, filename);
+}
+
+static int dirfunc(const char *dirname,
+		   const char *filename,
+		   struct proc_dircontents *buffer,
+		   unsigned int maxlen,
+		   void *arg)
+{
+	unsigned int used = 0;
+	char name[100];
+	unsigned int i;
+
+	for (i = 0; i < 10; i++) {
+		sprintf(name, "file-%u", i);
+		used = proc_add_dircontents(buffer, used, maxlen,
+					    S_IFREG|0400, testfetch,
+					    NULL, NULL, NULL, name);
+	}
+	/* And one infinite subdirectory example */
+	used = proc_add_dircontents(buffer, used, maxlen,
+				    S_IFDIR|0555, NULL, NULL, dirfunc, NULL,
+				    "subdir");
+	return proc_end_dircontents(buffer, used, maxlen);
+}
+
+static int __init init_test(void)
+{
+	int ret;
+	ret = proc("testdir", "number", number, int, 0644);
+	if (ret)
+		printk("Proc registration failed: %i\n", ret);
+	proc_dir("testdir", "subdir", dirfunc, NULL);
+	return 0;
+}
+
+static void __exit exit_test(void)
+{
+	unproc("testdir", "number");
+	unproc_dir("testdir", "subdir");
+}
+
+module_init(init_test);
+module_exit(exit_test);
diff -urN -I \$.*\$ --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.4.13-uml/fs/simpleproc/inode.c working-2.4.13-uml-proc/fs/simpleproc/inode.c
--- linux-2.4.13-uml/fs/simpleproc/inode.c	Thu Jan  1 10:00:00 1970
+++ working-2.4.13-uml-proc/fs/simpleproc/inode.c	Thu Nov  1 21:29:14 2001
@@ -0,0 +1,790 @@
+/*
+ * Simple /proc filesystem for Linux.
+ *
+ * Conceptually, there are two types of directories here: static
+ * (entries are created and deleted using
+ * register_proc/unregister_proc), and dynamic (contents are created
+ * on demand using a callback).
+ *
+ *   Copyright (C) 2001 Rusty Russell.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/simpleproc.h>
+#include <asm/semaphore.h>
+
+#include <asm/uaccess.h>
+
+/* Proc mount point */
+struct vfsmount *proc_mnt;
+
+/* Serialize insert/delete and mounts */
+static DECLARE_MUTEX(proc_semaphore);
+
+#define SIMPLE_PROCFS_MAGIC	0x62121174
+
+/* Start with this many bytes allocated for file read */
+#define PROCFS_START_FILE	64
+/* Start with this many bytes allocated for directory read */
+#define PROCFS_START_DIR	PAGE_SIZE
+/* Approximate upper ceiling for memory usage per fs */
+#define PROCFS_MAX_SIZE		PAGE_SIZE
+
+/* Pre-decls for assigning */
+static struct inode_operations proc_punt_inodeops;
+static struct file_operations proc_helper_fileops;
+static struct file_operations proc_helper_dirops;
+static struct file_operations proc_punt_dirops;
+static struct inode_operations proc_helper_inodeops;
+static struct super_operations proc_ops;
+static struct dentry_operations proc_dentry_ops;
+
+struct proc_buffer
+{
+	unsigned int maxlen;
+	unsigned int len;
+	/* One is for the nul terminator */
+	char buffer[1];
+};
+
+struct proc_data *__new_proc(void *arg,
+			     proc_fetchfn_t *fetch,
+			     proc_commitfn_t *commit,
+			     proc_dirfn_t *dir)
+{
+	struct proc_data *pdata;
+
+	pdata = kmalloc(sizeof(*pdata), GFP_KERNEL);
+	if (pdata) {
+		pdata->arg = arg;
+		pdata->fetch = fetch;
+		pdata->commit = commit;
+		pdata->dir = dir;
+	}
+	return pdata;
+}
+
+/* FIXME: I have no idea what all this does: stolen from old /proc --RR */
+static int proc_statfs(struct super_block *sb, struct statfs *buf)
+{
+	buf->f_type = SIMPLE_PROCFS_MAGIC;
+	buf->f_bsize = PAGE_SIZE/sizeof(long);
+	buf->f_bfree = 0;
+	buf->f_bavail = 0;
+	buf->f_ffree = 0;
+	buf->f_namelen = NAME_MAX;
+	return 0;
+}
+
+/* Convenience routine to make an inode */
+static struct inode *
+new_proc_inode(struct super_block *sb, int mode, int is_dynamic)
+{
+	struct inode * inode = new_inode(sb);
+
+	if (!inode)
+		return NULL;
+
+	inode->i_mode = mode;
+	inode->i_uid = 0;
+	inode->i_gid = 0;
+	inode->i_blksize = PAGE_CACHE_SIZE;
+	inode->i_blocks = 0;
+	inode->i_rdev = NODEV;
+	inode->i_mapping->a_ops = NULL;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	switch (mode & S_IFMT) {
+	case S_IFREG:
+		inode->i_fop = &proc_helper_fileops;
+		break;
+	case S_IFDIR:
+		if (is_dynamic) {
+			inode->i_fop = &proc_punt_dirops;
+			inode->i_op = &proc_punt_inodeops;
+		} else {
+			inode->i_fop = &proc_helper_dirops;
+			inode->i_op = &proc_helper_inodeops;
+		}
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	return inode;
+}
+
+/* Make a new proc entry in this directory: must be holding proc_semapore */
+static int make_proc_entry(struct dentry *dir,
+			   const char *fname,
+			   int mode,
+			   struct proc_data *pdata,
+			   int is_dynamic)
+{
+	struct inode *inode;
+	struct dentry *dentry;
+	struct qstr qstr;
+
+	/* Create qstr for this entry */
+	qstr.name = fname;
+	qstr.len = strlen(fname);
+	qstr.hash = full_name_hash(qstr.name, qstr.len);
+
+	/* You can't put a static proc entry in a dynamic dir */
+	if (dir->d_inode->i_op == &proc_punt_inodeops)
+		BUG();
+
+	/* Does it already exist? */
+	dentry = d_lookup(dir, &qstr);
+	if (dentry) {
+		dput(dentry);
+		return -EEXIST;
+	}
+
+	/* Doesn't exist: create inode */
+	inode = new_proc_inode(dir->d_sb, mode, is_dynamic);
+	if (!inode)
+		return -ENOMEM;
+
+	/* Create dentry */
+	dentry = d_alloc(dir, &qstr);
+	if (!dentry) {
+		iput(inode);
+		return -ENOMEM;
+	}
+	dentry->d_op = &proc_dentry_ops;
+	dentry->d_fsdata = pdata;
+	d_add(dentry, inode);
+
+	/* Pin the dentry here, so it doesn't get pruned */
+	dget(dentry);
+	return 0;
+}
+
+/* Create (static) proc directory if neccessary. */
+/* FIXME: Keep refcnt, so we can delete when no more users */
+static struct dentry *get_proc_dir(const char *dirname)
+{
+	struct dentry *dentry;
+	struct qstr qstr;
+	const char *delim;
+
+	/* FIXME: Definitely need a better way --RR */
+	dentry = dget(proc_mnt->mnt_sb->s_root);
+	delim = dirname;
+
+	for (;;) {
+		struct dentry *newdentry;
+
+		/* Ignore multiple slashes */ 
+		while (*delim == '/') delim++;
+		qstr.name = delim;
+		delim = strchr(qstr.name, '/');
+		if (!delim) delim = qstr.name + strlen(qstr.name);
+		qstr.len = delim-(char *)qstr.name;
+		qstr.hash = full_name_hash(qstr.name, qstr.len);
+
+		if (qstr.len == 0)
+			break;
+
+		/* If entry doesn't exist, create it */
+		while (!(newdentry = d_lookup(dentry, &qstr))) {
+			char fname[qstr.len+1];
+			int ret;
+
+			strncpy(fname, qstr.name, qstr.len);
+			fname[qstr.len] = '\0';
+			down(&proc_semaphore);
+			ret = make_proc_entry(dentry, fname, S_IFDIR|0555,
+					       NULL, 0);
+			up(&proc_semaphore);
+
+			if (ret < 0) {
+				dput(dentry);
+				return ERR_PTR(ret);
+			}
+		}
+		dput(dentry);
+		dentry = newdentry;
+	}
+	return dentry;
+}
+
+/* Actually add a proc file or dynamic directory */
+int __proc(const char *dirname, const char *fname, int mode,
+	   struct proc_data *pdata)
+{
+	struct dentry *dir;
+	int ret;
+
+	if (!pdata)
+		return -ENOMEM;
+
+	dir = get_proc_dir(dirname);
+	if (IS_ERR(dir))
+		return PTR_ERR(dir);
+
+	ret = make_proc_entry(dir, fname, mode, pdata, S_ISDIR(mode) ? 1 : 0);
+	dput(dir);
+	return ret;
+}
+
+static int proc_nofetch(const char *dirname, const char *fname,
+			char *outbuf, unsigned int len, void *arg)
+{
+	return -ENOENT;
+}
+
+static int proc_nocommit(const char *dirname, const char *fname,
+			 const char *inbuf, unsigned int len, void *arg)
+{
+	return -ENOENT;
+}
+
+static int proc_nodir(const char *dirname,
+		      const char *filename,
+		      struct proc_dircontents *buffer,
+		      unsigned int size,
+		      void *arg)
+{
+	return -ENOENT;
+}
+
+/* Release a proc entry */
+void unproc(const char *dir, const char *fname)
+{
+	struct dentry *dentry;
+	const char *delim;
+	struct qstr qstr;
+	struct proc_data *pdata;
+
+	/* FIXME: There's a better way, right? --RR */
+	dentry = dget(proc_mnt->mnt_sb->s_root);
+
+	delim = dir;
+	for (;;) {
+		/* Ignore multiple slashes */ 
+		while (*delim == '/') delim++;
+		qstr.name = delim;
+		delim = strchr(qstr.name, '/');
+		if (!delim) delim = qstr.name + strlen(qstr.name);
+		qstr.len = delim-(char *)qstr.name;
+		qstr.hash = full_name_hash(qstr.name, qstr.len);
+
+		if (qstr.len == 0)
+			break;
+
+		dentry = d_lookup(dentry, &qstr);
+		if (!dentry)
+			BUG();
+		dput(dentry->d_parent);
+	}
+
+	qstr.name = fname;
+	qstr.len = strlen(fname);
+	qstr.hash = full_name_hash(qstr.name, qstr.len);
+	dentry = d_lookup(dentry, &qstr);
+	if (!dentry)
+		BUG();
+	dput(dentry->d_parent);
+
+	/* We have the dentry: change the private area so it doesn't
+           enter the caller any more. */
+	pdata = dentry->d_fsdata;
+	pdata->commit = proc_nocommit;
+	pdata->fetch = proc_nofetch;
+	pdata->dir = proc_nodir;
+
+	/* This will probably free the dentry immediately, but if not,
+           too bad. */
+	dput(dentry);
+	dput(dentry);
+}
+
+void unproc_dir(const char *dir, const char *fname)
+{
+	unproc(dir, fname);
+}
+
+/* See if /proc entry exists (entries registered in directory). */
+static struct dentry *proc_lookup(struct inode *dir,
+					 struct dentry *dentry)
+{
+	/* Since we place new staticn entries in the dcache, if we get
+	   here, we know the entry does not exist.  Create a negative
+	   dentry, and return NULL */
+	d_add(dentry, NULL);
+	return NULL;
+}
+
+/* Call callback to get directory contents */
+static struct proc_dircontents *get_dir_contents(const char *dirname,
+						 const char *filename,
+						 struct proc_data *pdata)
+{
+	struct proc_dircontents *ret;
+	unsigned int size = PROCFS_START_DIR;
+
+	ret = kmalloc(size, GFP_KERNEL);
+	while (ret) {
+		int used;
+		used = pdata->dir(dirname, filename, ret, size, pdata->arg);
+		if (used < 0) {
+			kfree(ret);
+			return ERR_PTR(used);
+		}
+		if (used <= size)
+			return ret;
+
+		/* Realloc larger and loop */
+		kfree(ret);
+		size = used;
+		ret = kmalloc(size, GFP_KERNEL);
+	}
+	return ERR_PTR(-ENOMEM);
+}
+
+/* Incrementing is a little tricky: round up to alignment */
+static struct proc_dircontents *next_dcont(struct proc_dircontents *dcontents)
+{
+	unsigned int len;
+
+	len = ((sizeof(*dcontents) + strlen(dcontents->name) + 1
+		+ __alignof__(*dcontents) - 1)
+	       & ~(__alignof__(*dcontents) - 1));
+	return (void *)dcontents + len;
+}
+
+/* Search results from callback for this name, and if found create inode */
+static struct proc_dircontents *
+find_dcontents(struct proc_dircontents *dir_contents,
+	       struct dentry *dentry)
+{
+	while (dir_contents->mode) {
+		if (strcmp(dentry->d_name.name, dir_contents->name) == 0)
+			return dir_contents;
+		dir_contents = next_dcont(dir_contents);
+	}
+	/* Not found... */
+	return NULL;
+}
+
+/* Since there are no hard links in this filesystem, we can simply map
+   inodes to dentries.  This is not possibly in general! */
+static struct dentry *inode_to_dentry(struct inode *inode)
+{
+	if (inode->i_dentry.next->next != &inode->i_dentry)
+		BUG();
+	return list_entry(inode->i_dentry.next, struct dentry, d_alias);
+}
+
+/* See if /proc entry exists (user controls contents of directory). */
+static struct dentry *proc_punt_lookup(struct inode *dir,
+				       struct dentry *dentry)
+{
+	/* We do the whole callback on every lookup. */
+	struct proc_data *pdata;
+	struct proc_dircontents *dir_contents, *dc;
+	struct inode *inode;
+	struct dentry *parent;
+
+	/* Since we know the inode is a directory, there is only one
+           inode in the dentry alias list, so mapping inode -> dentry
+           is easy */
+	parent = inode_to_dentry(dir);
+	dir_contents = get_dir_contents(parent->d_name.name,
+					dentry->d_name.name,
+					parent->d_fsdata);
+	if (!dir_contents || IS_ERR(dir_contents))
+		return (struct dentry *)dir_contents;
+
+	/* Looks through callback-supplied list for this dentry */ 
+	dc = find_dcontents(dir_contents, dentry);
+	if (!dc) {
+		kfree(dir_contents);
+		return NULL;
+	}
+	inode = new_proc_inode(dentry->d_sb, dc->mode, 1);
+	if (!inode) {
+		kfree(dir_contents);
+		return ERR_PTR(-ENOMEM);
+	}
+	pdata = __new_proc(dc->arg, dc->fetch, dc->commit, dc->dir);
+	if (!pdata) {
+		iput(inode);
+		kfree(dir_contents);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	dentry->d_op = &proc_dentry_ops;
+	dentry->d_fsdata = pdata;
+	d_add(dentry, inode);
+	kfree(dir_contents);
+	return NULL;
+}
+
+/* On open, we grab contents if we're readable... */
+static int proc_file_snapshot(struct inode *inode, struct file *filp)
+{
+	unsigned int size;
+	struct proc_buffer *buf;
+	struct proc_data *pdata;
+	char *dirname;
+	unsigned long page;
+
+	pdata = filp->f_dentry->d_fsdata;
+	/* Start at this, and work up */
+	size = PROCFS_START_FILE;
+
+	if (!(filp->f_mode & FMODE_READ)) {
+		/* Allocate write buffer: */
+		buf = kmalloc(sizeof(*buf) + size, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+		buf->maxlen = size;
+		buf->len = 0;
+		filp->private_data = buf;
+		return 0;
+	}
+
+	/* For the moment, you can't open for read & write.  Later,
+           when seek resets snapshot/commit, we should allow this. */
+	if (filp->f_mode & FMODE_WRITE)
+		return -EINVAL;
+
+	page = __get_free_page(GFP_USER);
+	if (!page)
+		return -ENOMEM;
+
+	/* FIXME: This is not right: the callbacks don't care what the
+	   process's idea of root is, it only wants path after proc/. */
+	dirname = d_path(filp->f_dentry, filp->f_vfsmnt,
+			 (char *)page, PAGE_SIZE);
+	if (dirname < (char *)page)
+		BUG();
+
+	/* buf[0] holds the size */
+	buf = kmalloc(sizeof(*buf)+size, GFP_KERNEL);
+	while (buf) {
+		int used;
+		used = pdata->fetch(dirname, filp->f_dentry->d_name.name,
+				    buf->buffer, size, pdata->arg);
+		if (used < 0) {
+			kfree(buf);
+			free_page(page);
+			/* FIXME: if used == -ENOENT, destroy dcache entry */
+			return used;
+		}
+		if (used <= size) {
+			free_page(page);
+			filp->private_data = buf;
+			/* Nul terminate and save size */
+			buf->maxlen = size;
+			buf->len = used;
+			buf->buffer[used] = '\0';
+			return 0;
+		}
+
+		/* Realloc larger and loop */
+		kfree(buf);
+		size = used;
+		if (size > PROCFS_MAX_SIZE)
+			break;
+		buf = kmalloc(sizeof(*buf)+size, GFP_KERNEL);
+	}
+	free_page(page);
+	return -ENOMEM;
+}
+
+/* On close, we commit contents if we've been written to... */
+static int proc_file_commit(struct inode *inode, struct file *filp)
+{
+	int ret;
+	struct proc_data *pdata;
+	struct proc_buffer *buf;
+	char *dirname;
+	unsigned long page;
+
+	pdata = filp->f_dentry->d_fsdata;
+	if (!(filp->f_mode & FMODE_WRITE)) {
+		kfree(filp->private_data);
+		return 0;
+	}
+
+	page = __get_free_page(GFP_USER);
+	if (!page) {
+		kfree(filp->private_data);
+		return -ENOMEM;
+	}
+
+	/* FIXME: This is not right: the callbacks don't care what the
+	   process's idea of root is, it only wants path after proc/. */
+	dirname = d_path(filp->f_dentry, filp->f_vfsmnt,
+			 (char *)page, PAGE_SIZE);
+	if (dirname < (char *)page)
+		BUG();
+
+	/* nul-terminate buffer */
+	buf = filp->private_data;
+	buf->buffer[buf->len] = '\0';
+	ret = pdata->commit(dirname, filp->f_dentry->d_name.name,
+			    buf->buffer, buf->len, pdata->arg);
+	
+	kfree(filp->private_data);
+	free_page(page);
+	return ret;
+}
+
+/* Copy from buffer */
+static ssize_t proc_file_read(struct file *filp, char *ubuf, size_t size,
+			      loff_t *off)
+{
+	struct proc_buffer *buf;
+	struct inode *inode;
+
+	/* Use inode semaphore to serialize against writes. */
+	inode = filp->f_dentry->d_inode;
+	if (down_interruptible(&inode->i_sem) != 0)
+		return -EINTR;
+
+	buf = filp->private_data;
+	if (size + *off > buf->len)
+		size = buf->len - *off;
+
+	/* Copy from static buffer */
+	if (copy_to_user(ubuf, buf->buffer, size) != 0) {
+		up(&inode->i_sem);
+		return -EFAULT;
+	}
+	up(&inode->i_sem);
+
+	*off += size;
+	return (ssize_t)size;
+}
+
+/* Copy to buffer */
+static ssize_t proc_file_write(struct file *filp,
+			       const char *ubuf,
+			       size_t size,
+			       loff_t *off)
+{
+	struct inode *inode;
+	struct proc_buffer *buf;
+	struct proc_data *pdata;
+
+	pdata = filp->f_dentry->d_fsdata;
+
+	/* Use inode semaphore to serialize writes & reads. */
+	inode = filp->f_dentry->d_inode;
+	if (down_interruptible(&inode->i_sem) != 0)
+		return -EINTR;
+
+	buf = filp->private_data;
+	if (*off + size > buf->maxlen) {
+		struct proc_buffer *newbuffer;
+		/* Prevent them using too much memory */
+		if (*off + size > PROCFS_MAX_SIZE) {
+			up(&inode->i_sem);
+			return -ENOSPC;
+		}
+		/* Room for count at head */
+		newbuffer = kmalloc(sizeof(*newbuffer) + *off + size,
+				    GFP_USER);
+		if (!newbuffer) {
+			up(&inode->i_sem);
+			return -ENOMEM;
+		}
+		memcpy(newbuffer, buf, sizeof(*buf) + buf->len);
+		kfree(filp->private_data);
+		filp->private_data = buf = newbuffer;
+	}
+
+	/* Do actual copy */
+	if (copy_from_user(buf->buffer + *off, ubuf, size) != 0) {
+		up(&inode->i_sem);
+		return -EFAULT;
+	}
+	up(&inode->i_sem);
+	buf->len += size;
+	*off += size;
+
+	return size;
+}
+
+/* Call the user's callback to get contents of this directory.
+   Generate . and .. automagically. */
+static int proc_dynamic_readdir(struct file *filp,
+				void *dirent,
+				filldir_t filldir)
+{
+	int i;
+	struct proc_dircontents *dcontents, *dp;
+	char *dirname;
+	unsigned long page;
+	struct proc_data *pdata;
+	struct dentry *dentry = filp->f_dentry;
+
+	pdata = filp->f_dentry->d_fsdata;
+
+	i = filp->f_pos;
+	switch (i) {
+	case 0:
+		if (filldir(dirent, ".", 1, 0, dentry->d_inode->i_ino, DT_DIR)
+		    < 0)
+			break;
+		i++;
+		filp->f_pos++;
+		/* fallthrough */
+	case 1:
+		if (filldir(dirent, "..", 2, 0,
+			    dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
+			break;
+		i++;
+		filp->f_pos++;
+	}
+
+	page = __get_free_page(GFP_USER);
+	if (!page) return -ENOMEM;
+
+	/* FIXME: This is not right: the callbacks don't care what the
+	   process's idea of root is, it only wants path after proc/. */
+	dirname = d_path(filp->f_dentry, filp->f_vfsmnt,
+			 (char *)page, PAGE_SIZE);
+	if (dirname < (char *)page)
+		BUG();
+
+	/* Call user callback to get directory */
+	dcontents = get_dir_contents(dirname,
+				     dentry->d_name.name,
+				     pdata);
+	if (IS_ERR(dcontents)) {
+		free_page(page);
+		return PTR_ERR(dcontents);
+	}
+
+	/* Skip any already-read entries... */
+	for (dp = dcontents, i -= 2; dp->mode && i; dp = next_dcont(dp), i++);
+
+	for (; dp->mode; dp = next_dcont(dp)) {
+		/* FIXME: Use non-zero inode numbers */
+		if (filldir(dirent, dp->name, strlen(dp->name),
+			    filp->f_pos,
+			    filp->f_pos,
+			    S_ISDIR(dp->mode) ? DT_DIR : DT_REG) < 0)
+			break;
+		filp->f_pos++;
+	}
+	free_page(page);
+	kfree(dcontents);
+	return 0;
+}
+
+/* Free the private area when dentry is freed. */
+static void proc_release(struct dentry *dentry)
+{
+	kfree(dentry->d_fsdata);
+}
+
+static struct super_block *proc_read_super(struct super_block *s,
+					   void *data, 
+					   int silent)
+{
+	struct inode * root_inode;
+
+	s->s_blocksize = 1024;
+	s->s_blocksize_bits = 10;
+	s->s_magic = SIMPLE_PROCFS_MAGIC;
+	s->s_op = &proc_ops;
+
+	root_inode = new_proc_inode(s, S_IFDIR|0555, 0);
+	if (!root_inode) return NULL;
+
+	/* Block concurrent mounts */
+	down(&proc_semaphore);
+
+	s->s_root = d_alloc_root(root_inode);
+	if (!s->s_root) {
+		iput(root_inode);
+		up(&proc_semaphore);
+		return NULL;
+	}
+	up(&proc_semaphore);
+	return s;
+}
+
+/* Proc files use these wrappers */
+static struct file_operations proc_helper_fileops = {
+	open:		proc_file_snapshot,
+	release:	proc_file_commit,
+	read:		proc_file_read,
+	write:		proc_file_write,
+};
+
+/* Directories which use normal registration mechanism, which sit in
+   the dcache */
+static struct file_operations proc_helper_dirops = {
+	read:		generic_read_dir,
+	readdir:	dcache_readdir,
+};
+
+/* Directories which have their own dynamic content */
+static struct file_operations proc_punt_dirops = {
+	read:		generic_read_dir,
+	readdir:	proc_dynamic_readdir,
+};
+
+/* You can only do lookups through these dirs: dynamic ones do callbacks... */
+static struct inode_operations proc_punt_inodeops = {
+	lookup:		proc_punt_lookup,
+};
+
+/* ... static ones look up registrations */
+static struct inode_operations proc_helper_inodeops = {
+	lookup:		proc_lookup,
+};
+
+static struct super_operations proc_ops = {
+	statfs:		proc_statfs,
+	put_inode:	force_delete,
+};
+
+static struct dentry_operations proc_dentry_ops = {
+	d_release:	proc_release,
+};
+
+static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, FS_SINGLE);
+
+static int __init init_proc_fs(void)
+{
+	register_filesystem(&proc_fs_type);
+	proc_mnt = kern_mount(&proc_fs_type);
+	return 0;
+}
+
+static void __exit exit_proc_fs(void)
+{
+	unregister_filesystem(&proc_fs_type);
+}
+
+module_init(init_proc_fs);
+module_exit(exit_proc_fs);
+

^ permalink raw reply	[flat|nested] 258+ messages in thread
[parent not found: <Pine.LNX.4.33.0111041141100.14150-100000@penguin.transmeta.com>]
* Re: PROPOSAL: dot-proc interface [was: /proc stuff]
@ 2001-11-04 23:06 Craig Thrall
  2001-11-04 23:39 ` Jakob Østergaard
  0 siblings, 1 reply; 258+ messages in thread
From: Craig Thrall @ 2001-11-04 23:06 UTC (permalink / raw)
  To: 'jakob@unthought.net'; +Cc: 'linux-kernel@vger.kernel.org'

> Problem:  Could it be made simpler to parse from scripting languages,
> without making it less elegant to parse in plain C ?

Yes.  At one point, somebody suggested XML.  Now, as much as I hate the fact
that people somehow equate high-tech with tags, I think whomever originally
suggested it might be on to something.  :)

Fact is, just about EVERY language out there has some sort of utility to
parse XML.  There's expat for C, Perl and Python have libs, etc.  We could
even write a proc DTD that could specify the valid data types.

There are two problems:

1. Performance - it's slower to go through a library that outputs XML than
do a printf("%d", pid) or the like.

2. Space - based on a little experience using XML as a transport, the space
used by the tags adds up.

3. Work - writing a good package to do this, and rewriting bits of the
kernel to use it.  I'll volunteer my time.

Just a thought,

Craig

^ permalink raw reply	[flat|nested] 258+ messages in thread
[parent not found: <20011104214229Z17052-23341+37@humbolt.nl.linux.org>]
* RFC: booleans and the kernel
@ 2002-01-24 17:42 Jeff Garzik
  2002-01-24 18:22 ` Anton Altaparmakov
                   ` (4 more replies)
  0 siblings, 5 replies; 258+ messages in thread
From: Jeff Garzik @ 2002-01-24 17:42 UTC (permalink / raw)
  To: Linux-Kernel list

A small issue... 

C99 introduced _Bool as a builtin type.  The gcc patch for it went into
cvs around Dec 2000.  Any objections to propagating this type and usage
of 'true' and 'false' around the kernel?

Where variables are truly boolean use of a bool type makes the
intentions of the code more clear.  And it also gives the compiler a
slightly better chance to optimize code [I suspect].

Actually I prefer 'bool' to '_Bool', if this becomes a kernel standard.

	Jeff


-- 
Jeff Garzik      | "I went through my candy like hot oatmeal
Building 1024    |  through an internally-buttered weasel."
MandrakeSoft     |             - goats.com

^ permalink raw reply	[flat|nested] 258+ messages in thread

end of thread, other threads:[~2002-01-29  6:37 UTC | newest]

Thread overview: 258+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-11-01 10:32 [PATCH] 2.5 PROPOSAL: Replacement for current /proc of shit Rusty Russell
2001-11-01 10:42 ` Jeff Garzik
2001-11-01 16:49   ` Martin Dalecki
2001-11-01 17:06   ` Gábor Lénárt
2001-11-01 12:06 ` Tim Jansen
2001-11-01 18:34   ` James Simmons
2001-11-02  1:42 ` Rusty Russell
2001-11-02  1:56   ` Erik Andersen
2001-11-02 11:44     ` Padraig Brady
2001-11-02  9:11   ` Alexander Viro
2001-11-02 12:39     ` Martin Dalecki
2001-11-02 11:57       ` Alexander Viro
2001-11-02 13:55       ` Keith Owens
2001-11-02 15:08         ` Martin Dalecki
2001-11-04  5:36       ` Albert D. Cahalan
2001-11-02 12:46     ` Miquel van Smoorenburg
2001-11-02  2:20 ` Rusty Russell
2001-11-02 13:59   ` Tim Jansen
     [not found]     ` <20011103103106.7eb6098b.rusty@rustcorp.com.au>
2001-11-03 11:47       ` Tim Jansen
2001-11-03 23:44       ` Rusty Russell
2001-11-04  1:40   ` Daniel Phillips
2001-11-04  2:08     ` Jakob Østergaard
2001-11-04 12:30       ` Tim Jansen
2001-11-04 13:36         ` Daniel Kobras
2001-11-04 14:13           ` Tim Jansen
2001-11-04 15:33             ` PROPOSAL: dot-proc interface [was: /proc stuff] Jakob Østergaard
2001-11-04 16:05               ` Gábor Lénárt
2001-11-04 16:31               ` Daniel Phillips
2001-11-04 17:30                 ` Jakob Østergaard
2001-11-04 16:45               ` Tim Jansen
2001-11-04 17:28                 ` Daniel Phillips
2001-11-04 17:41                   ` Jakob Østergaard
2001-11-04 17:54                     ` SpaceWalker
2001-11-04 20:45                       ` Albert D. Cahalan
2001-11-04 17:59                     ` John Levon
2001-11-04 18:31                       ` Jakob Østergaard
2001-11-04 18:40                         ` Alexander Viro
2001-11-04 19:04                           ` Jakob Østergaard
2001-11-04 19:24                             ` Alex Bligh - linux-kernel
2001-11-04 19:45                               ` Jakob Østergaard
2001-11-04 19:52                                 ` Alexander Viro
2001-11-04 20:06                                   ` Jakob Østergaard
2001-11-04 22:01                                   ` Daniel Phillips
2001-11-04 21:12                                 ` Albert D. Cahalan
2001-11-04 21:20                                   ` Jakob Østergaard
2001-11-04 21:42                                     ` Tim Jansen
2001-11-04 22:13                                     ` Albert D. Cahalan
2001-11-05 11:23                                       ` Martin Dalecki
2001-11-05 15:58                                         ` Alexander Viro
2001-11-05 18:30                                           ` Martin Dalecki
2001-11-05 23:00                                             ` Albert D. Cahalan
2001-11-06 13:47                                               ` Martin Dalecki
2001-11-06 17:13                                               ` Gerhard Mack
2001-11-05 16:38                                       ` Stephen Satchell
2001-11-05 18:39                                         ` Martin Dalecki
2001-11-05 18:28                                           ` Ben Greear
2001-11-05 18:40                                             ` Rik van Riel
2001-11-05 21:03                                               ` Tim Jansen
2001-11-05 21:58                                                 ` Ben Greear
2001-11-05 22:51                                                   ` Tim Jansen
2001-11-05 22:59                                                     ` Erik Andersen
2001-11-05 23:35                                                       ` Tim Jansen
2001-11-05 23:41                                                         ` Alexander Viro
2001-11-06 13:49                                                           ` Martin Dalecki
2001-11-06 19:49                                                       ` dank
2001-11-06 22:22                                                         ` Erik Andersen
2001-11-06 22:47                                                           ` dank
2001-11-06 23:11                                                             ` Erik Andersen
2001-11-06 23:39                                                             ` Ricky Beam
2001-11-07 12:45                                                           ` Remco Post
2001-11-07  1:06                                                         ` George Greer
2001-11-05 19:58                                       ` Jonathan Lundell
2001-11-05 21:43                                       ` Stephen Satchell
2001-11-06  5:22                                         ` Ragnar Hojland Espinosa
2001-11-04 21:22                                   ` Alex Bligh - linux-kernel
2001-11-05  4:03                                 ` Stuart Young
2001-11-05  4:05                                   ` Alexander Viro
2001-11-05  4:55                                   ` Stuart Young
2001-11-05 16:32                                     ` SpaceWalker
2001-11-06  6:46                                       ` Jakob Østergaard
2001-11-04 19:29                             ` Alexander Viro
2001-11-04 19:50                               ` Jakob Østergaard
2001-11-04 20:01                                 ` Alexander Viro
2001-11-04 20:09                                   ` Jakob Østergaard
2001-11-06  7:23                                 ` Kai Henningsen
2001-11-06 14:00                                   ` Jakob Østergaard
2001-11-04 18:27                     ` Tim Jansen
2001-11-04 18:35                       ` Alexander Viro
2001-11-04 18:39                       ` Jakob Østergaard
2001-11-07  1:20                       ` Pavel Machek
2001-11-07 21:14                         ` Rik van Riel
2000-01-01  0:13                           ` Pavel Machek
2001-11-04 18:20                   ` Tim Jansen
2001-11-04 18:30                     ` Alexander Viro
2001-11-04 18:52                       ` Jakob Østergaard
2001-11-04 19:18                         ` Daniel Phillips
2001-11-04 21:41                       ` Albert D. Cahalan
2001-11-05 11:06                       ` Martin Dalecki
2001-11-05 10:28                         ` Daniel Phillips
2001-11-05 22:46                           ` Albert D. Cahalan
2001-11-06  0:54                             ` Daniel Phillips
2001-11-06  1:11                             ` Stephen Satchell
2001-11-04 18:46                     ` Jakob Østergaard
2001-11-04 19:07                   ` Linus Torvalds
2001-11-04 19:20                     ` Jakob Østergaard
2001-11-04 19:32                       ` Dave Jones
2001-11-04 19:52                         ` Jakob Østergaard
2001-11-04 20:06                           ` Alexander Viro
2001-11-04 20:11                             ` Jakob Østergaard
2001-11-11 10:06                           ` Kai Henningsen
2001-11-11 19:43                             ` Jakob Østergaard
2001-11-12 13:43                               ` Pascal Schmidt
2001-11-13 12:09                                 ` Jakob Østergaard
2001-11-13 14:41                               ` Riley Williams
2001-11-04 22:09                     ` Luigi Genoni
2001-11-04 17:48                 ` Jakob Østergaard
2001-11-04 18:02                   ` John Levon
2001-11-04 18:34                   ` Tim Jansen
2001-11-04 18:59                     ` Jakob Østergaard
2001-11-04 19:19                       ` Tim Jansen
2001-11-04 19:24                         ` Jakob Østergaard
2001-11-04 19:41                           ` Tim Jansen
2001-11-04 19:55                             ` Jakob Østergaard
2001-11-04 20:13                               ` Tim Jansen
2001-11-04 20:11                                 ` Jakob Østergaard
2001-11-04 20:47                                   ` Alex Bligh - linux-kernel
2001-11-04 21:02                                     ` Jakob Østergaard
2001-11-04 22:53                               ` Stephen Satchell
2001-11-05 11:04               ` zmwillow
2001-11-05 13:41               ` Petr Baudis
2001-11-05 20:49                 ` Tim Jansen
2001-11-05 22:01                   ` Ben Greear
     [not found]                   ` <20011105223413.U11619@pasky.ji.cz>
     [not found]                     ` <160rly-1tl3XUC@fmrl05.sul.t-online.com>
2001-11-05 22:07                       ` Petr Baudis
2001-11-06  7:25                 ` Jakob Østergaard
2001-11-06  8:21                   ` Petr Baudis
2001-11-06  8:34                     ` Alexander Viro
2001-11-06 13:43                       ` Jakob Østergaard
2001-11-06 17:01                       ` Petr Baudis
2001-11-05 19:55               ` PROPOSAL: kernfs (was: Re: PROPOSAL: dot-proc interface [was: /proc st Kai Henningsen
2001-11-06 18:56               ` PROPOSAL: /proc standards (was dot-proc interface [was: /proc stuff]) Stephen Satchell
2001-11-06 19:38                 ` Ben Greear
2001-11-06 20:12                 ` PROPOSAL: /proc standards (was dot-proc interface [was: /proc Erik Hensema
2001-11-06 20:58                   ` Roy Sigurd Karlsbakk
2001-11-06 21:43                     ` Ricky Beam
2001-11-06 22:14                       ` Alexander Viro
2001-11-07  0:33                         ` Alex Bligh - linux-kernel
2001-11-07  7:20                           ` Albert D. Cahalan
2001-11-07  8:07                             ` Alexander Viro
2001-11-07 17:24                             ` Alex Bligh - linux-kernel
2001-11-07 17:22                               ` Blue Lang
2001-11-07 19:21                                 ` Ricky Beam
2001-11-11 10:27                                 ` Kai Henningsen
2001-11-08  0:47                               ` Albert D. Cahalan
2001-11-08 18:53                                 ` Alex Bligh - linux-kernel
2001-11-08 21:28                                   ` Ricky Beam
2001-11-09  5:15                                   ` Albert D. Cahalan
2001-11-19 19:22                                   ` bill davidsen
2001-11-07  0:13                       ` Martin Dalecki
2001-11-07  0:40                         ` Alex Bligh - linux-kernel
2001-11-07  1:10                         ` Ricky Beam
     [not found]                           ` <Pine.GSO.4.33.0111061947540.17287-100000@sweetums.bluetronic.ne t>
2001-11-07  1:17                             ` Alex Bligh - linux-kernel
2001-11-07 11:32                           ` Martin Dalecki
2001-11-07 12:35                       ` Remco Post
2001-11-07 23:53                         ` Albert D. Cahalan
2001-11-07 22:24                       ` Paul P Komkoff Jr
2001-11-07 23:15                         ` Phil Howard
2001-11-06 21:24                   ` Rik van Riel
2001-11-06 21:45                     ` Erik Hensema
2001-11-06 22:06                     ` Tim Jansen
2001-11-06 22:28                     ` Erik Andersen
2001-11-06 22:33                       ` Jan-Benedict Glaw
2001-11-06 22:42                         ` Erik Andersen
2001-11-06 22:49                           ` Jan-Benedict Glaw
2001-11-06 22:53                           ` Patrick Mochel
2001-11-06 22:52                             ` Erik Andersen
2001-11-06 22:46                         ` Ben Greear
2001-11-06 22:50                           ` Jan-Benedict Glaw
2001-11-07  0:17                         ` Martin Dalecki
2001-11-06 22:53                   ` J . A . Magallon
2001-11-05 16:49     ` [PATCH] 2.5 PROPOSAL: Replacement for current /proc of shit Jonathan Lundell
2001-11-05 20:46       ` Tim Jansen
2001-11-05 23:04         ` Greg KH
2001-11-05 22:19           ` Tim Jansen
2001-11-05  0:12   ` Rusty Russell
2001-11-05  3:34     ` Daniel Phillips
2001-11-05 22:48       ` Rusty Russell
2001-11-06 10:25         ` Daniel Phillips
2001-11-06 15:46         ` Theodore Tso
2001-11-07 23:35         ` Rusty Russell
     [not found] <Pine.LNX.4.33.0111041141100.14150-100000@penguin.transmeta.com>
2001-11-04 19:53 ` PROPOSAL: dot-proc interface [was: /proc stuff] Daniel Phillips
2001-11-04 23:06 Craig Thrall
2001-11-04 23:39 ` Jakob Østergaard
     [not found] <20011104214229Z17052-23341+37@humbolt.nl.linux.org>
2001-11-04 23:42 ` Alexander Viro
2001-11-05  0:10   ` Daniel Phillips
2002-01-24 17:42 RFC: booleans and the kernel Jeff Garzik
2002-01-24 18:22 ` Anton Altaparmakov
2002-01-24 18:33   ` Arnaldo Carvalho de Melo
2002-01-24 19:28 ` H. Peter Anvin
2002-01-24 19:34   ` Arnaldo Carvalho de Melo
2002-01-24 19:43     ` H. Peter Anvin
2002-01-24 19:47       ` Arnaldo Carvalho de Melo
2002-01-24 19:46     ` Ingo Oeser
2002-01-24 19:52 ` Oliver Xymoron
2002-01-24 20:03   ` Jeff Garzik
2002-01-24 20:06     ` Oliver Xymoron
2002-01-24 20:14       ` Jeff Garzik
2002-01-24 20:23       ` Alexander Viro
2002-01-24 20:25         ` Oliver Xymoron
2002-01-24 20:35           ` John Levon
2002-01-24 20:15     ` Alexander Viro
2002-01-24 20:21   ` Richard B. Johnson
2002-01-24 20:39     ` Oliver Xymoron
2002-01-24 21:55       ` Richard B. Johnson
2002-01-24 21:57         ` Jeff Garzik
2002-01-24 22:05         ` H. Peter Anvin
2002-01-24 22:13         ` Robert Love
2002-01-24 22:33       ` Xavier Bestel
2002-01-24 22:53         ` Xavier Bestel
2002-01-24 22:59         ` Robert Love
2002-01-24 23:27           ` Xavier Bestel
2002-01-25  6:13             ` Alexander Viro
2002-01-25  8:00               ` Momchil Velikov
2002-01-25 10:51               ` Xavier Bestel
2002-01-25 16:11               ` Olivier Galibert
2002-01-26  7:22               ` Timothy Covell
2002-01-25  7:48                 ` Alexander Viro
2002-01-25 23:49                   ` J.A. Magallon
2002-01-27 11:27                 ` Kai Henningsen
2002-01-25 23:09           ` Timothy Covell
2002-01-25  1:16             ` John Levon
2002-01-25 22:47         ` Timothy Covell
2002-01-25 21:24       ` Timothy Covell
2002-01-24 21:31         ` Oliver Xymoron
2002-01-24 22:19           ` Robert Love
2002-01-24 22:38             ` Robert Love
2002-01-25 22:44               ` Timothy Covell
2002-01-25  3:52                 ` Ragnar Hojland Espinosa
2002-01-25 20:39                   ` Calin A. Culianu
2002-01-25 23:07                   ` Rick Stevens
2002-01-25 19:02                 ` Kai Henningsen
2002-01-27  1:33                   ` Timothy Covell
2002-01-26  2:56                     ` Jamie Lokier
2002-01-27 11:18                   ` Kai Henningsen
2002-01-25 22:30             ` Timothy Covell
2002-01-24 22:36               ` Alexander Viro
2002-01-25  6:36               ` Kai Henningsen
     [not found]                 ` <200201250900.g0P8xoL10082@home.ashavan.org.>
2002-01-29  6:36                   ` Nix N. Nix
2002-01-25 21:43           ` Timothy Covell
2002-01-24 21:50             ` Oliver Xymoron
2002-01-24 22:21               ` H. Peter Anvin
2002-01-25 15:07                 ` Werner Almesberger
2002-01-25 15:21                   ` Jakub Jelinek
2002-01-25 16:45                   ` H. Peter Anvin
2002-01-25 11:07         ` Helge Hafting
2002-01-24 22:33 ` Chris Wedgwood
2002-01-24 22:44   ` H. Peter Anvin
2002-01-26 10:22     ` Chris Wedgwood
2002-01-25  2:00 ` Erik Andersen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).