Skip to content

Commit

Permalink
kernfs: replace kernfs_node->u.completion with kernfs_root->deactivat…
Browse files Browse the repository at this point in the history
…e_waitq

kernfs_node->u.completion is used to notify deactivation completion
from kernfs_put_active() to kernfs_deactivate().  We now allow
multiple racing removals of the same node and the current removal
scheme is no longer correct - kernfs_remove() invocation may return
before the node is properly deactivated if it races against another
removal.  The removal path will be restructured to address the issue.

To help such restructure which requires supporting multiple waiters,
this patch replaces kernfs_node->u.completion with
kernfs_root->deactivate_waitq.  This makes deactivation event
notifications share a per-root waitqueue_head; however, the wait path
is quite cold and this will also allow shaving one pointer off
kernfs_node.

v2: Refreshed on top of ("kernfs: make kernfs_deactivate() honor
    KERNFS_LOCKDEP flag").

Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Tejun Heo authored and Greg Kroah-Hartman committed Feb 7, 2014
1 parent a660793 commit abd54f0
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 20 deletions.
31 changes: 13 additions & 18 deletions fs/kernfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* This file is released under the GPLv2.
*/

#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/idr.h>
Expand Down Expand Up @@ -151,6 +152,7 @@ struct kernfs_node *kernfs_get_active(struct kernfs_node *kn)
*/
void kernfs_put_active(struct kernfs_node *kn)
{
struct kernfs_root *root = kernfs_root(kn);
int v;

if (unlikely(!kn))
Expand All @@ -162,11 +164,7 @@ void kernfs_put_active(struct kernfs_node *kn)
if (likely(v != KN_DEACTIVATED_BIAS))
return;

/*
* atomic_dec_return() is a mb(), we'll always see the updated
* kn->u.completion.
*/
complete(kn->u.completion);
wake_up_all(&root->deactivate_waitq);
}

/**
Expand All @@ -177,28 +175,24 @@ void kernfs_put_active(struct kernfs_node *kn)
*/
static void kernfs_deactivate(struct kernfs_node *kn)
{
DECLARE_COMPLETION_ONSTACK(wait);
int v;
struct kernfs_root *root = kernfs_root(kn);

BUG_ON(!(kn->flags & KERNFS_REMOVED));

if (!(kernfs_type(kn) & KERNFS_ACTIVE_REF))
return;

kn->u.completion = (void *)&wait;

if (kn->flags & KERNFS_LOCKDEP)
rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_);
/* atomic_add_return() is a mb(), put_active() will always see
* the updated kn->u.completion.
*/
v = atomic_add_return(KN_DEACTIVATED_BIAS, &kn->active);

if (v != KN_DEACTIVATED_BIAS) {
if (kn->flags & KERNFS_LOCKDEP)
lock_contended(&kn->dep_map, _RET_IP_);
wait_for_completion(&wait);
}
atomic_add(KN_DEACTIVATED_BIAS, &kn->active);

if ((kn->flags & KERNFS_LOCKDEP) &&
atomic_read(&kn->active) != KN_DEACTIVATED_BIAS)
lock_contended(&kn->dep_map, _RET_IP_);

wait_event(root->deactivate_waitq,
atomic_read(&kn->active) == KN_DEACTIVATED_BIAS);

if (kn->flags & KERNFS_LOCKDEP) {
lock_acquired(&kn->dep_map, _RET_IP_);
Expand Down Expand Up @@ -630,6 +624,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv)

root->dir_ops = kdops;
root->kn = kn;
init_waitqueue_head(&root->deactivate_waitq);

return root;
}
Expand Down
4 changes: 2 additions & 2 deletions include/linux/kernfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <linux/lockdep.h>
#include <linux/rbtree.h>
#include <linux/atomic.h>
#include <linux/completion.h>
#include <linux/wait.h>

struct file;
struct dentry;
Expand Down Expand Up @@ -92,7 +92,6 @@ struct kernfs_node {
struct rb_node rb;

union {
struct completion *completion;
struct kernfs_node *removed_list;
} u;

Expand Down Expand Up @@ -133,6 +132,7 @@ struct kernfs_root {
/* private fields, do not use outside kernfs proper */
struct ida ino_ida;
struct kernfs_dir_ops *dir_ops;
wait_queue_head_t deactivate_waitq;
};

struct kernfs_open_file {
Expand Down

0 comments on commit abd54f0

Please sign in to comment.