diff options
author | NeilBrown <neilb@suse.de> | 2009-08-04 01:22:38 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-08-04 16:21:44 -0400 |
commit | 989a19b9b10635eeb91c08cefe6cf82986bd4ee2 (patch) | |
tree | dc18e7d07558c7a217daed108ec9d62ec9be4836 | |
parent | 5c4d26390341732a8d614141a4cf4663610a1698 (diff) |
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>
-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, | |||
176 | EXPORT_SYMBOL_GPL(sunrpc_cache_update); | 176 | EXPORT_SYMBOL_GPL(sunrpc_cache_update); |
177 | 177 | ||
178 | static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); | 178 | static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); |
179 | |||
180 | static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) | ||
181 | { | ||
182 | if (!test_bit(CACHE_VALID, &h->flags) || | ||
183 | h->expiry_time < get_seconds()) | ||
184 | return -EAGAIN; | ||
185 | else if (detail->flush_time > h->last_refresh) | ||
186 | return -EAGAIN; | ||
187 | else { | ||
188 | /* entry is valid */ | ||
189 | if (test_bit(CACHE_NEGATIVE, &h->flags)) | ||
190 | return -ENOENT; | ||
191 | else | ||
192 | return 0; | ||
193 | } | ||
194 | } | ||
179 | /* | 195 | /* |
180 | * This is the generic cache management routine for all | 196 | * This is the generic cache management routine for all |
181 | * the authentication caches. | 197 | * the authentication caches. |
@@ -184,8 +200,10 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); | |||
184 | * | 200 | * |
185 | * | 201 | * |
186 | * Returns 0 if the cache_head can be used, or cache_puts it and returns | 202 | * Returns 0 if the cache_head can be used, or cache_puts it and returns |
187 | * -EAGAIN if upcall is pending, | 203 | * -EAGAIN if upcall is pending and request has been queued |
188 | * -ETIMEDOUT if upcall failed and should be retried, | 204 | * -ETIMEDOUT if upcall failed or request could not be queue or |
205 | * upcall completed but item is still invalid (implying that | ||
206 | * the cache item has been replaced with a newer one). | ||
189 | * -ENOENT if cache entry was negative | 207 | * -ENOENT if cache entry was negative |
190 | */ | 208 | */ |
191 | int cache_check(struct cache_detail *detail, | 209 | int cache_check(struct cache_detail *detail, |
@@ -195,17 +213,7 @@ int cache_check(struct cache_detail *detail, | |||
195 | long refresh_age, age; | 213 | long refresh_age, age; |
196 | 214 | ||
197 | /* First decide return status as best we can */ | 215 | /* First decide return status as best we can */ |
198 | if (!test_bit(CACHE_VALID, &h->flags) || | 216 | rv = cache_is_valid(detail, h); |
199 | h->expiry_time < get_seconds()) | ||
200 | rv = -EAGAIN; | ||
201 | else if (detail->flush_time > h->last_refresh) | ||
202 | rv = -EAGAIN; | ||
203 | else { | ||
204 | /* entry is valid */ | ||
205 | if (test_bit(CACHE_NEGATIVE, &h->flags)) | ||
206 | rv = -ENOENT; | ||
207 | else rv = 0; | ||
208 | } | ||
209 | 217 | ||
210 | /* now see if we want to start an upcall */ | 218 | /* now see if we want to start an upcall */ |
211 | refresh_age = (h->expiry_time - h->last_refresh); | 219 | refresh_age = (h->expiry_time - h->last_refresh); |
@@ -238,10 +246,14 @@ int cache_check(struct cache_detail *detail, | |||
238 | } | 246 | } |
239 | } | 247 | } |
240 | 248 | ||
241 | if (rv == -EAGAIN) | 249 | if (rv == -EAGAIN) { |
242 | if (cache_defer_req(rqstp, h) != 0) | 250 | if (cache_defer_req(rqstp, h) == 0) { |
243 | rv = -ETIMEDOUT; | 251 | /* Request is not deferred */ |
244 | 252 | rv = cache_is_valid(detail, h); | |
253 | if (rv == -EAGAIN) | ||
254 | rv = -ETIMEDOUT; | ||
255 | } | ||
256 | } | ||
245 | if (rv) | 257 | if (rv) |
246 | cache_put(h, detail); | 258 | cache_put(h, detail); |
247 | return rv; | 259 | return rv; |
@@ -560,11 +572,11 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item) | |||
560 | * or continue and drop the oldest below | 572 | * or continue and drop the oldest below |
561 | */ | 573 | */ |
562 | if (net_random()&1) | 574 | if (net_random()&1) |
563 | return -ETIMEDOUT; | 575 | return 0; |
564 | } | 576 | } |
565 | dreq = req->defer(req); | 577 | dreq = req->defer(req); |
566 | if (dreq == NULL) | 578 | if (dreq == NULL) |
567 | return -ETIMEDOUT; | 579 | return 0; |
568 | 580 | ||
569 | dreq->item = item; | 581 | dreq->item = item; |
570 | 582 | ||
@@ -594,8 +606,9 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item) | |||
594 | if (!test_bit(CACHE_PENDING, &item->flags)) { | 606 | if (!test_bit(CACHE_PENDING, &item->flags)) { |
595 | /* must have just been validated... */ | 607 | /* must have just been validated... */ |
596 | cache_revisit_request(item); | 608 | cache_revisit_request(item); |
609 | return 0; | ||
597 | } | 610 | } |
598 | return 0; | 611 | return 1; |
599 | } | 612 | } |
600 | 613 | ||
601 | static void cache_revisit_request(struct cache_head *item) | 614 | static void cache_revisit_request(struct cache_head *item) |