lkml.org 
[lkml]   [2007]   [Apr]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH 11/21] sysfs: add sysfs_dirent->s_parent
    Date
    From
    Add sysfs_dirent->s_parent.  With this patch, each sd points to and
    holds a reference to its parent. This allows walking sysfs tree
    without referencing sd->s_dentry which can go away anytime if the user
    doesn't control when it's deleted.

    sd->s_parent is initialized and parent is referenced in
    sysfs_attach_dirent(). Reference to parent is released when the sd is
    released, so as long as reference to a sd is held, s_parent can be
    followed.

    dentry walk in sysfs_readdir() is convereted to s_parent walk.

    This will be used to reimplement symlink such that it uses only
    sysfs_dirent tree.

    Signed-off-by: Tejun Heo <htejun@gmail.com>
    ---
    fs/sysfs/dir.c | 30 +++++++++++++++++++++++-------
    fs/sysfs/mount.c | 1 +
    fs/sysfs/sysfs.h | 1 +
    3 files changed, 25 insertions(+), 7 deletions(-)

    diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
    index a339e47..609a2f5 100644
    --- a/fs/sysfs/dir.c
    +++ b/fs/sysfs/dir.c
    @@ -46,6 +46,11 @@ static void sysfs_free_ino(ino_t ino)

    void release_sysfs_dirent(struct sysfs_dirent * sd)
    {
    + struct sysfs_dirent *parent_sd;
    +
    + repeat:
    + parent_sd = sd->s_parent;
    +
    if (sd->s_type & SYSFS_KOBJ_LINK) {
    struct sysfs_symlink * sl = sd->s_element;
    kfree(sl->link_name);
    @@ -55,6 +60,10 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)
    kfree(sd->s_iattr);
    sysfs_free_ino(sd->s_ino);
    kmem_cache_free(sysfs_dir_cachep, sd);
    +
    + sd = parent_sd;
    + if (sd && atomic_dec_and_test(&sd->s_count))
    + goto repeat;
    }

    static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
    @@ -107,8 +116,10 @@ void sysfs_attach_dirent(struct sysfs_dirent *sd,
    dentry->d_op = &sysfs_dentry_ops;
    }

    - if (parent_sd)
    + if (parent_sd) {
    + sd->s_parent = sysfs_get(parent_sd);
    list_add(&sd->s_sibling, &parent_sd->s_children);
    + }
    }

    /*
    @@ -553,7 +564,10 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
    i++;
    /* fallthrough */
    case 1:
    - ino = parent_ino(dentry);
    + if (parent_sd->s_parent)
    + ino = parent_sd->s_parent->s_ino;
    + else
    + ino = parent_sd->s_ino;
    if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
    break;
    filp->f_pos++;
    @@ -670,13 +684,13 @@ int sysfs_make_shadowed_dir(struct kobject *kobj,

    struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)
    {
    + struct dentry *dir = kobj->dentry;
    + struct inode *inode = dir->d_inode;
    + struct dentry *parent = dir->d_parent;
    + struct sysfs_dirent *parent_sd = parent->d_fsdata;
    + struct dentry *shadow;
    struct sysfs_dirent *sd;
    - struct dentry *parent, *dir, *shadow;
    - struct inode *inode;

    - dir = kobj->dentry;
    - inode = dir->d_inode;
    - parent = dir->d_parent;
    shadow = ERR_PTR(-EINVAL);
    if (!sysfs_is_shadowed_inode(inode))
    goto out;
    @@ -688,6 +702,8 @@ struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)
    sd = sysfs_new_dirent(kobj, inode->i_mode, SYSFS_DIR);
    if (!sd)
    goto nomem;
    + /* point to parent_sd but don't attach to it */
    + sd->s_parent = sysfs_get(parent_sd);
    sysfs_attach_dirent(sd, NULL, shadow);

    d_instantiate(shadow, igrab(inode));
    diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
    index c1bafef..bc613f6 100644
    --- a/fs/sysfs/mount.c
    +++ b/fs/sysfs/mount.c
    @@ -28,6 +28,7 @@ static const struct super_operations sysfs_ops = {
    };

    static struct sysfs_dirent sysfs_root = {
    + .s_count = ATOMIC_INIT(1),
    .s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling),
    .s_children = LIST_HEAD_INIT(sysfs_root.s_children),
    .s_element = NULL,
    diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
    index c490156..0051ae2 100644
    --- a/fs/sysfs/sysfs.h
    +++ b/fs/sysfs/sysfs.h
    @@ -1,5 +1,6 @@
    struct sysfs_dirent {
    atomic_t s_count;
    + struct sysfs_dirent * s_parent;
    struct list_head s_sibling;
    struct list_head s_children;
    void * s_element;
    --
    1.5.0.3

    -
    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: 2007-04-28 15:47    [W:0.028 / U:58.932 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site