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>
kn->parent->dir.subdirs--;
rb_erase(&kn->rb, &kn->parent->dir.children);
kn->parent->dir.subdirs--;
rb_erase(&kn->rb, &kn->parent->dir.children);
- RB_CLEAR_NODE(&kn->rb);
- * 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);
{
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_);
if (kernfs_lockdep(kn)) {
rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_);
return;
root = kernfs_root(kn);
repeat:
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;
* 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);
if (kernfs_type(kn) == KERNFS_LINK)
kernfs_put(kn->symlink.target_kn);
kn = dentry->d_fsdata;
mutex_lock(&kernfs_mutex);
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? */
goto out_bad;
/* The kernfs node has been moved? */
kn->ino = ret;
atomic_set(&kn->count, 1);
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->name = name;
kn->mode = mode;
+ kn->flags = flags | KERNFS_REMOVED;
struct kernfs_iattrs *ps_iattr;
int ret;
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);
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);
if (kernfs_type(parent) != KERNFS_DIR)
return -EINVAL;
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);
kn->hash = kernfs_name_hash(kn->name, kn->ns);
kn->parent = parent;
kernfs_get(parent);
}
/* Mark the entry added into directory tree */
}
/* Mark the entry added into directory tree */
- atomic_sub(KN_DEACTIVATED_BIAS, &kn->active);
+ kn->flags &= ~KERNFS_REMOVED;
+
* Removal can be called multiple times on the same node. Only the
* first invocation is effective and puts the base ref.
*/
* 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) {
return;
if (kn->parent) {
- atomic_add(KN_DEACTIVATED_BIAS, &kn->active);
+ kn->flags |= KERNFS_REMOVED;
kn->u.removed_list = acxt->removed;
acxt->removed = kn;
}
kn->u.removed_list = acxt->removed;
acxt->removed = kn;
}
acxt->removed = kn->u.removed_list;
acxt->removed = kn->u.removed_list;
kernfs_unmap_bin_file(kn);
kernfs_put(kn);
}
kernfs_unmap_bin_file(kn);
kernfs_put(kn);
}
return ERR_PTR(-ENOMEM);
}
return ERR_PTR(-ENOMEM);
}
- atomic_sub(KN_DEACTIVATED_BIAS, &kn->active);
+ kn->flags &= ~KERNFS_REMOVED;
kn->priv = priv;
kn->dir.root = root;
kn->priv = priv;
kn->dir.root = root;
kn->priv = priv;
/* link in */
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);
+ mutex_lock(&kernfs_mutex);
+
- if (!kernfs_get_active(new_parent))
+ if ((kn->flags | new_parent->flags) & KERNFS_REMOVED)
- 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))
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))
error = -EEXIST;
if (kernfs_find_ns(new_parent, new_name, new_ns))
/* rename kernfs_node */
if (strcmp(kn->name, new_name) != 0) {
error = -ENOMEM;
new_name = kstrdup(new_name, GFP_KERNEL);
if (!new_name)
/* rename kernfs_node */
if (strcmp(kn->name, new_name) != 0) {
error = -ENOMEM;
new_name = kstrdup(new_name, GFP_KERNEL);
if (!new_name)
if (kn->flags & KERNFS_STATIC_NAME)
kn->flags &= ~KERNFS_STATIC_NAME;
if (kn->flags & KERNFS_STATIC_NAME)
kn->flags &= ~KERNFS_STATIC_NAME;
kernfs_link_sibling(kn);
error = 0;
kernfs_link_sibling(kn);
error = 0;
mutex_unlock(&kernfs_mutex);
mutex_unlock(&kernfs_mutex);
- kernfs_put_active(kn);
-out_put_new_parent:
- kernfs_put_active(new_parent);
-out:
struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos)
{
if (pos) {
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;
kernfs_put(pos);
if (!valid)
pos = NULL;
if (ops->mmap)
kn->flags |= KERNFS_HAS_MMAP;
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);
if (rc) {
kernfs_put(kn);
struct simple_xattrs xattrs;
};
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 */
/* KERNFS_TYPE_MASK and types are defined in include/linux/kernfs.h */
kn->symlink.target_kn = target;
kernfs_get(target); /* ref owned by symlink */
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);
#define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK
enum kernfs_node_flag {
#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,
KERNFS_NS = 0x0020,
KERNFS_HAS_SEQ_SHOW = 0x0040,
KERNFS_HAS_MMAP = 0x0080,