linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Andrey Borzenkov <arvidjaar@mail.ru>
To: Andrew Morton <akpm@osdl.org>
Cc: linux-kernel@vger.kernel.org, devfs@oss.sgi.com
Subject: [PATCH][2.5.74] devfs lookup deadlock/stack corruption combined patch
Date: Mon, 7 Jul 2003 23:06:15 +0400	[thread overview]
Message-ID: <200307072306.15995.arvidjaar@mail.ru> (raw)
In-Reply-To: <20030706175405.518f680d.akpm@osdl.org>

[-- Attachment #1: Type: text/plain, Size: 1783 bytes --]

On Monday 07 July 2003 04:54, you wrote:
> Actually, don't bother.  This idea can be made to work, but
> we already have enough tricky stuff in the wait/wakeup area.
>
> Let's run with your original patch.
>

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.

Attached is combined patch and fix for deadlock only (to show it alone). 
Andrew, I slightly polished original stack corruption version to look more 
consistent with the rest of devfs; also removed NULL pointer checks - let it 
just BUG in this case if it happens.

I have already sent the patch for 2.4 two times - please, could somebody 
finally either apply it or explain what is wrong with it. Richard is out of 
reach apparently and the bug is real and seen by many people.

regards

-andrey

[-- Attachment #2: 2.5.74-devfs_combined.patch --]
[-- Type: text/x-diff, Size: 4211 bytes --]

--- linux-2.5.74-smp/fs/devfs/base.c.deadlock	2003-06-23 19:46:44.000000000 +0400
+++ linux-2.5.74-smp/fs/devfs/base.c	2003-07-07 22:38:35.000000000 +0400
@@ -2208,8 +2208,38 @@ 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 *info = kmalloc (sizeof (*info), GFP_KERNEL);
+
+    if (info == NULL) {
+	PRINTK ("(): cannot allocate memory\n");
+	return NULL;
+    }
+
+    init_waitqueue_head (&info->wait_queue);
+    atomic_set (&info->count, 1);
+    DPRINTK (DEBUG_I_LOOKUP, "(%p): allocated\n", info);
+    return info;
+}
+
+static inline void get_devfs_lookup_struct (struct devfs_lookup_struct *info)
+{
+    atomic_inc (&info->count);
+}
+
+static inline void put_devfs_lookup_struct (struct devfs_lookup_struct *info)
+{
+    if (!atomic_dec_and_test (&info->count))
+	return;
+
+    DPRINTK (DEBUG_I_LOOKUP, "(%p): freed\n", info);
+    kfree (info);
+}
+
 /* 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, int flags)
@@ -2252,11 +2282,13 @@ 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);
     }
     else read_unlock (&parent->u.dir.lock);
     return 1;
@@ -2268,7 +2300,7 @@ static int devfs_d_revalidate_wait (stru
 static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry)
 {
     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;
@@ -2285,9 +2317,10 @@ 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.de = de;
-    init_waitqueue_head (&lookup_info.wait_queue);
-    dentry->d_fsdata = &lookup_info;
+    lookup_info = new_devfs_lookup_struct ();
+    if (lookup_info == NULL) return ERR_PTR (-ENOMEM);
+    lookup_info->de = de;
+    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
@@ -2297,6 +2330,7 @@ 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;
 	}
@@ -2308,8 +2342,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  */
-    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
 	early  */
     if (dentry->d_inode) goto out;
@@ -2333,11 +2366,13 @@ static struct dentry *devfs_lookup (stru
 	     de->name, de->inode.ino, inode, de, current->comm);
     d_instantiate (dentry, inode);
 out:
+    write_lock (&parent->u.dir.lock);
     dentry->d_op = &devfs_dops;
     dentry->d_fsdata = NULL;
-    write_lock (&parent->u.dir.lock);
-    wake_up (&lookup_info.wait_queue);
+    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  */

[-- Attachment #3: 2.5.74-devfs_lookup_deadlock.patch --]
[-- Type: text/x-diff, Size: 829 bytes --]

--- linux-2.5.74-smp/fs/devfs/base.c.orig	2003-07-07 20:58:36.000000000 +0400
+++ linux-2.5.74-smp/fs/devfs/base.c	2003-07-07 20:58:50.000000000 +0400
@@ -2308,7 +2308,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  */
@@ -2338,6 +2337,7 @@ out:
     write_lock (&parent->u.dir.lock);
     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);
     return retval;
 }   /*  End Function devfs_lookup  */

  parent reply	other threads:[~2003-07-07 18:52 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <E198K0q-000Am8-00.arvidjaar-mail-ru@f23.mail.ru>
     [not found] ` <Pine.LNX.4.55.0304231157560.1309@marabou.research.att.com>
     [not found]   ` <Pine.LNX.4.55.0305050005230.1278@marabou.research.att.com>
2003-07-06 17:06     ` [PATCH][2.5.73] stack corruption in devfs_lookup Andrey Borzenkov
2003-07-06 19:03       ` Andrew Morton
     [not found]         ` <20030706175405.518f680d.akpm@osdl.org>
2003-07-07 19:06           ` Andrey Borzenkov [this message]
2003-07-07 21:00             ` [PATCH][2.5.74] devfs lookup deadlock/stack corruption combined patch Andrew Morton
2003-07-08 17:49               ` Andrey Borzenkov
2003-07-09  1:20                 ` Herbert Poetzl
2003-07-09  1:26                   ` Andrew Morton
2003-07-09  2:09                     ` Herbert Poetzl
2003-07-09 10:34                       ` Thierry Vignaud
2003-07-07 21:41             ` Pavel Roskin
2003-07-26 14:58         ` [PATCH][2.6.0-test1] redesign - stack corruption in devfs_lookup Andrey Borzenkov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200307072306.15995.arvidjaar@mail.ru \
    --to=arvidjaar@mail.ru \
    --cc=akpm@osdl.org \
    --cc=devfs@oss.sgi.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).