Revert "kernfs: remove KERNFS_REMOVED"

This reverts commit ae34372eb8408b3d07e870f1939f99007a730d28.

Tejun writes:
        I'm sorry but can you please revert the whole series?
        get_active() waiting while a node is deactivated has potential
        to lead to deadlock and that deactivate/reactivate interface is
        something fundamentally flawed and that cgroup will have to work
        with the remove_self() like everybody else.  IOW, I think the
        first posting was correct.

Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 7f8afc1..1c9130a3 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -127,7 +127,6 @@
 		kn->parent->dir.subdirs--;
 
 	rb_erase(&kn->rb, &kn->parent->dir.children);
-	RB_CLEAR_NODE(&kn->rb);
 }
 
 /**
@@ -178,16 +177,18 @@
 }
 
 /**
- * kernfs_drain - drain kernfs_node
- * @kn: kernfs_node to drain
+ *	kernfs_deactivate - deactivate kernfs_node
+ *	@kn: kernfs_node to deactivate
  *
- * Drain existing usages.
+ *	Deny new active references and drain existing ones.
  */
-static void kernfs_drain(struct kernfs_node *kn)
+static void kernfs_deactivate(struct kernfs_node *kn)
 {
 	struct kernfs_root *root = kernfs_root(kn);
 
-	WARN_ON_ONCE(atomic_read(&kn->active) >= 0);
+	BUG_ON(!(kn->flags & KERNFS_REMOVED));
+
+	atomic_add(KN_DEACTIVATED_BIAS, &kn->active);
 
 	if (kernfs_lockdep(kn)) {
 		rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_);
@@ -232,15 +233,13 @@
 		return;
 	root = kernfs_root(kn);
  repeat:
-	/*
-	 * Moving/renaming is always done while holding reference.
+	/* Moving/renaming is always done while holding reference.
 	 * kn->parent won't change beneath us.
 	 */
 	parent = kn->parent;
 
-	WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS,
-		  "kernfs_put: %s/%s: released with incorrect active_ref %d\n",
-		  parent ? parent->name : "", kn->name, atomic_read(&kn->active));
+	WARN(!(kn->flags & KERNFS_REMOVED), "kernfs: free using entry: %s/%s\n",
+	     parent ? parent->name : "", kn->name);
 
 	if (kernfs_type(kn) == KERNFS_LINK)
 		kernfs_put(kn->symlink.target_kn);
@@ -282,8 +281,8 @@
 	kn = dentry->d_fsdata;
 	mutex_lock(&kernfs_mutex);
 
-	/* Force fresh lookup if removed */
-	if (kn->parent && RB_EMPTY_NODE(&kn->rb))
+	/* The kernfs node has been deleted */
+	if (kn->flags & KERNFS_REMOVED)
 		goto out_bad;
 
 	/* The kernfs node has been moved? */
@@ -351,12 +350,11 @@
 	kn->ino = ret;
 
 	atomic_set(&kn->count, 1);
-	atomic_set(&kn->active, KN_DEACTIVATED_BIAS);
-	RB_CLEAR_NODE(&kn->rb);
+	atomic_set(&kn->active, 0);
 
 	kn->name = name;
 	kn->mode = mode;
-	kn->flags = flags;
+	kn->flags = flags | KERNFS_REMOVED;
 
 	return kn;
 
@@ -415,8 +413,6 @@
 	struct kernfs_iattrs *ps_iattr;
 	int ret;
 
-	WARN_ON_ONCE(atomic_read(&parent->active) < 0);
-
 	if (has_ns != (bool)kn->ns) {
 		WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n",
 		     has_ns ? "required" : "invalid", parent->name, kn->name);
@@ -426,6 +422,9 @@
 	if (kernfs_type(parent) != KERNFS_DIR)
 		return -EINVAL;
 
+	if (parent->flags & KERNFS_REMOVED)
+		return -ENOENT;
+
 	kn->hash = kernfs_name_hash(kn->name, kn->ns);
 	kn->parent = parent;
 	kernfs_get(parent);
@@ -442,7 +441,8 @@
 	}
 
 	/* Mark the entry added into directory tree */
-	atomic_sub(KN_DEACTIVATED_BIAS, &kn->active);
+	kn->flags &= ~KERNFS_REMOVED;
+
 	return 0;
 }
 
@@ -470,7 +470,7 @@
 	 * Removal can be called multiple times on the same node.  Only the
 	 * first invocation is effective and puts the base ref.
 	 */
-	if (atomic_read(&kn->active) < 0)
+	if (kn->flags & KERNFS_REMOVED)
 		return;
 
 	if (kn->parent) {
@@ -484,7 +484,7 @@
 		}
 	}
 
-	atomic_add(KN_DEACTIVATED_BIAS, &kn->active);
+	kn->flags |= KERNFS_REMOVED;
 	kn->u.removed_list = acxt->removed;
 	acxt->removed = kn;
 }
@@ -512,7 +512,7 @@
 
 		acxt->removed = kn->u.removed_list;
 
-		kernfs_drain(kn);
+		kernfs_deactivate(kn);
 		kernfs_unmap_bin_file(kn);
 		kernfs_put(kn);
 	}
@@ -610,7 +610,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
-	atomic_sub(KN_DEACTIVATED_BIAS, &kn->active);
+	kn->flags &= ~KERNFS_REMOVED;
 	kn->priv = priv;
 	kn->dir.root = root;
 
@@ -662,13 +662,9 @@
 	kn->priv = priv;
 
 	/* link in */
-	rc = -ENOENT;
-	if (kernfs_get_active(parent)) {
-		kernfs_addrm_start(&acxt);
-		rc = kernfs_add_one(&acxt, kn, parent);
-		kernfs_addrm_finish(&acxt);
-		kernfs_put_active(parent);
-	}
+	kernfs_addrm_start(&acxt);
+	rc = kernfs_add_one(&acxt, kn, parent);
+	kernfs_addrm_finish(&acxt);
 
 	if (!rc)
 		return kn;
@@ -903,29 +899,27 @@
 {
 	int error;
 
-	error = -ENOENT;
-	if (!kernfs_get_active(new_parent))
-		goto out;
-	if (!kernfs_get_active(kn))
-		goto out_put_new_parent;
-
 	mutex_lock(&kernfs_mutex);
 
+	error = -ENOENT;
+	if ((kn->flags | new_parent->flags) & KERNFS_REMOVED)
+		goto out;
+
 	error = 0;
 	if ((kn->parent == new_parent) && (kn->ns == new_ns) &&
 	    (strcmp(kn->name, new_name) == 0))
-		goto out_unlock;	/* nothing to rename */
+		goto out;	/* nothing to rename */
 
 	error = -EEXIST;
 	if (kernfs_find_ns(new_parent, new_name, new_ns))
-		goto out_unlock;
+		goto out;
 
 	/* rename kernfs_node */
 	if (strcmp(kn->name, new_name) != 0) {
 		error = -ENOMEM;
 		new_name = kstrdup(new_name, GFP_KERNEL);
 		if (!new_name)
-			goto out_unlock;
+			goto out;
 
 		if (kn->flags & KERNFS_STATIC_NAME)
 			kn->flags &= ~KERNFS_STATIC_NAME;
@@ -947,12 +941,8 @@
 	kernfs_link_sibling(kn);
 
 	error = 0;
-out_unlock:
+ out:
 	mutex_unlock(&kernfs_mutex);
-	kernfs_put_active(kn);
-out_put_new_parent:
-	kernfs_put_active(new_parent);
-out:
 	return error;
 }
 
@@ -972,7 +962,8 @@
 	struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos)
 {
 	if (pos) {
-		int valid = pos->parent == parent && hash == pos->hash;
+		int valid = !(pos->flags & KERNFS_REMOVED) &&
+			pos->parent == parent && hash == pos->hash;
 		kernfs_put(pos);
 		if (!valid)
 			pos = NULL;
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 231a171..bdd3885 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -856,13 +856,9 @@
 	if (ops->mmap)
 		kn->flags |= KERNFS_HAS_MMAP;
 
-	rc = -ENOENT;
-	if (kernfs_get_active(parent)) {
-		kernfs_addrm_start(&acxt);
-		rc = kernfs_add_one(&acxt, kn, parent);
-		kernfs_addrm_finish(&acxt);
-		kernfs_put_active(parent);
-	}
+	kernfs_addrm_start(&acxt);
+	rc = kernfs_add_one(&acxt, kn, parent);
+	kernfs_addrm_finish(&acxt);
 
 	if (rc) {
 		kernfs_put(kn);
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index 57a93f4..c6ba5bc 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -26,8 +26,7 @@
 	struct simple_xattrs	xattrs;
 };
 
-/* +1 to avoid triggering overflow warning when negating it */
-#define KN_DEACTIVATED_BIAS		(INT_MIN + 1)
+#define KN_DEACTIVATED_BIAS		INT_MIN
 
 /* KERNFS_TYPE_MASK and types are defined in include/linux/kernfs.h */
 
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index b2c106c..a03e260 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -40,13 +40,9 @@
 	kn->symlink.target_kn = target;
 	kernfs_get(target);	/* ref owned by symlink */
 
-	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);
-	}
+	kernfs_addrm_start(&acxt);
+	error = kernfs_add_one(&acxt, kn, parent);
+	kernfs_addrm_finish(&acxt);
 
 	if (!error)
 		return kn;