diff options
author | Tejun Heo <htejun@gmail.com> | 2007-06-13 21:27:21 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-12 01:09:08 +0200 |
commit | d0bcb5689a521df98bff7549fcb8b17499660a99 (patch) | |
tree | 6f9deb74f4facc5e638b71ba8b99ac2baeed9859 /fs/sysfs/inode.c | |
parent | sysfs: Fix oops in sysfs_drop_dentry on x86_64 (diff) | |
download | linux-d0bcb5689a521df98bff7549fcb8b17499660a99.tar.xz linux-d0bcb5689a521df98bff7549fcb8b17499660a99.zip |
sysfs: make sysfs_drop_dentry() access inodes using ilookup()
sysfs_drop_dentry() used to go through sd->s_dentry and
sd->s_parent->s_dentry to access the inodes. This is incorrect
because inode can be cached without dentry.
This patch makes sysfs_drop_dentry() access inodes using ilookup() on
sd->s_ino. This is both correct and simpler.
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.c | 63 |
1 files changed, 28 insertions, 35 deletions
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index ee31bf369a88..63daa06c4194 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -219,9 +219,9 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode) */ void sysfs_drop_dentry(struct sysfs_dirent *sd) { - struct dentry *dentry = NULL, *parent = NULL; - struct inode *dir; + struct dentry *dentry = NULL; struct timespec curtime; + 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. @@ -229,19 +229,9 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd) spin_lock(&sysfs_lock); spin_lock(&dcache_lock); + /* drop dentry if it's there and dput() didn't kill it yet */ if (sd->s_dentry && sd->s_dentry->d_inode) { - /* get dentry if it's there and dput() didn't kill it yet */ dentry = dget_locked(sd->s_dentry); - parent = dentry->d_parent; - } else if (sd->s_parent->s_dentry->d_inode) { - /* We need to update the parent even if dentry for the - * victim itself doesn't exist. - */ - parent = dget_locked(sd->s_parent->s_dentry); - } - - /* drop */ - if (dentry) { spin_lock(&dentry->d_lock); __d_drop(dentry); spin_unlock(&dentry->d_lock); @@ -250,36 +240,39 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd) spin_unlock(&dcache_lock); spin_unlock(&sysfs_lock); - /* nothing to do if the parent isn't in dcache */ - if (!parent) - return; + dput(dentry); + /* XXX: unpin if directory, this will go away soon */ + if (sd->s_type & SYSFS_DIR) + dput(dentry); /* adjust nlink and update timestamp */ - dir = parent->d_inode; - mutex_lock(&dir->i_mutex); - curtime = CURRENT_TIME; - dir->i_ctime = dir->i_mtime = curtime; + inode = ilookup(sysfs_sb, sd->s_ino); + if (inode) { + mutex_lock(&inode->i_mutex); - if (dentry) { - dentry->d_inode->i_ctime = curtime; - drop_nlink(dentry->d_inode); - if (sd->s_type & SYSFS_DIR) { - drop_nlink(dentry->d_inode); - drop_nlink(dir); - /* XXX: unpin if directory, this will go away soon */ - dput(dentry); - } + inode->i_ctime = curtime; + drop_nlink(inode); + if (sd->s_type & SYSFS_DIR) + drop_nlink(inode); + + mutex_unlock(&inode->i_mutex); + iput(inode); } - mutex_unlock(&dir->i_mutex); + /* adjust nlink and udpate timestamp of the parent */ + inode = ilookup(sysfs_sb, sd->s_parent->s_ino); + if (inode) { + mutex_lock(&inode->i_mutex); - /* bye bye */ - if (dentry) - dput(dentry); - else - dput(parent); + inode->i_ctime = inode->i_mtime = curtime; + if (sd->s_type & SYSFS_DIR) + drop_nlink(inode); + + mutex_unlock(&inode->i_mutex); + iput(inode); + } } int sysfs_hash_and_remove(struct dentry * dir, const char * name) |