Commit 1cf2ec10 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] devfs deadlock fix

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.
parent 934acf6c
...@@ -2350,7 +2350,6 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry, st ...@@ -2350,7 +2350,6 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry, st
revalidation */ revalidation */
up (&dir->i_sem); up (&dir->i_sem);
wait_for_devfsd_finished (fs_info); /* If I'm not devfsd, must wait */ 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; de = lookup_info->de;
/* If someone else has been so kind as to make the inode, we go home /* If someone else has been so kind as to make the inode, we go home
early */ early */
...@@ -2381,6 +2380,7 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry, st ...@@ -2381,6 +2380,7 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry, st
wake_up (&lookup_info->wait_queue); wake_up (&lookup_info->wait_queue);
put_devfs_lookup_struct(lookup_info); put_devfs_lookup_struct(lookup_info);
write_unlock (&parent->u.dir.lock); write_unlock (&parent->u.dir.lock);
down (&dir->i_sem); /* Grab it again because them's the rules */
devfs_put (de); devfs_put (de);
return retval; return retval;
} /* End Function devfs_lookup */ } /* End Function devfs_lookup */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment