diff options
author | NeilBrown <neilb@suse.de> | 2009-08-04 15:22:38 +1000 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-08-04 16:21:44 -0400 |
commit | 989a19b9b10635eeb91c08cefe6cf82986bd4ee2 (patch) | |
tree | dc18e7d07558c7a217daed108ec9d62ec9be4836 /net | |
parent | 5c4d26390341732a8d614141a4cf4663610a1698 (diff) | |
download | linux-stable-989a19b9b10635eeb91c08cefe6cf82986bd4ee2.tar.gz linux-stable-989a19b9b10635eeb91c08cefe6cf82986bd4ee2.tar.bz2 linux-stable-989a19b9b10635eeb91c08cefe6cf82986bd4ee2.zip |
sunrpc/cache: recheck cache validity after cache_defer_req
If cache_defer_req did not leave the request on a queue, then it could
possibly have waited long enough that the cache became valid. So check the
status after the call.
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/cache.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 44f45166378a..bbd31f1215e7 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -176,6 +176,22 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, EXPORT_SYMBOL_GPL(sunrpc_cache_update); static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); + +static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) +{ + if (!test_bit(CACHE_VALID, &h->flags) || + h->expiry_time < get_seconds()) + return -EAGAIN; + else if (detail->flush_time > h->last_refresh) + return -EAGAIN; + else { + /* entry is valid */ + if (test_bit(CACHE_NEGATIVE, &h->flags)) + return -ENOENT; + else + return 0; + } +} /* * This is the generic cache management routine for all * the authentication caches. @@ -184,8 +200,10 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); * * * Returns 0 if the cache_head can be used, or cache_puts it and returns - * -EAGAIN if upcall is pending, - * -ETIMEDOUT if upcall failed and should be retried, + * -EAGAIN if upcall is pending and request has been queued + * -ETIMEDOUT if upcall failed or request could not be queue or + * upcall completed but item is still invalid (implying that + * the cache item has been replaced with a newer one). * -ENOENT if cache entry was negative */ int cache_check(struct cache_detail *detail, @@ -195,17 +213,7 @@ int cache_check(struct cache_detail *detail, long refresh_age, age; /* First decide return status as best we can */ - if (!test_bit(CACHE_VALID, &h->flags) || - h->expiry_time < get_seconds()) - rv = -EAGAIN; - else if (detail->flush_time > h->last_refresh) - rv = -EAGAIN; - else { - /* entry is valid */ - if (test_bit(CACHE_NEGATIVE, &h->flags)) - rv = -ENOENT; - else rv = 0; - } + rv = cache_is_valid(detail, h); /* now see if we want to start an upcall */ refresh_age = (h->expiry_time - h->last_refresh); @@ -238,10 +246,14 @@ int cache_check(struct cache_detail *detail, } } - if (rv == -EAGAIN) - if (cache_defer_req(rqstp, h) != 0) - rv = -ETIMEDOUT; - + if (rv == -EAGAIN) { + if (cache_defer_req(rqstp, h) == 0) { + /* Request is not deferred */ + rv = cache_is_valid(detail, h); + if (rv == -EAGAIN) + rv = -ETIMEDOUT; + } + } if (rv) cache_put(h, detail); return rv; @@ -560,11 +572,11 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item) * or continue and drop the oldest below */ if (net_random()&1) - return -ETIMEDOUT; + return 0; } dreq = req->defer(req); if (dreq == NULL) - return -ETIMEDOUT; + return 0; dreq->item = item; @@ -594,8 +606,9 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item) if (!test_bit(CACHE_PENDING, &item->flags)) { /* must have just been validated... */ cache_revisit_request(item); + return 0; } - return 0; + return 1; } static void cache_revisit_request(struct cache_head *item) |