]> Pileus Git - ~andy/linux/commitdiff
Revert "kernfs: remove KERNFS_REMOVED"
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 13 Jan 2014 22:36:03 +0000 (14:36 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 13 Jan 2014 22:36:03 +0000 (14:36 -0800)
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>
fs/kernfs/dir.c
fs/kernfs/file.c
fs/kernfs/kernfs-internal.h
fs/kernfs/symlink.c
include/linux/kernfs.h

index 7f8afc1d08f144d7e08f36ebf82fb3dce657f98b..1c9130a33048664a099398a6b751765535041496 100644 (file)
@@ -127,7 +127,6 @@ static void kernfs_unlink_sibling(struct kernfs_node *kn)
                kn->parent->dir.subdirs--;
 
        rb_erase(&kn->rb, &kn->parent->dir.children);
-       RB_CLEAR_NODE(&kn->rb);
 }
 
 /**
@@ -178,16 +177,18 @@ void kernfs_put_active(struct kernfs_node *kn)
 }
 
 /**
- * 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 @@ void kernfs_put(struct kernfs_node *kn)
                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 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
        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 @@ struct kernfs_node *kernfs_new_node(struct kernfs_root *root, const char *name,
        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 @@ int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn,
        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 @@ int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn,
        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 @@ int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn,
        }
 
        /* Mark the entry added into directory tree */
-       atomic_sub(KN_DEACTIVATED_BIAS, &kn->active);
+       kn->flags &= ~KERNFS_REMOVED;
+
        return 0;
 }
 
@@ -470,7 +470,7 @@ static void kernfs_remove_one(struct kernfs_addrm_cxt *acxt,
         * 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 @@ static void kernfs_remove_one(struct kernfs_addrm_cxt *acxt,
                }
        }
 
-       atomic_add(KN_DEACTIVATED_BIAS, &kn->active);
+       kn->flags |= KERNFS_REMOVED;
        kn->u.removed_list = acxt->removed;
        acxt->removed = kn;
 }
@@ -512,7 +512,7 @@ void kernfs_addrm_finish(struct kernfs_addrm_cxt *acxt)
 
                acxt->removed = kn->u.removed_list;
 
-               kernfs_drain(kn);
+               kernfs_deactivate(kn);
                kernfs_unmap_bin_file(kn);
                kernfs_put(kn);
        }
@@ -610,7 +610,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv)
                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 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
        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 kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
 {
        int error;
 
+       mutex_lock(&kernfs_mutex);
+
        error = -ENOENT;
-       if (!kernfs_get_active(new_parent))
+       if ((kn->flags | new_parent->flags) & KERNFS_REMOVED)
                goto out;
-       if (!kernfs_get_active(kn))
-               goto out_put_new_parent;
-
-       mutex_lock(&kernfs_mutex);
 
        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 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
        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 @@ static struct kernfs_node *kernfs_dir_pos(const void *ns,
        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;
index 231a171f48b6f107f729594a82165f4973e56073..bdd38854ef65bd5d3191b97dd43ddcb16a717c3a 100644 (file)
@@ -856,13 +856,9 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
        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);
index 57a93f4d645ca708fad37d0aafecd3bdefbe3889..c6ba5bc37a98ae864664761ef0bfa9c4273830c2 100644 (file)
@@ -26,8 +26,7 @@ struct kernfs_iattrs {
        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 */
 
index b2c106ca343435a508038659ce7a3aac09ddc1b8..a03e26036ef93c59f0880012481905fb184d32f5 100644 (file)
@@ -40,13 +40,9 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
        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;
index 289d4f639adeabce353ba83a665cc330c11e7088..42ad32ff22f8ef41361e90cd170051f6d2dd32c9 100644 (file)
@@ -37,6 +37,7 @@ enum kernfs_node_type {
 #define KERNFS_FLAG_MASK       ~KERNFS_TYPE_MASK
 
 enum kernfs_node_flag {
+       KERNFS_REMOVED          = 0x0010,
        KERNFS_NS               = 0x0020,
        KERNFS_HAS_SEQ_SHOW     = 0x0040,
        KERNFS_HAS_MMAP         = 0x0080,