aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/dir.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-08-20 08:36:30 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 17:51:08 -0400
commit89bec09705d2033b8b765f3c3ac5093f80bd5bc4 (patch)
tree3f0583740c18258ab793e86ae11e3a24c4acf8eb /fs/sysfs/dir.c
parent3efa65b92d832873ece62b42a4268c2515943977 (diff)
sysfs: Rewrite sysfs_drop_dentry.
Currently we find the dentry to drop by looking at sd->s_dentry. We can just as easily accomplish the same task by looking up the sysfs inode and finding all of the dentries from there, with the added bonus that we don't need to play with the sysfs_assoc_lock. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Tejun Heo <htejun@gmail.com> Cc: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r--fs/sysfs/dir.c53
1 files changed, 26 insertions, 27 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 953e8432b0ae..1af963e66e3c 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -565,50 +565,49 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
565 * Drop dentry for @sd. @sd must have been unlinked from its 565 * Drop dentry for @sd. @sd must have been unlinked from its
566 * parent on entry to this function such that it can't be looked 566 * parent on entry to this function such that it can't be looked
567 * up anymore. 567 * up anymore.
568 *
569 * @sd->s_dentry which is protected with sysfs_assoc_lock points
570 * to the currently associated dentry but we're not holding a
571 * reference to it and racing with dput(). Grab dcache_lock and
572 * verify dentry before dropping it. If @sd->s_dentry is NULL or
573 * dput() beats us, no need to bother.
574 */ 568 */
575static void sysfs_drop_dentry(struct sysfs_dirent *sd) 569static void sysfs_drop_dentry(struct sysfs_dirent *sd)
576{ 570{
577 struct dentry *dentry = NULL;
578 struct inode *inode; 571 struct inode *inode;
572 struct dentry *dentry;
573
574 inode = ilookup(sysfs_sb, sd->s_ino);
575 if (!inode)
576 return;
579 577
580 /* We're not holding a reference to ->s_dentry dentry but the 578 /* Drop any existing dentries associated with sd.
581 * field will stay valid as long as sysfs_assoc_lock is held. 579 *
580 * For the dentry to be properly freed we need to grab a
581 * reference to the dentry under the dcache lock, unhash it,
582 * and then put it. The playing with the dentry count allows
583 * dput to immediately free the dentry if it is not in use.
582 */ 584 */
583 spin_lock(&sysfs_assoc_lock); 585repeat:
584 spin_lock(&dcache_lock); 586 spin_lock(&dcache_lock);
585 587 list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
586 /* drop dentry if it's there and dput() didn't kill it yet */ 588 if (d_unhashed(dentry))
587 if (sd->s_dentry && sd->s_dentry->d_inode) { 589 continue;
588 dentry = dget_locked(sd->s_dentry); 590 dget_locked(dentry);
589 spin_lock(&dentry->d_lock); 591 spin_lock(&dentry->d_lock);
590 __d_drop(dentry); 592 __d_drop(dentry);
591 spin_unlock(&dentry->d_lock); 593 spin_unlock(&dentry->d_lock);
594 spin_unlock(&dcache_lock);
595 dput(dentry);
596 goto repeat;
592 } 597 }
593
594 spin_unlock(&dcache_lock); 598 spin_unlock(&dcache_lock);
595 spin_unlock(&sysfs_assoc_lock);
596
597 dput(dentry);
598 599
599 /* adjust nlink and update timestamp */ 600 /* adjust nlink and update timestamp */
600 inode = ilookup(sysfs_sb, sd->s_ino); 601 mutex_lock(&inode->i_mutex);
601 if (inode) {
602 mutex_lock(&inode->i_mutex);
603 602
604 inode->i_ctime = CURRENT_TIME; 603 inode->i_ctime = CURRENT_TIME;
604 drop_nlink(inode);
605 if (sysfs_type(sd) == SYSFS_DIR)
605 drop_nlink(inode); 606 drop_nlink(inode);
606 if (sysfs_type(sd) == SYSFS_DIR)
607 drop_nlink(inode);
608 607
609 mutex_unlock(&inode->i_mutex); 608 mutex_unlock(&inode->i_mutex);
610 iput(inode); 609
611 } 610 iput(inode);
612} 611}
613 612
614/** 613/**