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 */
next prev 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).