Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=13b3086d2ea483cbcae5a4236446cecc082a72cf
Commit:     13b3086d2ea483cbcae5a4236446cecc082a72cf
Parent:     a26cd7226c24c3be5dd5f48a74832fe64beb8489
Author:     Tejun Heo <[EMAIL PROTECTED]>
AuthorDate: Thu Jun 14 03:45:14 2007 +0900
Committer:  Greg Kroah-Hartman <[EMAIL PROTECTED]>
CommitDate: Wed Jul 11 16:09:04 2007 -0700

    sysfs: add sysfs_dirent->s_parent
    
    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 <[EMAIL PROTECTED]>
    Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
---
 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 f16aa7e..5d50e1d 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -47,6 +47,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);
@@ -56,6 +61,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)
@@ -119,8 +128,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);
+       }
 }
 
 /*
@@ -571,7 +582,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++;
@@ -688,13 +702,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;
@@ -706,6 +720,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 00ab912..31c1fc6 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 f8f49cc..ce05d6f 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;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to