aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/cache.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-08-12 03:04:06 -0400
committerJ. Bruce Fields <bfields@redhat.com>2010-09-07 19:22:07 -0400
commitf16b6e8d838b2e2bb4561201311c66ac02ad67df (patch)
tree92c4ab62aa566029ce25989ef7dc8e3634365f63 /net/sunrpc/cache.c
parentc5b29f885afe890f953f7f23424045cdad31d3e4 (diff)
sunrpc/cache: allow threads to block while waiting for cache update.
The current practice of waiting for cache updates by queueing the whole request to be retried has (at least) two problems. 1/ With NFSv4, requests can be quite complex and re-trying a whole request when a later part fails should only be a last-resort, not a normal practice. 2/ Large requests, and in particular any 'write' request, will not be queued by the current code and doing so would be undesirable. In many cases only a very sort wait is needed before the cache gets valid data. So, providing the underlying transport permits it by setting ->thread_wait, arrange to wait briefly for an upcall to be completed (as reflected in the clearing of CACHE_PENDING). If the short wait was not long enough and CACHE_PENDING is still set, fall back on the old approach. The 'thread_wait' value is set to 5 seconds when there are spare threads, and 1 second when there are no spare threads. These values are probably much higher than needed, but will ensure some forward progress. Note that as we only request an update for a non-valid item, and as non-valid items are updated in place it is extremely unlikely that cache_check will return -ETIMEDOUT. Normally cache_defer_req will sleep for a short while and then find that the item is_valid. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net/sunrpc/cache.c')
-rw-r--r--net/sunrpc/cache.c59
1 files changed, 58 insertions, 1 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 8dc121955fdc..2c5297f245b4 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -509,10 +509,22 @@ static LIST_HEAD(cache_defer_list);
509static struct list_head cache_defer_hash[DFR_HASHSIZE]; 509static struct list_head cache_defer_hash[DFR_HASHSIZE];
510static int cache_defer_cnt; 510static int cache_defer_cnt;
511 511
512struct thread_deferred_req {
513 struct cache_deferred_req handle;
514 struct completion completion;
515};
516static void cache_restart_thread(struct cache_deferred_req *dreq, int too_many)
517{
518 struct thread_deferred_req *dr =
519 container_of(dreq, struct thread_deferred_req, handle);
520 complete(&dr->completion);
521}
522
512static int cache_defer_req(struct cache_req *req, struct cache_head *item) 523static int cache_defer_req(struct cache_req *req, struct cache_head *item)
513{ 524{
514 struct cache_deferred_req *dreq, *discard; 525 struct cache_deferred_req *dreq, *discard;
515 int hash = DFR_HASH(item); 526 int hash = DFR_HASH(item);
527 struct thread_deferred_req sleeper;
516 528
517 if (cache_defer_cnt >= DFR_MAX) { 529 if (cache_defer_cnt >= DFR_MAX) {
518 /* too much in the cache, randomly drop this one, 530 /* too much in the cache, randomly drop this one,
@@ -521,7 +533,15 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
521 if (net_random()&1) 533 if (net_random()&1)
522 return -ENOMEM; 534 return -ENOMEM;
523 } 535 }
524 dreq = req->defer(req); 536 if (req->thread_wait) {
537 dreq = &sleeper.handle;
538 sleeper.completion =
539 COMPLETION_INITIALIZER_ONSTACK(sleeper.completion);
540 dreq->revisit = cache_restart_thread;
541 } else
542 dreq = req->defer(req);
543
544 retry:
525 if (dreq == NULL) 545 if (dreq == NULL)
526 return -ENOMEM; 546 return -ENOMEM;
527 547
@@ -555,6 +575,43 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
555 cache_revisit_request(item); 575 cache_revisit_request(item);
556 return -EAGAIN; 576 return -EAGAIN;
557 } 577 }
578
579 if (dreq == &sleeper.handle) {
580 if (wait_for_completion_interruptible_timeout(
581 &sleeper.completion, req->thread_wait) <= 0) {
582 /* The completion wasn't completed, so we need
583 * to clean up
584 */
585 spin_lock(&cache_defer_lock);
586 if (!list_empty(&sleeper.handle.hash)) {
587 list_del_init(&sleeper.handle.recent);
588 list_del_init(&sleeper.handle.hash);
589 cache_defer_cnt--;
590 spin_unlock(&cache_defer_lock);
591 } else {
592 /* cache_revisit_request already removed
593 * this from the hash table, but hasn't
594 * called ->revisit yet. It will very soon
595 * and we need to wait for it.
596 */
597 spin_unlock(&cache_defer_lock);
598 wait_for_completion(&sleeper.completion);
599 }
600 }
601 if (test_bit(CACHE_PENDING, &item->flags)) {
602 /* item is still pending, try request
603 * deferral
604 */
605 dreq = req->defer(req);
606 goto retry;
607 }
608 /* only return success if we actually deferred the
609 * request. In this case we waited until it was
610 * answered so no deferral has happened - rather
611 * an answer already exists.
612 */
613 return -EEXIST;
614 }
558 return 0; 615 return 0;
559} 616}
560 617