From dd14cbc994709a1c5a64ed3621f583c49a27e521 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 11 Jun 2007 14:04:01 +0900 Subject: sysfs: fix race condition around sd->s_dentry, take#2 Allowing attribute and symlink dentries to be reclaimed means sd->s_dentry can change dynamically. However, updates to the field are unsynchronized leading to race conditions. This patch adds sysfs_lock and use it to synchronize updates to sd->s_dentry. Due to the locking around ->d_iput, the check in sysfs_drop_dentry() is complex. sysfs_lock only protect sd->s_dentry pointer itself. The validity of the dentry is protected by dcache_lock, so whether dentry is alive or not can only be tested while holding both locks. This is minimal backport of sysfs_drop_dentry() rewrite in devel branch. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/inode.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'fs/sysfs/inode.c') diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 38bbe071cc1..5266eec15f6 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -246,9 +246,23 @@ static inline void orphan_all_buffers(struct inode *node) */ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) { - struct dentry * dentry = sd->s_dentry; + struct dentry *dentry = NULL; struct inode *inode; + /* We're not holding a reference to ->s_dentry dentry but the + * field will stay valid as long as sysfs_lock is held. + */ + spin_lock(&sysfs_lock); + spin_lock(&dcache_lock); + + /* dget dentry if it's still alive */ + if (sd->s_dentry && sd->s_dentry->d_inode) + dentry = dget_locked(sd->s_dentry); + + spin_unlock(&dcache_lock); + spin_unlock(&sysfs_lock); + + /* drop dentry */ if (dentry) { spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); @@ -268,6 +282,8 @@ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); } + + dput(dentry); } } -- cgit v1.2.3