dentry: Fix race condition in d_invalidate d_invalidate checks for an unhashed entry early and then later relies on that information when removing the entry from the hashlist. However, we may drop the dcache_lock in order to deal with children (in case of a directory). At that point the entry may become unhashed. The later attempt to remove it again will then fail with a NULL pointer dereference. Recheck if the entry is still hashed after regaining the lock. Signed-off-by: Christoph Lameter --- fs/dcache.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) Index: linux-2.6/fs/dcache.c =================================================================== --- linux-2.6.orig/fs/dcache.c 2007-08-02 07:29:15.000000000 -0700 +++ linux-2.6/fs/dcache.c 2007-08-02 07:29:24.000000000 -0700 @@ -242,10 +242,8 @@ int d_invalidate(struct dentry * dentry) * If it's already been dropped, return OK. */ spin_lock(&dcache_lock); - if (d_unhashed(dentry)) { - spin_unlock(&dcache_lock); - return 0; - } + if (d_unhashed(dentry)) + goto unlock_out; /* * Check whether to do a partial shrink_dcache * to get rid of unused child entries. @@ -254,6 +252,10 @@ int d_invalidate(struct dentry * dentry) spin_unlock(&dcache_lock); shrink_dcache_parent(dentry); spin_lock(&dcache_lock); + + /* We dropped the lock. Recheck */ + if (d_unhashed(dentry)) + goto unlock_out; } /* @@ -277,6 +279,7 @@ int d_invalidate(struct dentry * dentry) __d_drop(dentry); spin_unlock(&dentry->d_lock); +unlock_out: spin_unlock(&dcache_lock); return 0; }