<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: Andrey Borzenkov &lt;arvidjaar@mail.ru&gt;

- use struct nameidata in devfs_d_revalidate_wait to detect when it is
  called without i_sem hold; take i_sem on parent in this case.  This
  prevents both deadlock with devfs_lookup by allowing it to drop i_sem
  consistently and oops in d_instantiate by ensuring that it always runs
  protected

- remove dead code that deals with major number allocation.  The only
  remaining user was devfs itself and patch changes it to

- use register_chardev to get device number for internal /dev/.devfsd and
  /dev/.statd.

- remove dead auto allocation flag as well

- remove code that does module get on dev open - it is handled by fops_get.
   Use init_special_inode consistently

- get rid of struct cdev_type and bdev_type - both have just single dev_t
  now



---

 /dev/null       |    3 
 fs/devfs/base.c |  404 +++++++++++++++++++++++++++-----------------------------
 fs/devfs/util.c |  159 ----------------------
 3 files changed, 198 insertions(+), 368 deletions(-)

diff -puN fs/devfs/base.c~devfs-race-fix-cleanup fs/devfs/base.c
--- 25/fs/devfs/base.c~devfs-race-fix-cleanup	2004-02-03 12:23:49.000000000 -0800
+++ 25-akpm/fs/devfs/base.c	2004-02-03 12:23:49.000000000 -0800
@@ -676,6 +676,7 @@
 #include &lt;linux/smp.h&gt;
 #include &lt;linux/rwsem.h&gt;
 #include &lt;linux/sched.h&gt;
+#include &lt;linux/namei.h&gt;
 
 #include &lt;asm/uaccess.h&gt;
 #include &lt;asm/io.h&gt;
@@ -685,9 +686,7 @@
 #include &lt;asm/bitops.h&gt;
 #include &lt;asm/atomic.h&gt;
 
-#include "internal.h"
-
-#define DEVFS_VERSION            "1.22 (20021013)"
+#define DEVFS_VERSION            "2004-01-31"
 
 #define DEVFS_NAME "devfs"
 
@@ -762,18 +761,6 @@ struct directory_type
     unsigned char no_more_additions:1;
 };
 
-struct bdev_type
-{
-    dev_t dev;
-};
-
-struct cdev_type
-{
-    struct file_operations *ops;
-    dev_t dev;
-    unsigned char autogen:1;
-};
-
 struct symlink_type
 {
     unsigned int length;         /*  Not including the NULL-termimator       */
@@ -801,8 +788,7 @@ struct devfs_entry
     union 
     {
 	struct directory_type dir;
-	struct bdev_type bdev;
-	struct cdev_type cdev;
+	dev_t dev;
 	struct symlink_type symlink;
 	const char *name;        /*  Only used for (mode == 0)               */
     }
@@ -813,7 +799,7 @@ struct devfs_entry
     struct devfs_inode inode;
     umode_t mode;
     unsigned short namelen;      /*  I think 64k+ filenames are a way off... */
-    unsigned char vfs_deletable:1;/*  Whether the VFS may delete the entry   */
+    unsigned char vfs:1;/*  Whether the VFS may delete the entry   */
     char name[1];                /*  This is just a dummy: the allocated array
 				     is bigger. This is NULL-terminated      */
 };
@@ -925,8 +911,6 @@ static void devfs_put (devfs_handle_t de
 	     de-&gt;name, de, de-&gt;parent,
 	     de-&gt;parent ? de-&gt;parent-&gt;name : "no parent");
     if ( S_ISLNK (de-&gt;mode) ) kfree (de-&gt;u.symlink.linkname);
-    if ( S_ISCHR (de-&gt;mode) &amp;&amp; de-&gt;u.cdev.autogen )
-	devfs_dealloc_devnum (de-&gt;mode, de-&gt;u.cdev.dev);
     WRITE_ENTRY_MAGIC (de, 0);
 #ifdef CONFIG_DEVFS_DEBUG
     spin_lock (&amp;stat_lock);
@@ -1063,46 +1047,40 @@ static int _devfs_append_entry (devfs_ha
     return retval;
 }   /*  End Function _devfs_append_entry  */
 
-
 /**
  *	_devfs_get_root_entry - Get the root devfs entry.
  *
  *	Returns the root devfs entry on success, else %NULL.
+ *
+ *	TODO it must be called asynchronously due to the fact
+ *	that devfs is initialized relatively late. Proper way
+ *	is to remove module_init from init_devfs_fs and manually
+ *	call it early enough during system init
  */
 
-static struct devfs_entry *_devfs_get_root_entry (void)
+static struct devfs_entry *_devfs_get_root_entry(void)
 {
-    struct devfs_entry *new;
-    static spinlock_t root_lock = SPIN_LOCK_UNLOCKED;
+	struct devfs_entry *new;
+	static spinlock_t root_lock = SPIN_LOCK_UNLOCKED;
 
-    /*  Always ensure the root is created  */
-    if (root_entry) return root_entry;
-    if ( ( new = _devfs_alloc_entry (NULL, 0,MODE_DIR) ) == NULL ) return NULL;
-    spin_lock (&amp;root_lock);
-    if (root_entry)
-    {
-	spin_unlock (&amp;root_lock);
-	devfs_put (new);
-	return (root_entry);
-    }
-    root_entry = new;
-    spin_unlock (&amp;root_lock);
-    /*  And create the entry for ".devfsd"  */
-    if ( ( new = _devfs_alloc_entry (".devfsd", 0, S_IFCHR |S_IRUSR |S_IWUSR) )
-	 == NULL ) return NULL;
-    new-&gt;u.cdev.dev = devfs_alloc_devnum (S_IFCHR |S_IRUSR |S_IWUSR);
-    new-&gt;u.cdev.ops = &amp;devfsd_fops;
-    _devfs_append_entry (root_entry, new, NULL);
-#ifdef CONFIG_DEVFS_DEBUG
-    if ( ( new = _devfs_alloc_entry (".stat", 0, S_IFCHR | S_IRUGO | S_IWUGO) )
-	 == NULL ) return NULL;
-    new-&gt;u.cdev.dev = devfs_alloc_devnum (S_IFCHR | S_IRUGO | S_IWUGO);
-    new-&gt;u.cdev.ops = &amp;stat_fops;
-    _devfs_append_entry (root_entry, new, NULL);
-#endif
-    return root_entry;
-}   /*  End Function _devfs_get_root_entry  */
+	if (root_entry)
+		return root_entry;
 
+	new = _devfs_alloc_entry(NULL, 0, MODE_DIR);
+	if (new == NULL )
+		return NULL;
+
+	spin_lock(&amp;root_lock);
+	if (root_entry) {
+		spin_unlock(&amp;root_lock);
+		devfs_put(new);
+		return root_entry;
+	}
+	root_entry = new;
+	spin_unlock(&amp;root_lock);
+
+	return root_entry;
+}   /*  End Function _devfs_get_root_entry  */
 
 /**
  *	_devfs_descend - Descend down a tree using the next component name.
@@ -1237,6 +1215,7 @@ static devfs_handle_t _devfs_walk_path (
 	}
 	if (S_ISLNK (de-&gt;mode) &amp;&amp; traverse_symlink)
 	{   /*  Need to follow the link: this is a stack chomper  */
+		/* FIXME what if it puts outside of mounted tree? */
 	    link = _devfs_walk_path (dir, de-&gt;u.symlink.linkname,
 				     de-&gt;u.symlink.length, TRUE);
 	    devfs_put (de);
@@ -1444,27 +1423,19 @@ static void devfsd_notify (struct devfs_
 			 current-&gt;egid, &amp;fs_info);
 } 
 
-int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
+static int devfs_mk_dev(dev_t dev, umode_t mode, const char *fmt, va_list args)
 {
 	struct devfs_entry *dir = NULL, *de;
 	char buf[64];
-	va_list args;
 	int error, n;
 
-	va_start(args, fmt);
-	n = vsnprintf(buf, 64, fmt, args);
-	if (n &gt;= 64 || !buf[0]) {
-		printk(KERN_WARNING "%s: invalid format string\n",
-				__FUNCTION__);
+	n = vsnprintf(buf, sizeof(buf), fmt, args);
+	if (n &gt;= sizeof(buf) || !buf[0]) {
+		printk(KERN_WARNING "%s: invalid format string %s\n",
+				__FUNCTION__, fmt);
 		return -EINVAL;
 	}
 	
-	if (!S_ISBLK(mode)) {
-		printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",
-				__FUNCTION__, mode, buf);
-		return -EINVAL;
-	}
-
 	de = _devfs_prepare_leaf(&amp;dir, buf, mode);
 	if (!de) {
 		printk(KERN_WARNING "%s: could not prepare leaf for %s\n",
@@ -1472,7 +1443,7 @@ int devfs_mk_bdev(dev_t dev, umode_t mod
 		return -ENOMEM;		/* could be more accurate... */
 	}
 
-	de-&gt;u.bdev.dev = dev;
+	de-&gt;u.dev = dev;
 
 	error = _devfs_append_entry(dir, de, NULL);
 	if (error) {
@@ -1487,50 +1458,35 @@ int devfs_mk_bdev(dev_t dev, umode_t mod
 	return error;
 }
 
+int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
+{
+	va_list args;
+
+	if (!S_ISBLK(mode)) {
+		printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",
+				__FUNCTION__, mode, fmt);
+		return -EINVAL;
+	}
+
+	va_start(args, fmt);
+	return devfs_mk_dev(dev, mode, fmt, args);
+}
+
 EXPORT_SYMBOL(devfs_mk_bdev);
 
 
 int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...)
 {
-	struct devfs_entry *dir = NULL, *de;
-	char buf[64];
 	va_list args;
-	int error, n;
-
-	va_start(args, fmt);
-	n = vsnprintf(buf, 64, fmt, args);
-	if (n &gt;= 64 || !buf[0]) {
-		printk(KERN_WARNING "%s: invalid format string\n",
-				__FUNCTION__);
-		return -EINVAL;
-	}
 
 	if (!S_ISCHR(mode)) {
 		printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",
-				__FUNCTION__, mode, buf);
+				__FUNCTION__, mode, fmt);
 		return -EINVAL;
 	}
 
-	de = _devfs_prepare_leaf(&amp;dir, buf, mode);
-	if (!de) {
-		printk(KERN_WARNING "%s: could not prepare leaf for %s\n",
-				__FUNCTION__, buf);
-		return -ENOMEM;		/* could be more accurate... */
-	}
-
-	de-&gt;u.cdev.dev = dev;
-
-	error = _devfs_append_entry(dir, de, NULL);
-	if (error) {
-		printk(KERN_WARNING "%s: could not append to parent for %s\n",
-				__FUNCTION__, buf);
-		goto out;
-	}
-
-	devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED);
- out:
-	devfs_put(dir);
-	return error;
+	va_start(args, fmt);
+	return devfs_mk_dev(dev, mode, fmt, args);
 }
 
 EXPORT_SYMBOL(devfs_mk_cdev);
@@ -1663,7 +1619,7 @@ int devfs_mk_symlink(const char *from, c
 
 	err = devfs_do_symlink(NULL, from, to, &amp;de);
 	if (!err) {
-		de-&gt;vfs_deletable = TRUE;
+		de-&gt;vfs = TRUE;
 		devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED);
 	}
 
@@ -1732,8 +1688,8 @@ void devfs_remove(const char *fmt, ...)
 	int n;
 
 	va_start(args, fmt);
-	n = vsnprintf(buf, 64, fmt, args);
-	if (n &lt; 64 &amp;&amp; buf[0]) {
+	n = vsnprintf(buf, sizeof(buf), fmt, args);
+	if (n &lt; sizeof(buf) &amp;&amp; buf[0]) {
 		devfs_handle_t de = _devfs_find_entry(NULL, buf, 0);
 
 		if (!de) {
@@ -1784,33 +1740,6 @@ static int devfs_generate_path (devfs_ha
     return pos;
 }   /*  End Function devfs_generate_path  */
 
-
-/**
- *	devfs_get_ops - Get the device operations for a devfs entry.
- *	@de: The handle to the device entry.
- *
- *	Returns a pointer to the device operations on success, else NULL.
- *	The use count for the module owning the operations will be incremented.
- */
-
-static struct file_operations *devfs_get_ops (devfs_handle_t de)
-{
-    struct file_operations *ops = de-&gt;u.cdev.ops;
-    struct module *owner;
-
-    if (!ops)
-	return NULL;
-    owner = ops-&gt;owner;
-    read_lock (&amp;de-&gt;parent-&gt;u.dir.lock);  /*  Prevent module from unloading  */
-    if ( (de-&gt;next == de) || !try_module_get (owner) )
-    {   /*  Entry is already unhooked or module is unloading  */
-	read_unlock (&amp;de-&gt;parent-&gt;u.dir.lock);
-	return NULL;
-    }
-    read_unlock (&amp;de-&gt;parent-&gt;u.dir.lock);  /*  Module can continue unloading*/
-    return ops;
-}   /*  End Function devfs_get_ops  */
-
 /**
  *	devfs_setup - Process kernel boot options.
  *	@str: The boot options after the "devfs=".
@@ -1876,7 +1805,6 @@ static int __init devfs_setup (char *str
 
 __setup("devfs=", devfs_setup);
 
-EXPORT_SYMBOL(devfs_put);
 EXPORT_SYMBOL(devfs_mk_symlink);
 EXPORT_SYMBOL(devfs_mk_dir);
 EXPORT_SYMBOL(devfs_remove);
@@ -1996,6 +1924,7 @@ static struct inode *_devfs_get_vfs_inod
 	iput (inode);
 	return NULL;
     }
+    /* FIXME where is devfs_put? */
     inode-&gt;u.generic_ip = devfs_get (de);
     inode-&gt;i_ino = de-&gt;inode.ino;
     DPRINTK (DEBUG_I_GET, "(%d): VFS inode: %p  devfs_entry: %p\n",
@@ -2003,26 +1932,25 @@ static struct inode *_devfs_get_vfs_inod
     inode-&gt;i_blocks = 0;
     inode-&gt;i_blksize = FAKE_BLOCK_SIZE;
     inode-&gt;i_op = &amp;devfs_iops;
-    inode-&gt;i_fop = &amp;devfs_fops;
-    if ( S_ISCHR (de-&gt;mode) )
-    {
-	inode-&gt;i_rdev = de-&gt;u.cdev.dev;
-    }
-    else if ( S_ISBLK (de-&gt;mode) )
-	init_special_inode(inode, de-&gt;mode, de-&gt;u.bdev.dev);
-    else if ( S_ISFIFO (de-&gt;mode) )
-    	inode-&gt;i_fop = &amp;def_fifo_fops;
-    else if ( S_ISDIR (de-&gt;mode) )
-    {
-	inode-&gt;i_op = &amp;devfs_dir_iops;
-    	inode-&gt;i_fop = &amp;devfs_dir_fops;
-    }
-    else if ( S_ISLNK (de-&gt;mode) )
-    {
-	inode-&gt;i_op = &amp;devfs_symlink_iops;
-	inode-&gt;i_size = de-&gt;u.symlink.length;
-    }
     inode-&gt;i_mode = de-&gt;mode;
+	if (S_ISDIR(de-&gt;mode)) {
+		inode-&gt;i_op = &amp;devfs_dir_iops;
+		inode-&gt;i_fop = &amp;devfs_dir_fops;
+	} else if (S_ISLNK(de-&gt;mode)) {
+		inode-&gt;i_op = &amp;devfs_symlink_iops;
+		inode-&gt;i_size = de-&gt;u.symlink.length;
+	} else if (S_ISCHR(de-&gt;mode) || S_ISBLK(de-&gt;mode)) {
+		init_special_inode(inode, de-&gt;mode, de-&gt;u.dev);
+	} else if (S_ISFIFO(de-&gt;mode) || S_ISSOCK(de-&gt;mode)) {
+		init_special_inode(inode, de-&gt;mode, 0);
+	} else {
+		PRINTK("(%s): unknown mode %o de: %p\n",
+			de-&gt;name, de-&gt;mode, de);
+		iput(inode);
+		devfs_put(de);
+		return NULL;
+	}
+
     inode-&gt;i_uid = de-&gt;inode.uid;
     inode-&gt;i_gid = de-&gt;inode.gid;
     inode-&gt;i_atime = de-&gt;inode.atime;
@@ -2098,29 +2026,37 @@ static int devfs_readdir (struct file *f
     return stored;
 }   /*  End Function devfs_readdir  */
 
+/* Open devfs specific special files */
 static int devfs_open (struct inode *inode, struct file *file)
 {
-    int err = -ENODEV;
-    struct devfs_entry *de;
-    struct file_operations *ops;
+	int err;
+	int minor = MINOR(inode-&gt;i_rdev);
+	struct file_operations *old_fops, *new_fops;
 
-    de = get_devfs_entry_from_vfs_inode (inode);
-    if (de == NULL) return -ENODEV;
-    if ( S_ISDIR (de-&gt;mode) ) return 0;
-    file-&gt;private_data = de-&gt;info;
-    if (S_ISCHR(inode-&gt;i_mode)) {
-	ops = devfs_get_ops (de);  /*  Now have module refcount  */
-	file-&gt;f_op = ops;
-	if (file-&gt;f_op)
-	{
-	    lock_kernel ();
-	    err = file-&gt;f_op-&gt;open ? (*file-&gt;f_op-&gt;open) (inode, file) : 0;
-	    unlock_kernel ();
+	switch (minor) {
+	case 0: /* /dev/.devfsd */
+		new_fops = fops_get(&amp;devfsd_fops);
+		break;
+#ifdef CONFIG_DEVFS_DEBUG
+	case 1: /* /dev/.stat */
+		new_fops = fops_get(&amp;stat_fops);
+		break;
+#endif
+	default:
+		return -ENODEV;
 	}
-	else
-	    err = chrdev_open (inode, file);
-    }
-    return err;
+
+	if (new_fops == NULL)
+		return -ENODEV;
+	old_fops = file-&gt;f_op;
+	file-&gt;f_op = new_fops;
+	err = new_fops-&gt;open ? new_fops-&gt;open(inode, file) : 0;
+	if (err) {
+		file-&gt;f_op = old_fops;
+		fops_put(new_fops);
+	} else
+		fops_put(old_fops);
+	return err;
 }   /*  End Function devfs_open  */
 
 static struct file_operations devfs_fops =
@@ -2132,7 +2068,6 @@ static struct file_operations devfs_dir_
 {
     .read    = generic_read_dir,
     .readdir = devfs_readdir,
-    .open    = devfs_open,
 };
 
 
@@ -2223,6 +2158,34 @@ static int devfs_d_revalidate_wait (stru
     devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
     struct devfs_lookup_struct *lookup_info = dentry-&gt;d_fsdata;
     DECLARE_WAITQUEUE (wait, current);
+    int need_lock;
+
+    /*
+     * FIXME HACK
+     *
+     * make sure that
+     *   d_instantiate always runs under lock
+     *   we release i_sem lock before going to sleep
+     *
+     * unfortunately sometimes d_revalidate is called with
+     * and sometimes without i_sem lock held. The following checks
+     * attempt to deduce when we need to add (and drop resp.) lock
+     * here. This relies on current (2.6.2) calling coventions:
+     *
+     *   lookup_hash is always run under i_sem and is passing NULL
+     *   as nd
+     *
+     *   open(...,O_CREATE,...) calls _lookup_hash under i_sem
+     *   and sets flags to LOOKUP_OPEN|LOOKUP_CREATE
+     *
+     *   all other invocations of -&gt;d_revalidate seem to happen
+     *   outside of i_sem
+     */
+    need_lock = nd &amp;&amp;
+		(!(nd-&gt;flags &amp; LOOKUP_CREATE) || (nd-&gt;flags &amp; LOOKUP_PARENT));
+
+    if (need_lock)
+	down(&amp;dir-&gt;i_sem);
 
     if ( is_devfsd_or_child (fs_info) )
     {
@@ -2233,33 +2196,40 @@ static int devfs_d_revalidate_wait (stru
 		 "(%s): dentry: %p inode: %p de: %p by: \"%s\"\n",
 		 dentry-&gt;d_name.name, dentry, dentry-&gt;d_inode, de,
 		 current-&gt;comm);
-	if (dentry-&gt;d_inode) return 1;
+	if (dentry-&gt;d_inode)
+	    goto out;
 	if (de == NULL)
 	{
 	    read_lock (&amp;parent-&gt;u.dir.lock);
 	    de = _devfs_search_dir (parent, dentry-&gt;d_name.name,
 				    dentry-&gt;d_name.len);
 	    read_unlock (&amp;parent-&gt;u.dir.lock);
-	    if (de == NULL) return 1;
+	    if (de == NULL)
+		goto out;
 	    lookup_info-&gt;de = de;
 	}
 	/*  Create an inode, now that the driver information is available  */
 	inode = _devfs_get_vfs_inode (dir-&gt;i_sb, de, dentry);
-	if (!inode) return 1;
+	if (!inode)
+	    goto out;
 	DPRINTK (DEBUG_I_LOOKUP,
 		 "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
 		 de-&gt;name, de-&gt;inode.ino, inode, de, current-&gt;comm);
 	d_instantiate (dentry, inode);
-	return 1;
+	goto out;
     }
-    if (lookup_info == NULL) return 1;  /*  Early termination  */
+    if (lookup_info == NULL)
+	goto out;  /*  Early termination  */
     read_lock (&amp;parent-&gt;u.dir.lock);
     if (dentry-&gt;d_fsdata)
     {
 	set_current_state (TASK_UNINTERRUPTIBLE);
 	add_wait_queue (&amp;lookup_info-&gt;wait_queue, &amp;wait);
 	read_unlock (&amp;parent-&gt;u.dir.lock);
+	/* at this point it is always (hopefully) locked */
+	up(&amp;dir-&gt;i_sem);
 	schedule ();
+	down(&amp;dir-&gt;i_sem);
 	/*
 	 * This does not need nor should remove wait from wait_queue.
 	 * Wait queue head is never reused - nothing is ever added to it
@@ -2271,6 +2241,10 @@ static int devfs_d_revalidate_wait (stru
 
     }
     else read_unlock (&amp;parent-&gt;u.dir.lock);
+
+out:
+    if (need_lock)
+	up(&amp;dir-&gt;i_sem);
     return 1;
 }   /*  End Function devfs_d_revalidate_wait  */
 
@@ -2320,6 +2294,7 @@ static struct dentry *devfs_lookup (stru
 	revalidation  */
     up (&amp;dir-&gt;i_sem);
     wait_for_devfsd_finished (fs_info);  /*  If I'm not devfsd, must wait  */
+    down (&amp;dir-&gt;i_sem);      /*  Grab it again because them's the rules  */
     de = lookup_info.de;
     /*  If someone else has been so kind as to make the inode, we go home
 	early  */
@@ -2349,7 +2324,6 @@ out:
     dentry-&gt;d_fsdata = NULL;
     wake_up (&amp;lookup_info.wait_queue);
     write_unlock (&amp;parent-&gt;u.dir.lock);
-    down (&amp;dir-&gt;i_sem);      /*  Grab it again because them's the rules  */
     devfs_put (de);
     return retval;
 }   /*  End Function devfs_lookup  */
@@ -2364,7 +2338,7 @@ static int devfs_unlink (struct inode *d
     de = get_devfs_entry_from_vfs_inode (inode);
     DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry-&gt;d_name.name, de);
     if (de == NULL) return -ENOENT;
-    if (!de-&gt;vfs_deletable) return -EPERM;
+    if (!de-&gt;vfs) return -EPERM;
     write_lock (&amp;de-&gt;parent-&gt;u.dir.lock);
     unhooked = _devfs_unhook (de);
     write_unlock (&amp;de-&gt;parent-&gt;u.dir.lock);
@@ -2392,7 +2366,7 @@ static int devfs_symlink (struct inode *
     DPRINTK (DEBUG_DISABLED, "(%s): errcode from &lt;devfs_do_symlink&gt;: %d\n",
 	     dentry-&gt;d_name.name, err);
     if (err &lt; 0) return err;
-    de-&gt;vfs_deletable = TRUE;
+    de-&gt;vfs = TRUE;
     de-&gt;inode.uid = current-&gt;euid;
     de-&gt;inode.gid = current-&gt;egid;
     de-&gt;inode.atime = CURRENT_TIME;
@@ -2421,7 +2395,7 @@ static int devfs_mkdir (struct inode *di
     if (parent == NULL) return -ENOENT;
     de = _devfs_alloc_entry (dentry-&gt;d_name.name, dentry-&gt;d_name.len, mode);
     if (!de) return -ENOMEM;
-    de-&gt;vfs_deletable = TRUE;
+    de-&gt;vfs = TRUE;
     if ( ( err = _devfs_append_entry (parent, de, NULL) ) != 0 )
 	return err;
     de-&gt;inode.uid = current-&gt;euid;
@@ -2451,7 +2425,7 @@ static int devfs_rmdir (struct inode *di
     de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENOENT;
     if ( !S_ISDIR (de-&gt;mode) ) return -ENOTDIR;
-    if (!de-&gt;vfs_deletable) return -EPERM;
+    if (!de-&gt;vfs) return -EPERM;
     /*  First ensure the directory is empty and will stay that way  */
     write_lock (&amp;de-&gt;u.dir.lock);
     if (de-&gt;u.dir.first) err = -ENOTEMPTY;
@@ -2485,11 +2459,9 @@ static int devfs_mknod (struct inode *di
     if (parent == NULL) return -ENOENT;
     de = _devfs_alloc_entry (dentry-&gt;d_name.name, dentry-&gt;d_name.len, mode);
     if (!de) return -ENOMEM;
-    de-&gt;vfs_deletable = TRUE;
-    if (S_ISCHR (mode))
-	de-&gt;u.cdev.dev = rdev;
-    else if (S_ISBLK (mode))
-	de-&gt;u.bdev.dev = rdev;
+    de-&gt;vfs = TRUE;
+    if (S_ISCHR(mode) || S_ISBLK(mode))
+	de-&gt;u.dev = rdev;
     if ( ( err = _devfs_append_entry (parent, de, NULL) ) != 0 )
 	return err;
     de-&gt;inode.uid = current-&gt;euid;
@@ -2642,12 +2614,9 @@ static ssize_t devfsd_read (struct file 
     info-&gt;uid = entry-&gt;uid;
     info-&gt;gid = entry-&gt;gid;
     de = entry-&gt;de;
-    if (S_ISCHR(de-&gt;mode)) {
-	info-&gt;major = MAJOR(de-&gt;u.cdev.dev);
-	info-&gt;minor = MINOR(de-&gt;u.cdev.dev);
-    } else if (S_ISBLK (de-&gt;mode)) {
-	info-&gt;major = MAJOR(de-&gt;u.bdev.dev);
-	info-&gt;minor = MINOR(de-&gt;u.bdev.dev);
+    if (S_ISCHR(de-&gt;mode) || S_ISBLK(de-&gt;mode)) {
+	info-&gt;major = MAJOR(de-&gt;u.dev);
+	info-&gt;minor = MINOR(de-&gt;u.dev);
     }
     pos = devfs_generate_path (de, info-&gt;devname, DEVFS_PATHLEN);
     if (pos &lt; 0) return pos;
@@ -2809,30 +2778,53 @@ static ssize_t stat_read (struct file *f
 }   /*  End Function stat_read  */
 #endif
 
-
-static int __init init_devfs_fs (void)
+static int __init init_devfs_fs(void)
 {
-    int err;
+	int err;
+	int major;
+	struct devfs_entry *devfsd;
+#ifdef CONFIG_DEVFS_DEBUG
+	struct devfs_entry *stat;
+#endif
 
-    printk (KERN_INFO "%s: v%s Richard Gooch (rgooch@atnf.csiro.au)\n",
-	    DEVFS_NAME, DEVFS_VERSION);
-    devfsd_buf_cache = kmem_cache_create ("devfsd_event",
+	if (_devfs_get_root_entry() == NULL)
+		return -ENOMEM;
+
+	printk(KERN_INFO "%s: %s Richard Gooch (rgooch@atnf.csiro.au)\n",
+	       DEVFS_NAME, DEVFS_VERSION);
+	devfsd_buf_cache = kmem_cache_create("devfsd_event",
 					  sizeof (struct devfsd_buf_entry),
 					  0, 0, NULL, NULL);
-    if (!devfsd_buf_cache) OOPS ("(): unable to allocate event slab\n");
+	if (!devfsd_buf_cache)
+		OOPS("(): unable to allocate event slab\n");
 #ifdef CONFIG_DEVFS_DEBUG
-    devfs_debug = devfs_debug_init;
-    printk (KERN_INFO "%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug);
+	devfs_debug = devfs_debug_init;
+	printk(KERN_INFO "%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug);
 #endif
-    printk (KERN_INFO "%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options);
-    err = register_filesystem (&amp;devfs_fs_type);
-    if (!err)
-    {
-	struct vfsmount *devfs_mnt = kern_mount (&amp;devfs_fs_type);
-	err = PTR_ERR (devfs_mnt);
-	if ( !IS_ERR (devfs_mnt) ) err = 0;
-    }
-    return err;
+	printk(KERN_INFO "%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options);
+
+	/* register special device for devfsd communication */
+	major = register_chrdev(0, "devfs", &amp;devfs_fops);
+	if (major &lt; 0)
+		return major;
+
+	/*  And create the entry for ".devfsd"  */
+	devfsd = _devfs_alloc_entry(".devfsd", 0, S_IFCHR|S_IRUSR|S_IWUSR);
+	if (devfsd == NULL )
+		return -ENOMEM;
+	devfsd-&gt;u.dev = MKDEV(major, 0);
+	_devfs_append_entry(root_entry, devfsd, NULL);
+
+#ifdef CONFIG_DEVFS_DEBUG
+	stat = _devfs_alloc_entry(".stat", 0, S_IFCHR|S_IRUGO);
+	if (stat == NULL )
+		return -ENOMEM;
+	stat-&gt;u.dev = MKDEV(major, 1);
+	_devfs_append_entry (root_entry, stat, NULL);
+#endif
+
+	err = register_filesystem(&amp;devfs_fs_type);
+	return err;
 }   /*  End Function init_devfs_fs  */
 
 void __init mount_devfs_fs (void)
diff -puN -L fs/devfs/internal.h fs/devfs/internal.h~devfs-race-fix-cleanup /dev/null
--- 25/fs/devfs/internal.h
+++ /dev/null	2002-08-30 16:31:37.000000000 -0700
@@ -1,3 +0,0 @@
-
-extern dev_t devfs_alloc_devnum(umode_t mode);
-extern void devfs_dealloc_devnum(umode_t mode, dev_t devnum);
diff -puN fs/devfs/util.c~devfs-race-fix-cleanup fs/devfs/util.c
--- 25/fs/devfs/util.c~devfs-race-fix-cleanup	2004-02-03 12:23:49.000000000 -0800
+++ 25-akpm/fs/devfs/util.c	2004-02-03 12:23:49.000000000 -0800
@@ -72,7 +72,6 @@
 #include &lt;linux/vmalloc.h&gt;
 #include &lt;linux/genhd.h&gt;
 #include &lt;asm/bitops.h&gt;
-#include "internal.h"
 
 
 int devfs_register_tape(const char *name)
@@ -96,161 +95,3 @@ void devfs_unregister_tape(int num)
 }
 
 EXPORT_SYMBOL(devfs_unregister_tape);
-
-struct major_list
-{
-    spinlock_t lock;
-    unsigned long bits[256 / BITS_PER_LONG];
-};
-#if BITS_PER_LONG == 32
-#  define INITIALISER64(low,high) (low), (high)
-#else
-#  define INITIALISER64(low,high) ( (unsigned long) (high) &lt;&lt; 32 | (low) )
-#endif
-
-/*  Block majors already assigned:
-    0-3, 7-9, 11-63, 65-99, 101-113, 120-127, 199, 201, 240-255
-    Total free: 122
-*/
-static struct major_list block_major_list =
-{SPIN_LOCK_UNLOCKED,
-    {INITIALISER64 (0xfffffb8f, 0xffffffff),  /*  Majors 0-31,    32-63    */
-     INITIALISER64 (0xfffffffe, 0xff03ffef),  /*  Majors 64-95,   96-127   */
-     INITIALISER64 (0x00000000, 0x00000000),  /*  Majors 128-159, 160-191  */
-     INITIALISER64 (0x00000280, 0xffff0000),  /*  Majors 192-223, 224-255  */
-    }
-};
-
-/*  Char majors already assigned:
-    0-7, 9-151, 154-158, 160-211, 216-221, 224-230, 240-255
-    Total free: 19
-*/
-static struct major_list char_major_list =
-{SPIN_LOCK_UNLOCKED,
-    {INITIALISER64 (0xfffffeff, 0xffffffff),  /*  Majors 0-31,    32-63    */
-     INITIALISER64 (0xffffffff, 0xffffffff),  /*  Majors 64-95,   96-127   */
-     INITIALISER64 (0x7cffffff, 0xffffffff),  /*  Majors 128-159, 160-191  */
-     INITIALISER64 (0x3f0fffff, 0xffff007f),  /*  Majors 192-223, 224-255  */
-    }
-};
-
-
-/**
- *	devfs_alloc_major - Allocate a major number.
- *	@mode: The file mode (must be block device or character device).
- *	Returns the allocated major, else -1 if none are available.
- *	This routine is thread safe and does not block.
- */
-
-
-struct minor_list
-{
-    int major;
-    unsigned long bits[256 / BITS_PER_LONG];
-    struct minor_list *next;
-};
-
-static struct device_list {
-	struct minor_list	*first;
-	struct minor_list	*last;
-	int			none_free;
-} block_list, char_list;
-
-static DECLARE_MUTEX(device_list_mutex);
-
-
-/**
- *	devfs_alloc_devnum - Allocate a device number.
- *	@mode: The file mode (must be block device or character device).
- *
- *	Returns the allocated device number, else NODEV if none are available.
- *	This routine is thread safe and may block.
- */
-
-dev_t devfs_alloc_devnum(umode_t mode)
-{
-	struct device_list *list;
-	struct major_list *major_list;
-	struct minor_list *entry;
-	int minor;
-
-	if (S_ISCHR(mode)) {
-		major_list = &amp;char_major_list;
-		list = &amp;char_list;
-	} else {
-		major_list = &amp;block_major_list;
-		list = &amp;block_list;
-	}
-
-	down(&amp;device_list_mutex);
-	if (list-&gt;none_free)
-		goto out_unlock;
-
-	for (entry = list-&gt;first; entry; entry = entry-&gt;next) {
-		minor = find_first_zero_bit (entry-&gt;bits, 256);
-		if (minor &gt;= 256)
-			continue;
-		goto out_done;
-	}
-	
-	/*  Need to allocate a new major  */
-	entry = kmalloc (sizeof *entry, GFP_KERNEL);
-	if (!entry)
-		goto out_full;
-	memset(entry, 0, sizeof *entry);
-
-	spin_lock(&amp;major_list-&gt;lock);
-	entry-&gt;major = find_first_zero_bit(major_list-&gt;bits, 256);
-	if (entry-&gt;major &gt;= 256) {
-		spin_unlock(&amp;major_list-&gt;lock);
-		kfree(entry);
-		goto out_full;
-	}
-	__set_bit(entry-&gt;major, major_list-&gt;bits);
-	spin_unlock(&amp;major_list-&gt;lock);
-
-	if (!list-&gt;first)
-		list-&gt;first = entry;
-	else
-		list-&gt;last-&gt;next = entry;
-	list-&gt;last = entry;
-
-	minor = 0;
- out_done:
-	__set_bit(minor, entry-&gt;bits);
-	up(&amp;device_list_mutex);
-	return MKDEV(entry-&gt;major, minor);
- out_full:
-	list-&gt;none_free = 1;
- out_unlock:
-	up(&amp;device_list_mutex);
-	return 0;
-}
-
-
-/**
- *	devfs_dealloc_devnum - Dellocate a device number.
- *	@mode: The file mode (must be block device or character device).
- *	@devnum: The device number.
- *
- *	This routine is thread safe and may block.
- */
-
-void devfs_dealloc_devnum(umode_t mode, dev_t devnum)
-{
-	struct device_list *list = S_ISCHR(mode) ? &amp;char_list : &amp;block_list;
-	struct minor_list *entry;
-
-	if (!devnum)
-		return;
-
-	down(&amp;device_list_mutex);
-	for (entry = list-&gt;first; entry; entry = entry-&gt;next) {
-		if (entry-&gt;major == MAJOR(devnum)) {
-			if (__test_and_clear_bit(MINOR(devnum), entry-&gt;bits))
-				list-&gt;none_free = 0;
-			break;
-		}
-	}
-	up(&amp;device_list_mutex);
-}

_
</pre></body></html>