diff options
| author | Patrick Mochel <mochel@osdl.org> | 2003-01-09 23:37:04 -0600 |
|---|---|---|
| committer | Patrick Mochel <mochel@osdl.org> | 2003-01-09 23:37:04 -0600 |
| commit | b2aa16e83d30e24f5e7faea1aa532e3f6ebdec18 (patch) | |
| tree | b4b14663dfa1d1f97ec27c66f64fd38efe644fe9 | |
| parent | 00880cfff75b3b1fa44d8586d73fe2663644b0ba (diff) | |
sysfs: make sure we drop all the references on dentrys we acquire.
None of the file deletions were dropping the referencees to dentrys that
were acquired via the internal helper get_dentry(). This adds the missing
dput()s (and comments) to fix that.
Also, this adds a dget() on the directory and each file that's being removed
in sysfs_remove_dir(), (and associated dput()s) to guarantee the references
stay valid over the duration.
Originally reported by Mika Penttilä.
| -rw-r--r-- | fs/sysfs/inode.c | 51 |
1 files changed, 47 insertions, 4 deletions
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 3bbc05bfcb96..8ecf901ee6e1 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -704,7 +704,19 @@ static void hash_and_remove(struct dentry * dir, const char * name) (victim->d_parent->d_inode == dir->d_inode)) { simple_unlink(dir->d_inode,victim); d_delete(victim); + + pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name, + atomic_read(&victim->d_count)); + /** + * Drop reference from initial get_dentry(). + */ + dput(victim); } + + /** + * Drop the reference acquired from get_dentry() above. + */ + dput(victim); } up(&dir->d_inode->i_sem); } @@ -748,29 +760,60 @@ void sysfs_remove_link(struct kobject * kobj, char * name) void sysfs_remove_dir(struct kobject * kobj) { struct list_head * node, * next; - struct dentry * dentry = kobj->dentry; + struct dentry * dentry = dget(kobj->dentry); struct dentry * parent; if (!dentry) return; + pr_debug("sysfs %s: removing dir\n",dentry->d_name.name); parent = dget(dentry->d_parent); down(&parent->d_inode->i_sem); down(&dentry->d_inode->i_sem); list_for_each_safe(node,next,&dentry->d_subdirs) { - struct dentry * d = list_entry(node,struct dentry,d_child); - /* make sure dentry is still there */ + struct dentry * d = dget(list_entry(node,struct dentry,d_child)); + /** + * Make sure dentry is still there + */ + pr_debug(" o %s: ",d->d_name.name); if (d->d_inode) { + + pr_debug("removing"); + /** + * Unlink and unhash. + */ simple_unlink(dentry->d_inode,d); - d_delete(dentry); + d_delete(d); + + /** + * Drop reference from initial get_dentry(). + */ + dput(d); } + pr_debug(" done (%d)\n",atomic_read(&d->d_count)); + /** + * drop reference from dget() above. + */ + dput(d); } up(&dentry->d_inode->i_sem); d_invalidate(dentry); simple_rmdir(parent->d_inode,dentry); d_delete(dentry); + + pr_debug(" o %s removing done (%d)\n",dentry->d_name.name, + atomic_read(&dentry->d_count)); + /** + * Drop reference from initial get_dentry(). + */ + dput(dentry); + + /** + * Drop reference from dget() on entrance. + */ + dput(dentry); up(&parent->d_inode->i_sem); dput(parent); } |
