lkml.org 
[lkml]   [2004]   [Jul]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 3/5] Free sysfs_dirent on file removal


    o The following patch implements the code to free up the sysfs_dirents upon
    directory or file removal. It uses the sysfs_dirent based tree in order
    to remove the directory contents before removing the directory itself.
    It could do this without taking dcache_lock in sysfs_remove_dir() as
    it doesnot use dentry based tree.


    fs/sysfs/dir.c | 48 ++++++++++++++----------------------------------
    fs/sysfs/inode.c | 51 ++++++++++++++++++++++++++++++---------------------
    2 files changed, 44 insertions(+), 55 deletions(-)

    diff -puN fs/sysfs/inode.c~sysfs-backing-store-kill-sysfs_dirent fs/sysfs/inode.c
    --- linux-2.6.8-rc2-mm1/fs/sysfs/inode.c~sysfs-backing-store-kill-sysfs_dirent 2004-07-29 15:30:39.000000000 -0500
    +++ linux-2.6.8-rc2-mm1-maneesh/fs/sysfs/inode.c 2004-07-29 15:31:07.000000000 -0500
    @@ -11,6 +11,8 @@
    #include <linux/pagemap.h>
    #include <linux/namei.h>
    #include <linux/backing-dev.h>
    +#include "sysfs.h"
    +
    extern struct super_block * sysfs_sb;

    static struct address_space_operations sysfs_aops = {
    @@ -88,33 +90,40 @@ struct dentry * sysfs_get_dentry(struct
    return lookup_hash(&qstr,parent);
    }

    +/* Unhashes the dentry corresponding to given sysfs_dirent
    + * Called with parent inode's i_sem held.
    + */
    +void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
    +{
    + struct dentry * dentry = sd->s_dentry;
    +
    + if (dentry) {
    + if (!(d_unhashed(dentry) && dentry->d_inode)) {
    + spin_lock(&dcache_lock);
    + dget_locked(dentry);
    + __d_drop(dentry);
    + spin_unlock(&dcache_lock);
    + simple_unlink(parent->d_inode, dentry);
    + } else
    + dput(dentry);
    + }
    +}
    +
    void sysfs_hash_and_remove(struct dentry * dir, const char * name)
    {
    - struct dentry * victim;
    + struct sysfs_dirent * sd, * parent_sd = dir->d_fsdata;

    down(&dir->d_inode->i_sem);
    - victim = sysfs_get_dentry(dir,name);
    - if (!IS_ERR(victim)) {
    - /* make sure dentry is really there */
    - if (victim->d_inode &&
    - (victim->d_parent->d_inode == dir->d_inode)) {
    - pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name,
    - atomic_read(&victim->d_count));
    -
    - d_drop(victim);
    - /* release the target kobject in case of
    - * a symlink
    - */
    - if (S_ISLNK(victim->d_inode->i_mode))
    - kobject_put(victim->d_fsdata);
    - simple_unlink(dir->d_inode,victim);
    + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
    + if (!sd->s_element)
    + continue;
    + if (!strcmp(sysfs_get_name(sd), name)) {
    + list_del_init(&sd->s_sibling);
    + sysfs_drop_dentry(sd, dir);
    + sysfs_put(sd);
    + break;
    }
    - /*
    - * Drop reference from sysfs_get_dentry() above.
    - */
    - dput(victim);
    }
    up(&dir->d_inode->i_sem);
    }

    -
    diff -puN fs/sysfs/dir.c~sysfs-backing-store-kill-sysfs_dirent fs/sysfs/dir.c
    --- linux-2.6.8-rc2-mm1/fs/sysfs/dir.c~sysfs-backing-store-kill-sysfs_dirent 2004-07-29 15:30:39.000000000 -0500
    +++ linux-2.6.8-rc2-mm1-maneesh/fs/sysfs/dir.c 2004-07-29 15:31:07.000000000 -0500
    @@ -100,8 +100,13 @@ int sysfs_create_dir(struct kobject * ko
    static void remove_dir(struct dentry * d)
    {
    struct dentry * parent = dget(d->d_parent);
    + struct sysfs_dirent * sd;
    +
    down(&parent->d_inode->i_sem);
    d_delete(d);
    + sd = d->d_fsdata;
    + list_del_init(&sd->s_sibling);
    + sysfs_put(d->d_fsdata);
    if (d->d_inode)
    simple_rmdir(parent->d_inode,d);

    @@ -129,47 +134,22 @@ void sysfs_remove_subdir(struct dentry *

    void sysfs_remove_dir(struct kobject * kobj)
    {
    - struct list_head * node;
    struct dentry * dentry = dget(kobj->dentry);
    + struct sysfs_dirent * parent_sd = dentry->d_fsdata;
    + struct sysfs_dirent * sd, * tmp;

    if (!dentry)
    return;

    pr_debug("sysfs %s: removing dir\n",dentry->d_name.name);
    down(&dentry->d_inode->i_sem);
    -
    - spin_lock(&dcache_lock);
    -restart:
    - node = dentry->d_subdirs.next;
    - while (node != &dentry->d_subdirs) {
    - struct dentry * d = list_entry(node,struct dentry,d_child);
    -
    - node = node->next;
    - pr_debug(" o %s (%d): ",d->d_name.name,atomic_read(&d->d_count));
    - if (!d_unhashed(d) && (d->d_inode)) {
    - d = dget_locked(d);
    - pr_debug("removing");
    -
    - /**
    - * Unlink and unhash.
    - */
    - __d_drop(d);
    - spin_unlock(&dcache_lock);
    - /* release the target kobject in case of
    - * a symlink
    - */
    - if (S_ISLNK(d->d_inode->i_mode))
    - kobject_put(d->d_fsdata);
    -
    - simple_unlink(dentry->d_inode,d);
    - dput(d);
    - pr_debug(" done\n");
    - spin_lock(&dcache_lock);
    - /* re-acquired dcache_lock, need to restart */
    - goto restart;
    - }
    - }
    - spin_unlock(&dcache_lock);
    + list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
    + if (!sd->s_element)
    + continue;
    + list_del_init(&sd->s_sibling);
    + sysfs_drop_dentry(sd, dentry);
    + sysfs_put(sd);
    + }
    up(&dentry->d_inode->i_sem);

    remove_dir(dentry);
    _
    --
    Maneesh Soni
    Linux Technology Center,
    IBM Austin
    email: maneesh@in.ibm.com
    Phone: 1-512-838-1896 Fax:
    T/L : 6781896
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 14:04    [W:0.027 / U:1.004 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site