aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/kernfs/dir.c31
-rw-r--r--include/linux/kernfs.h4
2 files changed, 15 insertions, 20 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index bd6e18be6e1a..2193d30156ef 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -8,6 +8,7 @@
8 * This file is released under the GPLv2. 8 * This file is released under the GPLv2.
9 */ 9 */
10 10
11#include <linux/sched.h>
11#include <linux/fs.h> 12#include <linux/fs.h>
12#include <linux/namei.h> 13#include <linux/namei.h>
13#include <linux/idr.h> 14#include <linux/idr.h>
@@ -151,6 +152,7 @@ struct kernfs_node *kernfs_get_active(struct kernfs_node *kn)
151 */ 152 */
152void kernfs_put_active(struct kernfs_node *kn) 153void kernfs_put_active(struct kernfs_node *kn)
153{ 154{
155 struct kernfs_root *root = kernfs_root(kn);
154 int v; 156 int v;
155 157
156 if (unlikely(!kn)) 158 if (unlikely(!kn))
@@ -162,11 +164,7 @@ void kernfs_put_active(struct kernfs_node *kn)
162 if (likely(v != KN_DEACTIVATED_BIAS)) 164 if (likely(v != KN_DEACTIVATED_BIAS))
163 return; 165 return;
164 166
165 /* 167 wake_up_all(&root->deactivate_waitq);
166 * atomic_dec_return() is a mb(), we'll always see the updated
167 * kn->u.completion.
168 */
169 complete(kn->u.completion);
170} 168}
171 169
172/** 170/**
@@ -177,28 +175,24 @@ void kernfs_put_active(struct kernfs_node *kn)
177 */ 175 */
178static void kernfs_deactivate(struct kernfs_node *kn) 176static void kernfs_deactivate(struct kernfs_node *kn)
179{ 177{
180 DECLARE_COMPLETION_ONSTACK(wait); 178 struct kernfs_root *root = kernfs_root(kn);
181 int v;
182 179
183 BUG_ON(!(kn->flags & KERNFS_REMOVED)); 180 BUG_ON(!(kn->flags & KERNFS_REMOVED));
184 181
185 if (!(kernfs_type(kn) & KERNFS_ACTIVE_REF)) 182 if (!(kernfs_type(kn) & KERNFS_ACTIVE_REF))
186 return; 183 return;
187 184
188 kn->u.completion = (void *)&wait;
189
190 if (kn->flags & KERNFS_LOCKDEP) 185 if (kn->flags & KERNFS_LOCKDEP)
191 rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_); 186 rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_);
192 /* atomic_add_return() is a mb(), put_active() will always see
193 * the updated kn->u.completion.
194 */
195 v = atomic_add_return(KN_DEACTIVATED_BIAS, &kn->active);
196 187
197 if (v != KN_DEACTIVATED_BIAS) { 188 atomic_add(KN_DEACTIVATED_BIAS, &kn->active);
198 if (kn->flags & KERNFS_LOCKDEP) 189
199 lock_contended(&kn->dep_map, _RET_IP_); 190 if ((kn->flags & KERNFS_LOCKDEP) &&
200 wait_for_completion(&wait); 191 atomic_read(&kn->active) != KN_DEACTIVATED_BIAS)
201 } 192 lock_contended(&kn->dep_map, _RET_IP_);
193
194 wait_event(root->deactivate_waitq,
195 atomic_read(&kn->active) == KN_DEACTIVATED_BIAS);
202 196
203 if (kn->flags & KERNFS_LOCKDEP) { 197 if (kn->flags & KERNFS_LOCKDEP) {
204 lock_acquired(&kn->dep_map, _RET_IP_); 198 lock_acquired(&kn->dep_map, _RET_IP_);
@@ -630,6 +624,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv)
630 624
631 root->dir_ops = kdops; 625 root->dir_ops = kdops;
632 root->kn = kn; 626 root->kn = kn;
627 init_waitqueue_head(&root->deactivate_waitq);
633 628
634 return root; 629 return root;
635} 630}
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 5be9f0228a3b..295a3bf642ba 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -15,7 +15,7 @@
15#include <linux/lockdep.h> 15#include <linux/lockdep.h>
16#include <linux/rbtree.h> 16#include <linux/rbtree.h>
17#include <linux/atomic.h> 17#include <linux/atomic.h>
18#include <linux/completion.h> 18#include <linux/wait.h>
19 19
20struct file; 20struct file;
21struct dentry; 21struct dentry;
@@ -92,7 +92,6 @@ struct kernfs_node {
92 struct rb_node rb; 92 struct rb_node rb;
93 93
94 union { 94 union {
95 struct completion *completion;
96 struct kernfs_node *removed_list; 95 struct kernfs_node *removed_list;
97 } u; 96 } u;
98 97
@@ -133,6 +132,7 @@ struct kernfs_root {
133 /* private fields, do not use outside kernfs proper */ 132 /* private fields, do not use outside kernfs proper */
134 struct ida ino_ida; 133 struct ida ino_ida;
135 struct kernfs_dir_ops *dir_ops; 134 struct kernfs_dir_ops *dir_ops;
135 wait_queue_head_t deactivate_waitq;
136}; 136};
137 137
138struct kernfs_open_file { 138struct kernfs_open_file {