aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-13 17:30:47 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-13 17:30:47 -0500
commit4f4b1b6471cf219d136776f9ff9631a07c4e92b5 (patch)
treee70651b3459b90062cf59797a57e5d90e88e4166 /fs/kernfs
parent55f6e30d0a6a8975cc0831e8a4a3715b815b6a2f (diff)
Revert "kernfs: restructure removal path to fix possible premature return"
This reverts commit 45a140e587f3d32d8d424ed940dffb61e1739047. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: 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.c139
1 files changed, 53 insertions, 86 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index e565ec096ae9..7f8afc1d08f1 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -181,38 +181,14 @@ void kernfs_put_active(struct kernfs_node *kn)
181 * kernfs_drain - drain kernfs_node 181 * kernfs_drain - drain kernfs_node
182 * @kn: kernfs_node to drain 182 * @kn: kernfs_node to drain
183 * 183 *
184 * Drain existing usages of @kn. Mutiple removers may invoke this function 184 * Drain existing usages.
185 * concurrently on @kn and all will return after draining is complete.
186 * Returns %true if drain is performed and kernfs_mutex was temporarily
187 * released. %false if @kn was already drained and no operation was
188 * necessary.
189 *
190 * The caller is responsible for ensuring @kn stays pinned while this
191 * function is in progress even if it gets removed by someone else.
192 */ 185 */
193static bool kernfs_drain(struct kernfs_node *kn) 186static void kernfs_drain(struct kernfs_node *kn)
194 __releases(&kernfs_mutex) __acquires(&kernfs_mutex)
195{ 187{
196 struct kernfs_root *root = kernfs_root(kn); 188 struct kernfs_root *root = kernfs_root(kn);
197 189
198 lockdep_assert_held(&kernfs_mutex);
199 WARN_ON_ONCE(atomic_read(&kn->active) >= 0); 190 WARN_ON_ONCE(atomic_read(&kn->active) >= 0);
200 191
201 /*
202 * We want to go through the active ref lockdep annotation at least
203 * once for all node removals, but the lockdep annotation can't be
204 * nested inside kernfs_mutex and deactivation can't make forward
205 * progress if we keep dropping the mutex. Use JUST_ACTIVATED to
206 * force the slow path once for each deactivation if lockdep is
207 * enabled.
208 */
209 if ((!kernfs_lockdep(kn) || !(kn->flags & KERNFS_JUST_DEACTIVATED)) &&
210 atomic_read(&kn->active) == KN_DEACTIVATED_BIAS)
211 return false;
212
213 kn->flags &= ~KERNFS_JUST_DEACTIVATED;
214 mutex_unlock(&kernfs_mutex);
215
216 if (kernfs_lockdep(kn)) { 192 if (kernfs_lockdep(kn)) {
217 rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_); 193 rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_);
218 if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS) 194 if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS)
@@ -226,9 +202,6 @@ static bool kernfs_drain(struct kernfs_node *kn)
226 lock_acquired(&kn->dep_map, _RET_IP_); 202 lock_acquired(&kn->dep_map, _RET_IP_);
227 rwsem_release(&kn->dep_map, 1, _RET_IP_); 203 rwsem_release(&kn->dep_map, 1, _RET_IP_);
228 } 204 }
229
230 mutex_lock(&kernfs_mutex);
231 return true;
232} 205}
233 206
234/** 207/**
@@ -474,6 +447,49 @@ int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn,
474} 447}
475 448
476/** 449/**
450 * kernfs_remove_one - remove kernfs_node from parent
451 * @acxt: addrm context to use
452 * @kn: kernfs_node to be removed
453 *
454 * Mark @kn removed and drop nlink of parent inode if @kn is a
455 * directory. @kn is unlinked from the children list.
456 *
457 * This function should be called between calls to
458 * kernfs_addrm_start() and kernfs_addrm_finish() and should be
459 * passed the same @acxt as passed to kernfs_addrm_start().
460 *
461 * LOCKING:
462 * Determined by kernfs_addrm_start().
463 */
464static void kernfs_remove_one(struct kernfs_addrm_cxt *acxt,
465 struct kernfs_node *kn)
466{
467 struct kernfs_iattrs *ps_iattr;
468
469 /*
470 * Removal can be called multiple times on the same node. Only the
471 * first invocation is effective and puts the base ref.
472 */
473 if (atomic_read(&kn->active) < 0)
474 return;
475
476 if (kn->parent) {
477 kernfs_unlink_sibling(kn);
478
479 /* Update timestamps on the parent */
480 ps_iattr = kn->parent->iattr;
481 if (ps_iattr) {
482 ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME;
483 ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME;
484 }
485 }
486
487 atomic_add(KN_DEACTIVATED_BIAS, &kn->active);
488 kn->u.removed_list = acxt->removed;
489 acxt->removed = kn;
490}
491
492/**
477 * kernfs_addrm_finish - finish up kernfs_node add/remove 493 * kernfs_addrm_finish - finish up kernfs_node add/remove
478 * @acxt: addrm context to finish up 494 * @acxt: addrm context to finish up
479 * 495 *
@@ -496,6 +512,7 @@ void kernfs_addrm_finish(struct kernfs_addrm_cxt *acxt)
496 512
497 acxt->removed = kn->u.removed_list; 513 acxt->removed = kn->u.removed_list;
498 514
515 kernfs_drain(kn);
499 kernfs_unmap_bin_file(kn); 516 kernfs_unmap_bin_file(kn);
500 kernfs_put(kn); 517 kernfs_put(kn);
501 } 518 }
@@ -805,73 +822,23 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos,
805 return pos->parent; 822 return pos->parent;
806} 823}
807 824
808static void __kernfs_deactivate(struct kernfs_node *kn)
809{
810 struct kernfs_node *pos;
811
812 lockdep_assert_held(&kernfs_mutex);
813
814 /* prevent any new usage under @kn by deactivating all nodes */
815 pos = NULL;
816 while ((pos = kernfs_next_descendant_post(pos, kn))) {
817 if (atomic_read(&pos->active) >= 0) {
818 atomic_add(KN_DEACTIVATED_BIAS, &pos->active);
819 pos->flags |= KERNFS_JUST_DEACTIVATED;
820 }
821 }
822
823 /*
824 * Drain the subtree. If kernfs_drain() blocked to drain, which is
825 * indicated by %true return, it temporarily released kernfs_mutex
826 * and the rbtree might have been modified inbetween breaking our
827 * future walk. Restart the walk after each %true return.
828 */
829 pos = NULL;
830 while ((pos = kernfs_next_descendant_post(pos, kn))) {
831 bool drained;
832
833 kernfs_get(pos);
834 drained = kernfs_drain(pos);
835 kernfs_put(pos);
836 if (drained)
837 pos = NULL;
838 }
839}
840
841static void __kernfs_remove(struct kernfs_addrm_cxt *acxt, 825static void __kernfs_remove(struct kernfs_addrm_cxt *acxt,
842 struct kernfs_node *kn) 826 struct kernfs_node *kn)
843{ 827{
844 struct kernfs_node *pos; 828 struct kernfs_node *pos, *next;
845
846 lockdep_assert_held(&kernfs_mutex);
847 829
848 if (!kn) 830 if (!kn)
849 return; 831 return;
850 832
851 pr_debug("kernfs %s: removing\n", kn->name); 833 pr_debug("kernfs %s: removing\n", kn->name);
852 834
853 __kernfs_deactivate(kn); 835 next = NULL;
854
855 /* unlink the subtree node-by-node */
856 do { 836 do {
857 struct kernfs_iattrs *ps_iattr; 837 pos = next;
858 838 next = kernfs_next_descendant_post(pos, kn);
859 pos = kernfs_leftmost_descendant(kn); 839 if (pos)
860 840 kernfs_remove_one(acxt, pos);
861 if (pos->parent) { 841 } while (next);
862 kernfs_unlink_sibling(pos);
863
864 /* update timestamps on the parent */
865 ps_iattr = pos->parent->iattr;
866 if (ps_iattr) {
867 ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME;
868 ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME;
869 }
870 }
871
872 pos->u.removed_list = acxt->removed;
873 acxt->removed = pos;
874 } while (pos != kn);
875} 842}
876 843
877/** 844/**