aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/inode.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-06-11 01:04:01 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-06-12 19:08:47 -0400
commitdd14cbc994709a1c5a64ed3621f583c49a27e521 (patch)
treee48d38b7450661907c7b75490504c7f70b04d6cc /fs/sysfs/inode.c
parent6aa054aadfea613a437ad0b15d38eca2b963fc0a (diff)
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 <htejun@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/sysfs/inode.c')
-rw-r--r--fs/sysfs/inode.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 38bbe071cc15..5266eec15f6e 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -246,9 +246,23 @@ static inline void orphan_all_buffers(struct inode *node)
246 */ 246 */
247void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) 247void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
248{ 248{
249 struct dentry * dentry = sd->s_dentry; 249 struct dentry *dentry = NULL;
250 struct inode *inode; 250 struct inode *inode;
251 251
252 /* We're not holding a reference to ->s_dentry dentry but the
253 * field will stay valid as long as sysfs_lock is held.
254 */
255 spin_lock(&sysfs_lock);
256 spin_lock(&dcache_lock);
257
258 /* dget dentry if it's still alive */
259 if (sd->s_dentry && sd->s_dentry->d_inode)
260 dentry = dget_locked(sd->s_dentry);
261
262 spin_unlock(&dcache_lock);
263 spin_unlock(&sysfs_lock);
264
265 /* drop dentry */
252 if (dentry) { 266 if (dentry) {
253 spin_lock(&dcache_lock); 267 spin_lock(&dcache_lock);
254 spin_lock(&dentry->d_lock); 268 spin_lock(&dentry->d_lock);
@@ -268,6 +282,8 @@ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
268 spin_unlock(&dentry->d_lock); 282 spin_unlock(&dentry->d_lock);
269 spin_unlock(&dcache_lock); 283 spin_unlock(&dcache_lock);
270 } 284 }
285
286 dput(dentry);
271 } 287 }
272} 288}
273 289