Skip to content

Commit ea1c472

Browse files
htejungregkh
authored andcommitted
kernfs: replace kernfs_node->u.completion with kernfs_root->deactivate_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. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d92d2e6 commit ea1c472

File tree

2 files changed

+13
-18
lines changed

2 files changed

+13
-18
lines changed

fs/kernfs/dir.c

+11-16
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* This file is released under the GPLv2.
99
*/
1010

11+
#include <linux/sched.h>
1112
#include <linux/fs.h>
1213
#include <linux/namei.h>
1314
#include <linux/idr.h>
@@ -151,6 +152,7 @@ struct kernfs_node *kernfs_get_active(struct kernfs_node *kn)
151152
*/
152153
void kernfs_put_active(struct kernfs_node *kn)
153154
{
155+
struct kernfs_root *root = kernfs_root(kn);
154156
int v;
155157

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

165-
/*
166-
* atomic_dec_return() is a mb(), we'll always see the updated
167-
* kn->u.completion.
168-
*/
169-
complete(kn->u.completion);
167+
wake_up_all(&root->deactivate_waitq);
170168
}
171169

172170
/**
@@ -177,26 +175,22 @@ void kernfs_put_active(struct kernfs_node *kn)
177175
*/
178176
static void kernfs_deactivate(struct kernfs_node *kn)
179177
{
180-
DECLARE_COMPLETION_ONSTACK(wait);
181-
int v;
178+
struct kernfs_root *root = kernfs_root(kn);
182179

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

185182
if (!(kernfs_type(kn) & KERNFS_ACTIVE_REF))
186183
return;
187184

188-
kn->u.completion = (void *)&wait;
189-
190185
rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_);
191-
/* atomic_add_return() is a mb(), put_active() will always see
192-
* the updated kn->u.completion.
193-
*/
194-
v = atomic_add_return(KN_DEACTIVATED_BIAS, &kn->active);
195186

196-
if (v != KN_DEACTIVATED_BIAS) {
187+
atomic_add(KN_DEACTIVATED_BIAS, &kn->active);
188+
189+
if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS)
197190
lock_contended(&kn->dep_map, _RET_IP_);
198-
wait_for_completion(&wait);
199-
}
191+
192+
wait_event(root->deactivate_waitq,
193+
atomic_read(&kn->active) == KN_DEACTIVATED_BIAS);
200194

201195
lock_acquired(&kn->dep_map, _RET_IP_);
202196
rwsem_release(&kn->dep_map, 1, _RET_IP_);
@@ -613,6 +607,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv)
613607

614608
root->dir_ops = kdops;
615609
root->kn = kn;
610+
init_waitqueue_head(&root->deactivate_waitq);
616611

617612
return root;
618613
}

include/linux/kernfs.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include <linux/lockdep.h>
1616
#include <linux/rbtree.h>
1717
#include <linux/atomic.h>
18-
#include <linux/completion.h>
18+
#include <linux/wait.h>
1919

2020
struct file;
2121
struct iattr;
@@ -91,7 +91,6 @@ struct kernfs_node {
9191
struct rb_node rb;
9292

9393
union {
94-
struct completion *completion;
9594
struct kernfs_node *removed_list;
9695
} u;
9796

@@ -132,6 +131,7 @@ struct kernfs_root {
132131
/* private fields, do not use outside kernfs proper */
133132
struct ida ino_ida;
134133
struct kernfs_dir_ops *dir_ops;
134+
wait_queue_head_t deactivate_waitq;
135135
};
136136

137137
struct kernfs_open_file {

0 commit comments

Comments
 (0)