aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/kernfs')
-rw-r--r--fs/kernfs/dir.c27
1 files changed, 11 insertions, 16 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 510b5062ef30..ed62de6cdf8f 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,26 +175,22 @@ 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 rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_); 185 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);
195 186
196 if (v != KN_DEACTIVATED_BIAS) { 187 atomic_add(KN_DEACTIVATED_BIAS, &kn->active);
188
189 if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS)
197 lock_contended(&kn->dep_map, _RET_IP_); 190 lock_contended(&kn->dep_map, _RET_IP_);
198 wait_for_completion(&wait); 191
199 } 192 wait_event(root->deactivate_waitq,
193 atomic_read(&kn->active) == KN_DEACTIVATED_BIAS);
200 194
201 lock_acquired(&kn->dep_map, _RET_IP_); 195 lock_acquired(&kn->dep_map, _RET_IP_);
202 rwsem_release(&kn->dep_map, 1, _RET_IP_); 196 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)
613 607
614 root->dir_ops = kdops; 608 root->dir_ops = kdops;
615 root->kn = kn; 609 root->kn = kn;
610 init_waitqueue_head(&root->deactivate_waitq);
616 611
617 return root; 612 return root;
618} 613}