aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 01:49:48 -0500
committerNick Piggin <npiggin@kernel.dk>2011-01-07 01:50:25 -0500
commit77812a1ef139d84270d27faacc0630c887411013 (patch)
treea051134c0d1c74425a5f60adc0ca252c5db15b35 /fs
parentec33679d78f9d653a44ddba10b5fb824c06330a1 (diff)
fs: consolidate dentry kill sequence
The tricky locking for disposing of a dentry is duplicated 3 times in the dcache (dput, pruning a dentry from the LRU, and pruning its ancestors). Consolidate them all into a single function dentry_kill. Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c135
1 files changed, 61 insertions, 74 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index d1840b30c673..dc0551c9755d 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -284,6 +284,40 @@ void d_drop(struct dentry *dentry)
284} 284}
285EXPORT_SYMBOL(d_drop); 285EXPORT_SYMBOL(d_drop);
286 286
287/*
288 * Finish off a dentry we've decided to kill.
289 * dentry->d_lock must be held, returns with it unlocked.
290 * If ref is non-zero, then decrement the refcount too.
291 * Returns dentry requiring refcount drop, or NULL if we're done.
292 */
293static inline struct dentry *dentry_kill(struct dentry *dentry, int ref)
294 __releases(dentry->d_lock)
295{
296 struct dentry *parent;
297
298 if (!spin_trylock(&dcache_inode_lock)) {
299relock:
300 spin_unlock(&dentry->d_lock);
301 cpu_relax();
302 return dentry; /* try again with same dentry */
303 }
304 if (IS_ROOT(dentry))
305 parent = NULL;
306 else
307 parent = dentry->d_parent;
308 if (parent && !spin_trylock(&parent->d_lock)) {
309 spin_unlock(&dcache_inode_lock);
310 goto relock;
311 }
312 if (ref)
313 dentry->d_count--;
314 /* if dentry was on the d_lru list delete it from there */
315 dentry_lru_del(dentry);
316 /* if it was on the hash then remove it */
317 __d_drop(dentry);
318 return d_kill(dentry, parent);
319}
320
287/* 321/*
288 * This is dput 322 * This is dput
289 * 323 *
@@ -309,13 +343,9 @@ EXPORT_SYMBOL(d_drop);
309 * call the dentry unlink method as well as removing it from the queues and 343 * call the dentry unlink method as well as removing it from the queues and
310 * releasing its resources. If the parent dentries were scheduled for release 344 * releasing its resources. If the parent dentries were scheduled for release
311 * they too may now get deleted. 345 * they too may now get deleted.
312 *
313 * no dcache lock, please.
314 */ 346 */
315
316void dput(struct dentry *dentry) 347void dput(struct dentry *dentry)
317{ 348{
318 struct dentry *parent;
319 if (!dentry) 349 if (!dentry)
320 return; 350 return;
321 351
@@ -348,26 +378,7 @@ repeat:
348 return; 378 return;
349 379
350kill_it: 380kill_it:
351 if (!spin_trylock(&dcache_inode_lock)) { 381 dentry = dentry_kill(dentry, 1);
352relock:
353 spin_unlock(&dentry->d_lock);
354 cpu_relax();
355 goto repeat;
356 }
357 if (IS_ROOT(dentry))
358 parent = NULL;
359 else
360 parent = dentry->d_parent;
361 if (parent && !spin_trylock(&parent->d_lock)) {
362 spin_unlock(&dcache_inode_lock);
363 goto relock;
364 }
365 dentry->d_count--;
366 /* if dentry was on the d_lru list delete it from there */
367 dentry_lru_del(dentry);
368 /* if it was on the hash (d_delete case), then remove it */
369 __d_drop(dentry);
370 dentry = d_kill(dentry, parent);
371 if (dentry) 382 if (dentry)
372 goto repeat; 383 goto repeat;
373} 384}
@@ -563,51 +574,43 @@ restart:
563EXPORT_SYMBOL(d_prune_aliases); 574EXPORT_SYMBOL(d_prune_aliases);
564 575
565/* 576/*
566 * Throw away a dentry - free the inode, dput the parent. This requires that 577 * Try to throw away a dentry - free the inode, dput the parent.
567 * the LRU list has already been removed. 578 * Requires dentry->d_lock is held, and dentry->d_count == 0.
579 * Releases dentry->d_lock.
568 * 580 *
569 * Try to prune ancestors as well. This is necessary to prevent 581 * This may fail if locks cannot be acquired no problem, just try again.
570 * quadratic behavior of shrink_dcache_parent(), but is also expected
571 * to be beneficial in reducing dentry cache fragmentation.
572 */ 582 */
573static void prune_one_dentry(struct dentry *dentry, struct dentry *parent) 583static void try_prune_one_dentry(struct dentry *dentry)
574 __releases(dentry->d_lock) 584 __releases(dentry->d_lock)
575 __releases(parent->d_lock)
576 __releases(dcache_inode_lock)
577{ 585{
578 __d_drop(dentry); 586 struct dentry *parent;
579 dentry = d_kill(dentry, parent);
580 587
588 parent = dentry_kill(dentry, 0);
581 /* 589 /*
582 * Prune ancestors. 590 * If dentry_kill returns NULL, we have nothing more to do.
591 * if it returns the same dentry, trylocks failed. In either
592 * case, just loop again.
593 *
594 * Otherwise, we need to prune ancestors too. This is necessary
595 * to prevent quadratic behavior of shrink_dcache_parent(), but
596 * is also expected to be beneficial in reducing dentry cache
597 * fragmentation.
583 */ 598 */
599 if (!parent)
600 return;
601 if (parent == dentry)
602 return;
603
604 /* Prune ancestors. */
605 dentry = parent;
584 while (dentry) { 606 while (dentry) {
585relock:
586 spin_lock(&dentry->d_lock); 607 spin_lock(&dentry->d_lock);
587 if (dentry->d_count > 1) { 608 if (dentry->d_count > 1) {
588 dentry->d_count--; 609 dentry->d_count--;
589 spin_unlock(&dentry->d_lock); 610 spin_unlock(&dentry->d_lock);
590 return; 611 return;
591 } 612 }
592 if (!spin_trylock(&dcache_inode_lock)) { 613 dentry = dentry_kill(dentry, 1);
593relock2:
594 spin_unlock(&dentry->d_lock);
595 cpu_relax();
596 goto relock;
597 }
598
599 if (IS_ROOT(dentry))
600 parent = NULL;
601 else
602 parent = dentry->d_parent;
603 if (parent && !spin_trylock(&parent->d_lock)) {
604 spin_unlock(&dcache_inode_lock);
605 goto relock2;
606 }
607 dentry->d_count--;
608 dentry_lru_del(dentry);
609 __d_drop(dentry);
610 dentry = d_kill(dentry, parent);
611 } 614 }
612} 615}
613 616
@@ -617,8 +620,6 @@ static void shrink_dentry_list(struct list_head *list)
617 620
618 rcu_read_lock(); 621 rcu_read_lock();
619 for (;;) { 622 for (;;) {
620 struct dentry *parent;
621
622 dentry = list_entry_rcu(list->prev, struct dentry, d_lru); 623 dentry = list_entry_rcu(list->prev, struct dentry, d_lru);
623 if (&dentry->d_lru == list) 624 if (&dentry->d_lru == list)
624 break; /* empty */ 625 break; /* empty */
@@ -639,24 +640,10 @@ static void shrink_dentry_list(struct list_head *list)
639 continue; 640 continue;
640 } 641 }
641 642
642 if (!spin_trylock(&dcache_inode_lock)) {
643relock:
644 spin_unlock(&dentry->d_lock);
645 cpu_relax();
646 continue;
647 }
648 if (IS_ROOT(dentry))
649 parent = NULL;
650 else
651 parent = dentry->d_parent;
652 if (parent && !spin_trylock(&parent->d_lock)) {
653 spin_unlock(&dcache_inode_lock);
654 goto relock;
655 }
656 dentry_lru_del(dentry);
657
658 rcu_read_unlock(); 643 rcu_read_unlock();
659 prune_one_dentry(dentry, parent); 644
645 try_prune_one_dentry(dentry);
646
660 rcu_read_lock(); 647 rcu_read_lock();
661 } 648 }
662 rcu_read_unlock(); 649 rcu_read_unlock();