aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/kernfs')
-rw-r--r--fs/kernfs/dir.c129
1 files changed, 68 insertions, 61 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 2193d30156ef..3ac93737174a 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -106,18 +106,24 @@ static int kernfs_link_sibling(struct kernfs_node *kn)
106 * kernfs_unlink_sibling - unlink kernfs_node from sibling rbtree 106 * kernfs_unlink_sibling - unlink kernfs_node from sibling rbtree
107 * @kn: kernfs_node of interest 107 * @kn: kernfs_node of interest
108 * 108 *
109 * Unlink @kn from its sibling rbtree which starts from 109 * Try to unlink @kn from its sibling rbtree which starts from
110 * kn->parent->dir.children. 110 * kn->parent->dir.children. Returns %true if @kn was actually
111 * removed, %false if @kn wasn't on the rbtree.
111 * 112 *
112 * Locking: 113 * Locking:
113 * mutex_lock(kernfs_mutex) 114 * mutex_lock(kernfs_mutex)
114 */ 115 */
115static void kernfs_unlink_sibling(struct kernfs_node *kn) 116static bool kernfs_unlink_sibling(struct kernfs_node *kn)
116{ 117{
118 if (RB_EMPTY_NODE(&kn->rb))
119 return false;
120
117 if (kernfs_type(kn) == KERNFS_DIR) 121 if (kernfs_type(kn) == KERNFS_DIR)
118 kn->parent->dir.subdirs--; 122 kn->parent->dir.subdirs--;
119 123
120 rb_erase(&kn->rb, &kn->parent->dir.children); 124 rb_erase(&kn->rb, &kn->parent->dir.children);
125 RB_CLEAR_NODE(&kn->rb);
126 return true;
121} 127}
122 128
123/** 129/**
@@ -171,26 +177,34 @@ void kernfs_put_active(struct kernfs_node *kn)
171 * kernfs_deactivate - deactivate kernfs_node 177 * kernfs_deactivate - deactivate kernfs_node
172 * @kn: kernfs_node to deactivate 178 * @kn: kernfs_node to deactivate
173 * 179 *
174 * Deny new active references and drain existing ones. 180 * Deny new active references and drain existing ones. Mutiple
181 * removers may invoke this function concurrently on @kn and all will
182 * return after deactivation and draining are complete.
175 */ 183 */
176static void kernfs_deactivate(struct kernfs_node *kn) 184static void kernfs_deactivate(struct kernfs_node *kn)
185 __releases(&kernfs_mutex) __acquires(&kernfs_mutex)
177{ 186{
178 struct kernfs_root *root = kernfs_root(kn); 187 struct kernfs_root *root = kernfs_root(kn);
179 188
189 lockdep_assert_held(&kernfs_mutex);
180 BUG_ON(!(kn->flags & KERNFS_REMOVED)); 190 BUG_ON(!(kn->flags & KERNFS_REMOVED));
181 191
182 if (!(kernfs_type(kn) & KERNFS_ACTIVE_REF)) 192 if (!(kernfs_type(kn) & KERNFS_ACTIVE_REF))
183 return; 193 return;
184 194
185 if (kn->flags & KERNFS_LOCKDEP) 195 /* only the first invocation on @kn should deactivate it */
186 rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_); 196 if (atomic_read(&kn->active) >= 0)
197 atomic_add(KN_DEACTIVATED_BIAS, &kn->active);
187 198
188 atomic_add(KN_DEACTIVATED_BIAS, &kn->active); 199 mutex_unlock(&kernfs_mutex);
189 200
190 if ((kn->flags & KERNFS_LOCKDEP) && 201 if (kn->flags & KERNFS_LOCKDEP) {
191 atomic_read(&kn->active) != KN_DEACTIVATED_BIAS) 202 rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_);
192 lock_contended(&kn->dep_map, _RET_IP_); 203 if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS)
204 lock_contended(&kn->dep_map, _RET_IP_);
205 }
193 206
207 /* but everyone should wait for draining */
194 wait_event(root->deactivate_waitq, 208 wait_event(root->deactivate_waitq,
195 atomic_read(&kn->active) == KN_DEACTIVATED_BIAS); 209 atomic_read(&kn->active) == KN_DEACTIVATED_BIAS);
196 210
@@ -198,6 +212,8 @@ static void kernfs_deactivate(struct kernfs_node *kn)
198 lock_acquired(&kn->dep_map, _RET_IP_); 212 lock_acquired(&kn->dep_map, _RET_IP_);
199 rwsem_release(&kn->dep_map, 1, _RET_IP_); 213 rwsem_release(&kn->dep_map, 1, _RET_IP_);
200 } 214 }
215
216 mutex_lock(&kernfs_mutex);
201} 217}
202 218
203/** 219/**
@@ -347,6 +363,7 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
347 363
348 atomic_set(&kn->count, 1); 364 atomic_set(&kn->count, 1);
349 atomic_set(&kn->active, 0); 365 atomic_set(&kn->active, 0);
366 RB_CLEAR_NODE(&kn->rb);
350 367
351 kn->name = name; 368 kn->name = name;
352 kn->mode = mode; 369 kn->mode = mode;
@@ -454,49 +471,6 @@ int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn)
454} 471}
455 472
456/** 473/**
457 * kernfs_remove_one - remove kernfs_node from parent
458 * @acxt: addrm context to use
459 * @kn: kernfs_node to be removed
460 *
461 * Mark @kn removed and drop nlink of parent inode if @kn is a
462 * directory. @kn is unlinked from the children list.
463 *
464 * This function should be called between calls to
465 * kernfs_addrm_start() and kernfs_addrm_finish() and should be
466 * passed the same @acxt as passed to kernfs_addrm_start().
467 *
468 * LOCKING:
469 * Determined by kernfs_addrm_start().
470 */
471static void kernfs_remove_one(struct kernfs_addrm_cxt *acxt,
472 struct kernfs_node *kn)
473{
474 struct kernfs_iattrs *ps_iattr;
475
476 /*
477 * Removal can be called multiple times on the same node. Only the
478 * first invocation is effective and puts the base ref.
479 */
480 if (kn->flags & KERNFS_REMOVED)
481 return;
482
483 if (kn->parent) {
484 kernfs_unlink_sibling(kn);
485
486 /* Update timestamps on the parent */
487 ps_iattr = kn->parent->iattr;
488 if (ps_iattr) {
489 ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME;
490 ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME;
491 }
492 }
493
494 kn->flags |= KERNFS_REMOVED;
495 kn->u.removed_list = acxt->removed;
496 acxt->removed = kn;
497}
498
499/**
500 * kernfs_addrm_finish - finish up kernfs_node add/remove 474 * kernfs_addrm_finish - finish up kernfs_node add/remove
501 * @acxt: addrm context to finish up 475 * @acxt: addrm context to finish up
502 * 476 *
@@ -519,7 +493,6 @@ void kernfs_addrm_finish(struct kernfs_addrm_cxt *acxt)
519 493
520 acxt->removed = kn->u.removed_list; 494 acxt->removed = kn->u.removed_list;
521 495
522 kernfs_deactivate(kn);
523 kernfs_unmap_bin_file(kn); 496 kernfs_unmap_bin_file(kn);
524 kernfs_put(kn); 497 kernfs_put(kn);
525 } 498 }
@@ -828,20 +801,54 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos,
828static void __kernfs_remove(struct kernfs_addrm_cxt *acxt, 801static void __kernfs_remove(struct kernfs_addrm_cxt *acxt,
829 struct kernfs_node *kn) 802 struct kernfs_node *kn)
830{ 803{
831 struct kernfs_node *pos, *next; 804 struct kernfs_node *pos;
805
806 lockdep_assert_held(&kernfs_mutex);
832 807
833 if (!kn) 808 if (!kn)
834 return; 809 return;
835 810
836 pr_debug("kernfs %s: removing\n", kn->name); 811 pr_debug("kernfs %s: removing\n", kn->name);
837 812
838 next = NULL; 813 /* disable lookup and node creation under @kn */
814 pos = NULL;
815 while ((pos = kernfs_next_descendant_post(pos, kn)))
816 pos->flags |= KERNFS_REMOVED;
817
818 /* deactivate and unlink the subtree node-by-node */
839 do { 819 do {
840 pos = next; 820 pos = kernfs_leftmost_descendant(kn);
841 next = kernfs_next_descendant_post(pos, kn); 821
842 if (pos) 822 /*
843 kernfs_remove_one(acxt, pos); 823 * kernfs_deactivate() drops kernfs_mutex temporarily and
844 } while (next); 824 * @pos's base ref could have been put by someone else by
825 * the time the function returns. Make sure it doesn't go
826 * away underneath us.
827 */
828 kernfs_get(pos);
829
830 kernfs_deactivate(pos);
831
832 /*
833 * kernfs_unlink_sibling() succeeds once per node. Use it
834 * to decide who's responsible for cleanups.
835 */
836 if (!pos->parent || kernfs_unlink_sibling(pos)) {
837 struct kernfs_iattrs *ps_iattr =
838 pos->parent ? pos->parent->iattr : NULL;
839
840 /* update timestamps on the parent */
841 if (ps_iattr) {
842 ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME;
843 ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME;
844 }
845
846 pos->u.removed_list = acxt->removed;
847 acxt->removed = pos;
848 }
849
850 kernfs_put(pos);
851 } while (pos != kn);
845} 852}
846 853
847/** 854/**