
From: Andrey Borzenkov <arvidjaar@mail.ru>

A while back Andrey fixed a devfs bug in which we were running
remove_wait_queue() against a wait_queue_head which was on another process's
stack, and which had gone out of scope.

The patch reverts that fix and does it the same way as 2.4: just leave the
waitqueue struct dangling on the waitqueue_head: there is no need to touch it
at all.

It adds a big comment explaining why we are doing this nasty thing.



 fs/devfs/base.c |   65 ++++++++++++--------------------------------------------
 1 files changed, 15 insertions(+), 50 deletions(-)

diff -puN fs/devfs/base.c~devfs_lookup-revert-and-refix fs/devfs/base.c
--- 25/fs/devfs/base.c~devfs_lookup-revert-and-refix	2003-07-26 10:25:55.000000000 -0700
+++ 25-akpm/fs/devfs/base.c	2003-07-26 10:25:55.000000000 -0700
@@ -2221,46 +2221,8 @@ struct devfs_lookup_struct
 {
     devfs_handle_t de;
     wait_queue_head_t wait_queue;
-    atomic_t count;
 };
 
-static struct devfs_lookup_struct *
-new_devfs_lookup_struct(void)
-{
-	struct devfs_lookup_struct *p = kmalloc(sizeof(*p), GFP_KERNEL);
-
-	if (!p)
-		return NULL;
-
-	init_waitqueue_head (&p->wait_queue);
-	atomic_set(&p->count, 1);
-	return p;
-}
-
-static void
-get_devfs_lookup_struct(struct devfs_lookup_struct *info)
-{
-	if (info)
-		atomic_inc(&info->count);
-	else {
-		printk(KERN_ERR "null devfs_lookup_struct pointer\n");
-		dump_stack();
-	}
-}
-
-static void
-put_devfs_lookup_struct(struct devfs_lookup_struct *info)
-{
-	if (info) {
-		if (!atomic_dec_and_test(&info->count))
-			return;
-		kfree(info);
-	} else {
-		printk(KERN_ERR "null devfs_lookup_struct pointer\n");
-		dump_stack();
-	}
-}
-
 /* XXX: this doesn't handle the case where we got a negative dentry
         but a devfs entry has been registered in the meanwhile */
 static int devfs_d_revalidate_wait (struct dentry *dentry, struct nameidata *nd)
@@ -2303,13 +2265,19 @@ static int devfs_d_revalidate_wait (stru
     read_lock (&parent->u.dir.lock);
     if (dentry->d_fsdata)
     {
-	get_devfs_lookup_struct(lookup_info);
 	set_current_state (TASK_UNINTERRUPTIBLE);
 	add_wait_queue (&lookup_info->wait_queue, &wait);
 	read_unlock (&parent->u.dir.lock);
 	schedule ();
-	remove_wait_queue (&lookup_info->wait_queue, &wait);
-	put_devfs_lookup_struct(lookup_info);
+	/*
+	 * This does not need nor should remove wait from wait_queue.
+	 * Wait queue head is never reused - nothing is ever added to it
+	 * after all waiters have been waked up and head itself disappears
+	 * very soon after it. Moreover it is local variable on stack that
+	 * is likely to have already disappeared so any reference to it
+	 * at this point is buggy.
+	 */
+
     }
     else read_unlock (&parent->u.dir.lock);
     return 1;
@@ -2321,7 +2289,7 @@ static int devfs_d_revalidate_wait (stru
 static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
     struct devfs_entry tmp;  /*  Must stay in scope until devfsd idle again  */
-    struct devfs_lookup_struct *lookup_info;
+    struct devfs_lookup_struct lookup_info;
     struct fs_info *fs_info = dir->i_sb->s_fs_info;
     struct devfs_entry *parent, *de;
     struct inode *inode;
@@ -2338,10 +2306,9 @@ static struct dentry *devfs_lookup (stru
     read_lock (&parent->u.dir.lock);
     de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len);
     read_unlock (&parent->u.dir.lock);
-    lookup_info = new_devfs_lookup_struct();
-    if (!lookup_info) return ERR_PTR(-ENOMEM);
-    lookup_info->de = de;
-    dentry->d_fsdata = lookup_info;
+    lookup_info.de = de;
+    init_waitqueue_head (&lookup_info.wait_queue);
+    dentry->d_fsdata = &lookup_info;
     if (de == NULL)
     {   /*  Try with devfsd. For any kind of failure, leave a negative dentry
 	    so someone else can deal with it (in the case where the sysadmin
@@ -2351,7 +2318,6 @@ static struct dentry *devfs_lookup (stru
 	if (try_modload (parent, fs_info,
 			 dentry->d_name.name, dentry->d_name.len, &tmp) < 0)
 	{   /*  Lookup event was not queued to devfsd  */
-	    put_devfs_lookup_struct(lookup_info);
 	    d_add (dentry, NULL);
 	    return NULL;
 	}
@@ -2363,7 +2329,7 @@ static struct dentry *devfs_lookup (stru
 	revalidation  */
     up (&dir->i_sem);
     wait_for_devfsd_finished (fs_info);  /*  If I'm not devfsd, must wait  */
-    de = lookup_info->de;
+    de = lookup_info.de;
     /*  If someone else has been so kind as to make the inode, we go home
 	early  */
     if (dentry->d_inode) goto out;
@@ -2390,8 +2356,7 @@ out:
     write_lock (&parent->u.dir.lock);
     dentry->d_op = &devfs_dops;
     dentry->d_fsdata = NULL;
-    wake_up (&lookup_info->wait_queue);
-    put_devfs_lookup_struct(lookup_info);
+    wake_up (&lookup_info.wait_queue);
     write_unlock (&parent->u.dir.lock);
     down (&dir->i_sem);      /*  Grab it again because them's the rules  */
     devfs_put (de);

_
