From: Andrey Borzenkov <arvidjaar@mail.ru>

I finally hit a painfully trivial way to reproduce another long standing devfs 
problem - deadlock between devfs_lookup and devfs_d_revalidate_wait. When 
devfs_lookup releases directory i_sem devfs_d_revalidate_wait grabs it (it 
happens not for every path) and goes to wait to be waked up. Unfortunately, 
devfs_lookup attempts to acquire directory i_sem before ever waking it up ...

To reproduce (2.5.74 UP or SMP - does not matter, single CPU system)

ls /dev/foo & rm -f /dev/foo &

or possibly in a loop but then it easily fills up process table. In my case it 
hangs 100% reliably - on 2.5 OR 2.4.

The current fix is to move re-acquire of i_sem after all
devfs_d_revalidate_wait waiters have been waked up.  Much better fix would be
to ensure that ->d_revalidate either is always called under i_sem or always
without.  But that means the very heart of VFS and I do not dare to touch it.

The fix has been tested on 2.4 (and is part of unofficial Mandrake Club
kernel); I expected the same bug is in 2.5; I just was stupid not seeing the
way to reproduce it before.




 25-akpm/fs/devfs/base.c |    2 +-
 1 files changed, 1 insertion(+), 1 deletion(-)

diff -puN fs/devfs/base.c~devfs-deadlock-fix fs/devfs/base.c
--- 25/fs/devfs/base.c~devfs-deadlock-fix	Mon Jul  7 13:40:47 2003
+++ 25-akpm/fs/devfs/base.c	Mon Jul  7 13:40:47 2003
@@ -2350,7 +2350,6 @@ static struct dentry *devfs_lookup (stru
 	revalidation  */
     up (&dir->i_sem);
     wait_for_devfsd_finished (fs_info);  /*  If I'm not devfsd, must wait  */
-    down (&dir->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  */
@@ -2381,6 +2380,7 @@ out:
     wake_up (&lookup_info->wait_queue);
     put_devfs_lookup_struct(lookup_info);
     write_unlock (&parent->u.dir.lock);
+    down (&dir->i_sem);      /*  Grab it again because them's the rules  */
     devfs_put (de);
     return retval;
 }   /*  End Function devfs_lookup  */

_