aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs/symlink.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2014-01-10 08:57:21 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-10 13:44:25 -0800
commitae34372eb8408b3d07e870f1939f99007a730d28 (patch)
tree5c291bca19df41c3085f8fbf96047f81d9ab545b /fs/kernfs/symlink.c
parentkernfs: remove KERNFS_ACTIVE_REF and add kernfs_lockdep() (diff)
downloadlinux-dev-ae34372eb8408b3d07e870f1939f99007a730d28.tar.xz
linux-dev-ae34372eb8408b3d07e870f1939f99007a730d28.zip
kernfs: remove KERNFS_REMOVED
KERNFS_REMOVED is used to mark half-initialized and dying nodes so that they don't show up in lookups and deny adding new nodes under or renaming it; however, its role overlaps those of deactivation and removal from rbtree. It's necessary to deny addition of new children while removal is in progress; however, this role considerably intersects with deactivation - KERNFS_REMOVED prevents new children while deactivation prevents new file operations. There's no reason to have them separate making things more complex than necessary. KERNFS_REMOVED is also used to decide whether a node is still visible to vfs layer, which is rather redundant as equivalent determination can be made by testing whether the node is on its parent's children rbtree or not. This patch removes KERNFS_REMOVED. * Instead of KERNFS_REMOVED, each node now starts its life deactivated. This means that we now use both atomic_add() and atomic_sub() on KN_DEACTIVATED_BIAS, which is INT_MIN. The compiler generates an overflow warnings when negating INT_MIN as the negation can't be represented as a positive number. Nothing is actually broken but let's bump BIAS by one to avoid the warnings for archs which negates the subtrahend.. * KERNFS_REMOVED tests in add and rename paths are replaced with kernfs_get/put_active() of the target nodes. Due to the way the add path is structured now, active ref handling is done in the callers of kernfs_add_one(). This will be consolidated up later. * kernfs_remove_one() is updated to deactivate instead of setting KERNFS_REMOVED. This removes deactivation from kernfs_deactivate(), which is now renamed to kernfs_drain(). * kernfs_dop_revalidate() now tests RB_EMPTY_NODE(&kn->rb) instead of KERNFS_REMOVED and KERNFS_REMOVED test in kernfs_dir_pos() is dropped. A node which is removed from the children rbtree is not included in the iteration in the first place. This means that a node may be visible through vfs a bit longer - it's now also visible after deactivation until the actual removal. This slightly enlarged window difference doesn't make any difference to the userland. * Sanity check on KERNFS_REMOVED in kernfs_put() is replaced with checks on the active ref. * Some comment style updates in the affected area. v2: Reordered before removal path restructuring. kernfs_active() dropped and kernfs_get/put_active() used instead. RB_EMPTY_NODE() used in the lookup paths. 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.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index a03e26036ef9..b2c106ca3434 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -40,9 +40,13 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
kn->symlink.target_kn = target;
kernfs_get(target); /* ref owned by symlink */
- kernfs_addrm_start(&acxt);
- error = kernfs_add_one(&acxt, kn, parent);
- kernfs_addrm_finish(&acxt);
+ error = -ENOENT;
+ if (kernfs_get_active(parent)) {
+ kernfs_addrm_start(&acxt);
+ error = kernfs_add_one(&acxt, kn, parent);
+ kernfs_addrm_finish(&acxt);
+ kernfs_put_active(parent);
+ }
if (!error)
return kn;