aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2010-10-10 05:36:25 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-10-25 21:26:13 -0400
commit3049cfe24ef3872ba74f90630356722cf988b80d (patch)
tree18c7574640a8f95106facd56cb03a74b73d60f42 /fs
parent265ac90230257e9c035e4b0c63a0c11c5336e93c (diff)
fs: split __shrink_dcache_sb
Currently __shrink_dcache_sb has an extremly awkward calling convention because it tries to please very different callers. Split out the main loop into a shrink_dentry_list helper, which gets called directly from shrink_dcache_sb for the cases where all dentries need to be pruned, or from __shrink_dcache_sb for pruning only a certain number of dentries. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c127
1 files changed, 67 insertions, 60 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 1a976d4efbe1..e987ad576a39 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -459,66 +459,20 @@ static void prune_one_dentry(struct dentry * dentry)
459 } 459 }
460} 460}
461 461
462/* 462static void shrink_dentry_list(struct list_head *list)
463 * Shrink the dentry LRU on a given superblock.
464 * @sb : superblock to shrink dentry LRU.
465 * @count: If count is NULL, we prune all dentries on superblock.
466 * @flags: If flags is non-zero, we need to do special processing based on
467 * which flags are set. This means we don't need to maintain multiple
468 * similar copies of this loop.
469 */
470static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags)
471{ 463{
472 LIST_HEAD(referenced);
473 LIST_HEAD(tmp);
474 struct dentry *dentry; 464 struct dentry *dentry;
475 int cnt = 0;
476 465
477 BUG_ON(!sb); 466 while (!list_empty(list)) {
478 BUG_ON((flags & DCACHE_REFERENCED) && count == NULL); 467 dentry = list_entry(list->prev, struct dentry, d_lru);
479 spin_lock(&dcache_lock);
480 if (count != NULL)
481 /* called from prune_dcache() and shrink_dcache_parent() */
482 cnt = *count;
483restart:
484 if (count == NULL)
485 list_splice_init(&sb->s_dentry_lru, &tmp);
486 else {
487 while (!list_empty(&sb->s_dentry_lru)) {
488 dentry = list_entry(sb->s_dentry_lru.prev,
489 struct dentry, d_lru);
490 BUG_ON(dentry->d_sb != sb);
491
492 spin_lock(&dentry->d_lock);
493 /*
494 * If we are honouring the DCACHE_REFERENCED flag and
495 * the dentry has this flag set, don't free it. Clear
496 * the flag and put it back on the LRU.
497 */
498 if ((flags & DCACHE_REFERENCED)
499 && (dentry->d_flags & DCACHE_REFERENCED)) {
500 dentry->d_flags &= ~DCACHE_REFERENCED;
501 list_move(&dentry->d_lru, &referenced);
502 spin_unlock(&dentry->d_lock);
503 } else {
504 list_move_tail(&dentry->d_lru, &tmp);
505 spin_unlock(&dentry->d_lock);
506 cnt--;
507 if (!cnt)
508 break;
509 }
510 cond_resched_lock(&dcache_lock);
511 }
512 }
513 while (!list_empty(&tmp)) {
514 dentry = list_entry(tmp.prev, struct dentry, d_lru);
515 dentry_lru_del_init(dentry); 468 dentry_lru_del_init(dentry);
516 spin_lock(&dentry->d_lock); 469
517 /* 470 /*
518 * We found an inuse dentry which was not removed from 471 * We found an inuse dentry which was not removed from
519 * the LRU because of laziness during lookup. Do not free 472 * the LRU because of laziness during lookup. Do not free
520 * it - just keep it off the LRU list. 473 * it - just keep it off the LRU list.
521 */ 474 */
475 spin_lock(&dentry->d_lock);
522 if (atomic_read(&dentry->d_count)) { 476 if (atomic_read(&dentry->d_count)) {
523 spin_unlock(&dentry->d_lock); 477 spin_unlock(&dentry->d_lock);
524 continue; 478 continue;
@@ -527,13 +481,60 @@ restart:
527 /* dentry->d_lock was dropped in prune_one_dentry() */ 481 /* dentry->d_lock was dropped in prune_one_dentry() */
528 cond_resched_lock(&dcache_lock); 482 cond_resched_lock(&dcache_lock);
529 } 483 }
530 if (count == NULL && !list_empty(&sb->s_dentry_lru)) 484}
531 goto restart; 485
532 if (count != NULL) 486/**
533 *count = cnt; 487 * __shrink_dcache_sb - shrink the dentry LRU on a given superblock
488 * @sb: superblock to shrink dentry LRU.
489 * @count: number of entries to prune
490 * @flags: flags to control the dentry processing
491 *
492 * If flags contains DCACHE_REFERENCED reference dentries will not be pruned.
493 */
494static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags)
495{
496 /* called from prune_dcache() and shrink_dcache_parent() */
497 struct dentry *dentry;
498 LIST_HEAD(referenced);
499 LIST_HEAD(tmp);
500 int cnt = *count;
501
502 spin_lock(&dcache_lock);
503 while (!list_empty(&sb->s_dentry_lru)) {
504 dentry = list_entry(sb->s_dentry_lru.prev,
505 struct dentry, d_lru);
506 BUG_ON(dentry->d_sb != sb);
507
508 /*
509 * If we are honouring the DCACHE_REFERENCED flag and the
510 * dentry has this flag set, don't free it. Clear the flag
511 * and put it back on the LRU.
512 */
513 if (flags & DCACHE_REFERENCED) {
514 spin_lock(&dentry->d_lock);
515 if (dentry->d_flags & DCACHE_REFERENCED) {
516 dentry->d_flags &= ~DCACHE_REFERENCED;
517 list_move(&dentry->d_lru, &referenced);
518 spin_unlock(&dentry->d_lock);
519 cond_resched_lock(&dcache_lock);
520 continue;
521 }
522 spin_unlock(&dentry->d_lock);
523 }
524
525 list_move_tail(&dentry->d_lru, &tmp);
526 if (!--cnt)
527 break;
528 cond_resched_lock(&dcache_lock);
529 }
530
531 *count = cnt;
532 shrink_dentry_list(&tmp);
533
534 if (!list_empty(&referenced)) 534 if (!list_empty(&referenced))
535 list_splice(&referenced, &sb->s_dentry_lru); 535 list_splice(&referenced, &sb->s_dentry_lru);
536 spin_unlock(&dcache_lock); 536 spin_unlock(&dcache_lock);
537
537} 538}
538 539
539/** 540/**
@@ -619,13 +620,19 @@ static void prune_dcache(int count)
619 * shrink_dcache_sb - shrink dcache for a superblock 620 * shrink_dcache_sb - shrink dcache for a superblock
620 * @sb: superblock 621 * @sb: superblock
621 * 622 *
622 * Shrink the dcache for the specified super block. This 623 * Shrink the dcache for the specified super block. This is used to free
623 * is used to free the dcache before unmounting a file 624 * the dcache before unmounting a file system.
624 * system
625 */ 625 */
626void shrink_dcache_sb(struct super_block * sb) 626void shrink_dcache_sb(struct super_block *sb)
627{ 627{
628 __shrink_dcache_sb(sb, NULL, 0); 628 LIST_HEAD(tmp);
629
630 spin_lock(&dcache_lock);
631 while (!list_empty(&sb->s_dentry_lru)) {
632 list_splice_init(&sb->s_dentry_lru, &tmp);
633 shrink_dentry_list(&tmp);
634 }
635 spin_unlock(&dcache_lock);
629} 636}
630EXPORT_SYMBOL(shrink_dcache_sb); 637EXPORT_SYMBOL(shrink_dcache_sb);
631 638