[PATCH] d_delete-d_lookup race fix

From: Maneesh Soni
Date: Fri Sep 05 2003 - 06:37:10 EST


Hi Viro,

Thanks for pointing out the race. The patch is appended.

Andrew, please include this in next -mm, if Viro is ok with it.

Thanks
Maneesh


- d_delete() calls dentry_iput() after releasing the per dentry lock. This
can race with __d_lookup and lead to situation where we can make dentry
negative with ref count > 1. The following patch makes dentry_iput() to hold
per dentry lock till d_inode is NULL and dentry has been removed from
d_alias list.


fs/dcache.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)

diff -puN fs/dcache.c~d_delete-d_lookup-race-fix fs/dcache.c
--- linux-2.6.0-test4-mm6/fs/dcache.c~d_delete-d_lookup-race-fix 2003-09-05 16:16:56.000000000 +0530
+++ linux-2.6.0-test4-mm6-maneesh/fs/dcache.c 2003-09-05 16:50:49.000000000 +0530
@@ -82,7 +82,7 @@ static void d_free(struct dentry *dentry
/*
* Release the dentry's inode, using the filesystem
* d_iput() operation if defined.
- * Called with dcache_lock held, drops it.
+ * Called with dcache_lock and per dentry lock held, drops both.
*/
static inline void dentry_iput(struct dentry * dentry)
{
@@ -90,13 +90,16 @@ static inline void dentry_iput(struct de
if (inode) {
dentry->d_inode = NULL;
list_del_init(&dentry->d_alias);
+ spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
if (dentry->d_op && dentry->d_op->d_iput)
dentry->d_op->d_iput(dentry, inode);
else
iput(inode);
- } else
+ } else {
+ spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
+ }
}

/*
@@ -177,9 +180,8 @@ kill_it: {
dentry_stat.nr_unused--;
}
list_del(&dentry->d_child);
- spin_unlock(&dentry->d_lock);
dentry_stat.nr_dentry--; /* For d_free, below */
- /* drops the lock, at that point nobody can reach this dentry */
+ /*drops the locks, at that point nobody can reach this dentry */
dentry_iput(dentry);
parent = dentry->d_parent;
d_free(dentry);
@@ -341,7 +343,6 @@ static inline void prune_one_dentry(stru

__d_drop(dentry);
list_del(&dentry->d_child);
- spin_unlock(&dentry->d_lock);
dentry_stat.nr_dentry--; /* For d_free, below */
dentry_iput(dentry);
parent = dentry->d_parent;
@@ -1116,7 +1117,6 @@ void d_delete(struct dentry * dentry)
spin_lock(&dcache_lock);
spin_lock(&dentry->d_lock);
if (atomic_read(&dentry->d_count) == 1) {
- spin_unlock(&dentry->d_lock);
dentry_iput(dentry);
return;
}

_
--
Maneesh Soni
Linux Technology Center,
IBM Software Lab, Bangalore, India
email: maneesh@xxxxxxxxxx
Phone: 91-80-5044999 Fax: 91-80-5268553
T/L : 9243696
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/