diff options
author | Tejun Heo <tj@kernel.org> | 2014-01-17 18:58:25 +0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-01-17 23:50:07 +0400 |
commit | db4aad209bc9aefd91f0a9aeb9e37364088b39ad (patch) | |
tree | 28cc941640469a11111808a6e77be61e892e5041 /fs/kernfs/symlink.c | |
parent | 917f56caaabc215f9658006dad28a9665ec0ce19 (diff) | |
download | linux-db4aad209bc9aefd91f0a9aeb9e37364088b39ad.tar.xz |
kernfs: associate a new kernfs_node with its parent on creation
Once created, a kernfs_node is always destroyed by kernfs_put().
Since ba7443bc656e ("sysfs, kernfs: implement
kernfs_create/destroy_root()"), kernfs_put() depends on kernfs_root()
to locate the ino_ida. kernfs_root() in turn depends on
kernfs_node->parent being set for !dir nodes. This means that
kernfs_put() of a !dir node requires its ->parent to be initialized.
This leads to oops when a newly created !dir node is destroyed without
going through kernfs_add_one() or after failing kernfs_add_one()
before ->parent is set. kernfs_root() invoked from kernfs_put() will
try to dereference NULL parent.
Fix it by moving parent association to kernfs_new_node() from
kernfs_add_one(). kernfs_new_node() now takes @parent instead of
@root and determines the root from the parent and also sets the new
node's parent properly. @parent parameter is removed from
kernfs_add_one(). As there's no parent when creating the root node,
__kernfs_new_node() which takes @root as before and doesn't set the
parent is used in that case.
This ensures that a kernfs_node in any stage in its life has its
parent associated and thus can be put.
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/kernfs/symlink.c')
-rw-r--r-- | fs/kernfs/symlink.c | 5 |
1 files changed, 2 insertions, 3 deletions
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index a03e26036ef9..4d457055acb9 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -30,8 +30,7 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, struct kernfs_addrm_cxt acxt; int error; - kn = kernfs_new_node(kernfs_root(parent), name, S_IFLNK|S_IRWXUGO, - KERNFS_LINK); + kn = kernfs_new_node(parent, name, S_IFLNK|S_IRWXUGO, KERNFS_LINK); if (!kn) return ERR_PTR(-ENOMEM); @@ -41,7 +40,7 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, kernfs_get(target); /* ref owned by symlink */ kernfs_addrm_start(&acxt); - error = kernfs_add_one(&acxt, kn, parent); + error = kernfs_add_one(&acxt, kn); kernfs_addrm_finish(&acxt); if (!error) |