aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-10-07 00:29:46 -0400
committerJ. Bruce Fields <bfields@redhat.com>2010-10-11 19:30:28 -0400
commite33534d54f1fde3e541f64fa5ad0dd379fc45fa7 (patch)
treed7136fd857a84576a984f2441b7ee03fc9afd24e
parentd29068c431599fa96729556846562eb18429092d (diff)
sunrpc/cache: centralise handling of size limit on deferred list.
We limit the number of 'defer' requests to DFR_MAX. The imposition of this limit is spread about a bit - sometime we don't add new things to the list, sometimes we remove old things. Also it is currently applied to requests which we are 'waiting' for rather than 'deferring'. This doesn't seem ideal as 'waiting' requests are naturally limited by the number of threads. So gather the DFR_MAX handling code to one place and only apply it to requests that are actually being deferred. This means that not all 'cache_deferred_req' structures go on the 'cache_defer_list, so we need to be careful when adding and removing things. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--net/sunrpc/cache.c67
1 files changed, 43 insertions, 24 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 49115b107fb..ba61d0fa4b8 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -513,22 +513,25 @@ static int cache_defer_cnt;
513 513
514static void __unhash_deferred_req(struct cache_deferred_req *dreq) 514static void __unhash_deferred_req(struct cache_deferred_req *dreq)
515{ 515{
516 list_del_init(&dreq->recent);
517 hlist_del_init(&dreq->hash); 516 hlist_del_init(&dreq->hash);
518 cache_defer_cnt--; 517 if (!list_empty(&dreq->recent)) {
518 list_del_init(&dreq->recent);
519 cache_defer_cnt--;
520 }
519} 521}
520 522
521static void __hash_deferred_req(struct cache_deferred_req *dreq, struct cache_head *item) 523static void __hash_deferred_req(struct cache_deferred_req *dreq, struct cache_head *item)
522{ 524{
523 int hash = DFR_HASH(item); 525 int hash = DFR_HASH(item);
524 526
525 list_add(&dreq->recent, &cache_defer_list); 527 INIT_LIST_HEAD(&dreq->recent);
526 hlist_add_head(&dreq->hash, &cache_defer_hash[hash]); 528 hlist_add_head(&dreq->hash, &cache_defer_hash[hash]);
527} 529}
528 530
529static void setup_deferral(struct cache_deferred_req *dreq, struct cache_head *item) 531static void setup_deferral(struct cache_deferred_req *dreq,
532 struct cache_head *item,
533 int count_me)
530{ 534{
531 struct cache_deferred_req *discard;
532 535
533 dreq->item = item; 536 dreq->item = item;
534 537
@@ -536,18 +539,13 @@ static void setup_deferral(struct cache_deferred_req *dreq, struct cache_head *i
536 539
537 __hash_deferred_req(dreq, item); 540 __hash_deferred_req(dreq, item);
538 541
539 /* it is in, now maybe clean up */ 542 if (count_me) {
540 discard = NULL; 543 cache_defer_cnt++;
541 if (++cache_defer_cnt > DFR_MAX) { 544 list_add(&dreq->recent, &cache_defer_list);
542 discard = list_entry(cache_defer_list.prev,
543 struct cache_deferred_req, recent);
544 __unhash_deferred_req(discard);
545 } 545 }
546
546 spin_unlock(&cache_defer_lock); 547 spin_unlock(&cache_defer_lock);
547 548
548 if (discard)
549 /* there was one too many */
550 discard->revisit(discard, 1);
551} 549}
552 550
553struct thread_deferred_req { 551struct thread_deferred_req {
@@ -570,7 +568,7 @@ static void cache_wait_req(struct cache_req *req, struct cache_head *item)
570 sleeper.completion = COMPLETION_INITIALIZER_ONSTACK(sleeper.completion); 568 sleeper.completion = COMPLETION_INITIALIZER_ONSTACK(sleeper.completion);
571 dreq->revisit = cache_restart_thread; 569 dreq->revisit = cache_restart_thread;
572 570
573 setup_deferral(dreq, item); 571 setup_deferral(dreq, item, 0);
574 572
575 if (!test_bit(CACHE_PENDING, &item->flags) || 573 if (!test_bit(CACHE_PENDING, &item->flags) ||
576 wait_for_completion_interruptible_timeout( 574 wait_for_completion_interruptible_timeout(
@@ -594,17 +592,36 @@ static void cache_wait_req(struct cache_req *req, struct cache_head *item)
594 } 592 }
595} 593}
596 594
597static void cache_defer_req(struct cache_req *req, struct cache_head *item) 595static void cache_limit_defers(void)
598{ 596{
599 struct cache_deferred_req *dreq; 597 /* Make sure we haven't exceed the limit of allowed deferred
598 * requests.
599 */
600 struct cache_deferred_req *discard = NULL;
600 601
601 if (cache_defer_cnt >= DFR_MAX) 602 if (cache_defer_cnt <= DFR_MAX)
602 /* too much in the cache, randomly drop this one, 603 return;
603 * or continue and drop the oldest 604
604 */ 605 spin_lock(&cache_defer_lock);
605 if (net_random()&1)
606 return;
607 606
607 /* Consider removing either the first or the last */
608 if (cache_defer_cnt > DFR_MAX) {
609 if (net_random() & 1)
610 discard = list_entry(cache_defer_list.next,
611 struct cache_deferred_req, recent);
612 else
613 discard = list_entry(cache_defer_list.prev,
614 struct cache_deferred_req, recent);
615 __unhash_deferred_req(discard);
616 }
617 spin_unlock(&cache_defer_lock);
618 if (discard)
619 discard->revisit(discard, 1);
620}
621
622static void cache_defer_req(struct cache_req *req, struct cache_head *item)
623{
624 struct cache_deferred_req *dreq;
608 625
609 if (req->thread_wait) { 626 if (req->thread_wait) {
610 cache_wait_req(req, item); 627 cache_wait_req(req, item);
@@ -614,12 +631,14 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item)
614 dreq = req->defer(req); 631 dreq = req->defer(req);
615 if (dreq == NULL) 632 if (dreq == NULL)
616 return; 633 return;
617 setup_deferral(dreq, item); 634 setup_deferral(dreq, item, 1);
618 if (!test_bit(CACHE_PENDING, &item->flags)) 635 if (!test_bit(CACHE_PENDING, &item->flags))
619 /* Bit could have been cleared before we managed to 636 /* Bit could have been cleared before we managed to
620 * set up the deferral, so need to revisit just in case 637 * set up the deferral, so need to revisit just in case
621 */ 638 */
622 cache_revisit_request(item); 639 cache_revisit_request(item);
640
641 cache_limit_defers();
623} 642}
624 643
625static void cache_revisit_request(struct cache_head *item) 644static void cache_revisit_request(struct cache_head *item)