aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2014-01-10 08:57:25 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-10 16:48:08 -0500
commit895a068a524e134900b9d98b519309b7aae7bbb1 (patch)
tree3989057a5801f0d72dd2640f70479f7593504f7f /fs/kernfs
parent99177a34110889a8f2c36420c34e3bcc9bfd8a70 (diff)
kernfs: make kernfs_get_active() block if the node is deactivated but not removed
Currently, kernfs_get_active() fails if the target node is deactivated. This is fine as a node always gets removed after deactivation; however, we're gonna add reactivation so the assumption won't hold. It'd be incorrect for kernfs_get_active() to fail for a node which was deactivated only temporarily. This patch makes kernfs_get_active() block if the node is deactivated but not removed. If the node gets reactivated (not yet implemented), it will be retried and succeed. If the node gets removed, it will be woken up and fail. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/kernfs')
-rw-r--r--fs/kernfs/dir.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 770d687ee9f3..37dd6408f5f6 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -149,12 +149,25 @@ struct kernfs_node *kernfs_get_active(struct kernfs_node *kn)
149 if (unlikely(!kn)) 149 if (unlikely(!kn))
150 return NULL; 150 return NULL;
151 151
152 if (!atomic_inc_unless_negative(&kn->active))
153 return NULL;
154
155 if (kernfs_lockdep(kn)) 152 if (kernfs_lockdep(kn))
156 rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_); 153 rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_);
157 return kn; 154
155 /*
156 * Try to obtain an active ref. If @kn is deactivated, we block
157 * till either it's reactivated or killed.
158 */
159 do {
160 if (atomic_inc_unless_negative(&kn->active))
161 return kn;
162
163 wait_event(kernfs_root(kn)->deactivate_waitq,
164 atomic_read(&kn->active) >= 0 ||
165 RB_EMPTY_NODE(&kn->rb));
166 } while (!RB_EMPTY_NODE(&kn->rb));
167
168 if (kernfs_lockdep(kn))
169 rwsem_release(&kn->dep_map, 1, _RET_IP_);
170 return NULL;
158} 171}
159 172
160/** 173/**
@@ -786,6 +799,7 @@ static void __kernfs_deactivate(struct kernfs_node *kn)
786 799
787static void __kernfs_remove(struct kernfs_node *kn) 800static void __kernfs_remove(struct kernfs_node *kn)
788{ 801{
802 struct kernfs_root *root = kernfs_root(kn);
789 struct kernfs_node *pos; 803 struct kernfs_node *pos;
790 804
791 lockdep_assert_held(&kernfs_mutex); 805 lockdep_assert_held(&kernfs_mutex);
@@ -837,6 +851,9 @@ static void __kernfs_remove(struct kernfs_node *kn)
837 851
838 kernfs_put(pos); 852 kernfs_put(pos);
839 } while (pos != kn); 853 } while (pos != kn);
854
855 /* some nodes killed, kick get_active waiters */
856 wake_up_all(&root->deactivate_waitq);
840} 857}
841 858
842/** 859/**