diff options
Diffstat (limited to 'net/sunrpc/cache.c')
-rw-r--r-- | net/sunrpc/cache.c | 109 |
1 files changed, 61 insertions, 48 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 45cdaff9b361..d6eee291a0e2 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
@@ -103,23 +103,21 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, | |||
103 | EXPORT_SYMBOL_GPL(sunrpc_cache_lookup); | 103 | EXPORT_SYMBOL_GPL(sunrpc_cache_lookup); |
104 | 104 | ||
105 | 105 | ||
106 | static void queue_loose(struct cache_detail *detail, struct cache_head *ch); | 106 | static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch); |
107 | 107 | ||
108 | static int cache_fresh_locked(struct cache_head *head, time_t expiry) | 108 | static void cache_fresh_locked(struct cache_head *head, time_t expiry) |
109 | { | 109 | { |
110 | head->expiry_time = expiry; | 110 | head->expiry_time = expiry; |
111 | head->last_refresh = get_seconds(); | 111 | head->last_refresh = get_seconds(); |
112 | return !test_and_set_bit(CACHE_VALID, &head->flags); | 112 | set_bit(CACHE_VALID, &head->flags); |
113 | } | 113 | } |
114 | 114 | ||
115 | static void cache_fresh_unlocked(struct cache_head *head, | 115 | static void cache_fresh_unlocked(struct cache_head *head, |
116 | struct cache_detail *detail, int new) | 116 | struct cache_detail *detail) |
117 | { | 117 | { |
118 | if (new) | ||
119 | cache_revisit_request(head); | ||
120 | if (test_and_clear_bit(CACHE_PENDING, &head->flags)) { | 118 | if (test_and_clear_bit(CACHE_PENDING, &head->flags)) { |
121 | cache_revisit_request(head); | 119 | cache_revisit_request(head); |
122 | queue_loose(detail, head); | 120 | cache_dequeue(detail, head); |
123 | } | 121 | } |
124 | } | 122 | } |
125 | 123 | ||
@@ -132,7 +130,6 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, | |||
132 | */ | 130 | */ |
133 | struct cache_head **head; | 131 | struct cache_head **head; |
134 | struct cache_head *tmp; | 132 | struct cache_head *tmp; |
135 | int is_new; | ||
136 | 133 | ||
137 | if (!test_bit(CACHE_VALID, &old->flags)) { | 134 | if (!test_bit(CACHE_VALID, &old->flags)) { |
138 | write_lock(&detail->hash_lock); | 135 | write_lock(&detail->hash_lock); |
@@ -141,9 +138,9 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, | |||
141 | set_bit(CACHE_NEGATIVE, &old->flags); | 138 | set_bit(CACHE_NEGATIVE, &old->flags); |
142 | else | 139 | else |
143 | detail->update(old, new); | 140 | detail->update(old, new); |
144 | is_new = cache_fresh_locked(old, new->expiry_time); | 141 | cache_fresh_locked(old, new->expiry_time); |
145 | write_unlock(&detail->hash_lock); | 142 | write_unlock(&detail->hash_lock); |
146 | cache_fresh_unlocked(old, detail, is_new); | 143 | cache_fresh_unlocked(old, detail); |
147 | return old; | 144 | return old; |
148 | } | 145 | } |
149 | write_unlock(&detail->hash_lock); | 146 | write_unlock(&detail->hash_lock); |
@@ -167,11 +164,11 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail, | |||
167 | *head = tmp; | 164 | *head = tmp; |
168 | detail->entries++; | 165 | detail->entries++; |
169 | cache_get(tmp); | 166 | cache_get(tmp); |
170 | is_new = cache_fresh_locked(tmp, new->expiry_time); | 167 | cache_fresh_locked(tmp, new->expiry_time); |
171 | cache_fresh_locked(old, 0); | 168 | cache_fresh_locked(old, 0); |
172 | write_unlock(&detail->hash_lock); | 169 | write_unlock(&detail->hash_lock); |
173 | cache_fresh_unlocked(tmp, detail, is_new); | 170 | cache_fresh_unlocked(tmp, detail); |
174 | cache_fresh_unlocked(old, detail, 0); | 171 | cache_fresh_unlocked(old, detail); |
175 | cache_put(old, detail); | 172 | cache_put(old, detail); |
176 | return tmp; | 173 | return tmp; |
177 | } | 174 | } |
@@ -184,6 +181,22 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) | |||
184 | return cd->cache_upcall(cd, h); | 181 | return cd->cache_upcall(cd, h); |
185 | } | 182 | } |
186 | 183 | ||
184 | static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) | ||
185 | { | ||
186 | if (!test_bit(CACHE_VALID, &h->flags) || | ||
187 | h->expiry_time < get_seconds()) | ||
188 | return -EAGAIN; | ||
189 | else if (detail->flush_time > h->last_refresh) | ||
190 | return -EAGAIN; | ||
191 | else { | ||
192 | /* entry is valid */ | ||
193 | if (test_bit(CACHE_NEGATIVE, &h->flags)) | ||
194 | return -ENOENT; | ||
195 | else | ||
196 | return 0; | ||
197 | } | ||
198 | } | ||
199 | |||
187 | /* | 200 | /* |
188 | * This is the generic cache management routine for all | 201 | * This is the generic cache management routine for all |
189 | * the authentication caches. | 202 | * the authentication caches. |
@@ -192,8 +205,10 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) | |||
192 | * | 205 | * |
193 | * | 206 | * |
194 | * Returns 0 if the cache_head can be used, or cache_puts it and returns | 207 | * Returns 0 if the cache_head can be used, or cache_puts it and returns |
195 | * -EAGAIN if upcall is pending, | 208 | * -EAGAIN if upcall is pending and request has been queued |
196 | * -ETIMEDOUT if upcall failed and should be retried, | 209 | * -ETIMEDOUT if upcall failed or request could not be queue or |
210 | * upcall completed but item is still invalid (implying that | ||
211 | * the cache item has been replaced with a newer one). | ||
197 | * -ENOENT if cache entry was negative | 212 | * -ENOENT if cache entry was negative |
198 | */ | 213 | */ |
199 | int cache_check(struct cache_detail *detail, | 214 | int cache_check(struct cache_detail *detail, |
@@ -203,17 +218,7 @@ int cache_check(struct cache_detail *detail, | |||
203 | long refresh_age, age; | 218 | long refresh_age, age; |
204 | 219 | ||
205 | /* First decide return status as best we can */ | 220 | /* First decide return status as best we can */ |
206 | if (!test_bit(CACHE_VALID, &h->flags) || | 221 | rv = cache_is_valid(detail, h); |
207 | h->expiry_time < get_seconds()) | ||
208 | rv = -EAGAIN; | ||
209 | else if (detail->flush_time > h->last_refresh) | ||
210 | rv = -EAGAIN; | ||
211 | else { | ||
212 | /* entry is valid */ | ||
213 | if (test_bit(CACHE_NEGATIVE, &h->flags)) | ||
214 | rv = -ENOENT; | ||
215 | else rv = 0; | ||
216 | } | ||
217 | 222 | ||
218 | /* now see if we want to start an upcall */ | 223 | /* now see if we want to start an upcall */ |
219 | refresh_age = (h->expiry_time - h->last_refresh); | 224 | refresh_age = (h->expiry_time - h->last_refresh); |
@@ -229,10 +234,11 @@ int cache_check(struct cache_detail *detail, | |||
229 | switch (cache_make_upcall(detail, h)) { | 234 | switch (cache_make_upcall(detail, h)) { |
230 | case -EINVAL: | 235 | case -EINVAL: |
231 | clear_bit(CACHE_PENDING, &h->flags); | 236 | clear_bit(CACHE_PENDING, &h->flags); |
237 | cache_revisit_request(h); | ||
232 | if (rv == -EAGAIN) { | 238 | if (rv == -EAGAIN) { |
233 | set_bit(CACHE_NEGATIVE, &h->flags); | 239 | set_bit(CACHE_NEGATIVE, &h->flags); |
234 | cache_fresh_unlocked(h, detail, | 240 | cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY); |
235 | cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY)); | 241 | cache_fresh_unlocked(h, detail); |
236 | rv = -ENOENT; | 242 | rv = -ENOENT; |
237 | } | 243 | } |
238 | break; | 244 | break; |
@@ -245,10 +251,14 @@ int cache_check(struct cache_detail *detail, | |||
245 | } | 251 | } |
246 | } | 252 | } |
247 | 253 | ||
248 | if (rv == -EAGAIN) | 254 | if (rv == -EAGAIN) { |
249 | if (cache_defer_req(rqstp, h) != 0) | 255 | if (cache_defer_req(rqstp, h) < 0) { |
250 | rv = -ETIMEDOUT; | 256 | /* Request is not deferred */ |
251 | 257 | rv = cache_is_valid(detail, h); | |
258 | if (rv == -EAGAIN) | ||
259 | rv = -ETIMEDOUT; | ||
260 | } | ||
261 | } | ||
252 | if (rv) | 262 | if (rv) |
253 | cache_put(h, detail); | 263 | cache_put(h, detail); |
254 | return rv; | 264 | return rv; |
@@ -396,7 +406,7 @@ static int cache_clean(void) | |||
396 | ) | 406 | ) |
397 | continue; | 407 | continue; |
398 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) | 408 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) |
399 | queue_loose(current_detail, ch); | 409 | cache_dequeue(current_detail, ch); |
400 | 410 | ||
401 | if (atomic_read(&ch->ref.refcount) == 1) | 411 | if (atomic_read(&ch->ref.refcount) == 1) |
402 | break; | 412 | break; |
@@ -412,8 +422,10 @@ static int cache_clean(void) | |||
412 | if (!ch) | 422 | if (!ch) |
413 | current_index ++; | 423 | current_index ++; |
414 | spin_unlock(&cache_list_lock); | 424 | spin_unlock(&cache_list_lock); |
415 | if (ch) | 425 | if (ch) { |
426 | cache_revisit_request(ch); | ||
416 | cache_put(ch, d); | 427 | cache_put(ch, d); |
428 | } | ||
417 | } else | 429 | } else |
418 | spin_unlock(&cache_list_lock); | 430 | spin_unlock(&cache_list_lock); |
419 | 431 | ||
@@ -488,7 +500,7 @@ static int cache_defer_cnt; | |||
488 | 500 | ||
489 | static int cache_defer_req(struct cache_req *req, struct cache_head *item) | 501 | static int cache_defer_req(struct cache_req *req, struct cache_head *item) |
490 | { | 502 | { |
491 | struct cache_deferred_req *dreq; | 503 | struct cache_deferred_req *dreq, *discard; |
492 | int hash = DFR_HASH(item); | 504 | int hash = DFR_HASH(item); |
493 | 505 | ||
494 | if (cache_defer_cnt >= DFR_MAX) { | 506 | if (cache_defer_cnt >= DFR_MAX) { |
@@ -496,11 +508,11 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item) | |||
496 | * or continue and drop the oldest below | 508 | * or continue and drop the oldest below |
497 | */ | 509 | */ |
498 | if (net_random()&1) | 510 | if (net_random()&1) |
499 | return -ETIMEDOUT; | 511 | return -ENOMEM; |
500 | } | 512 | } |
501 | dreq = req->defer(req); | 513 | dreq = req->defer(req); |
502 | if (dreq == NULL) | 514 | if (dreq == NULL) |
503 | return -ETIMEDOUT; | 515 | return -ENOMEM; |
504 | 516 | ||
505 | dreq->item = item; | 517 | dreq->item = item; |
506 | 518 | ||
@@ -513,23 +525,24 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item) | |||
513 | list_add(&dreq->hash, &cache_defer_hash[hash]); | 525 | list_add(&dreq->hash, &cache_defer_hash[hash]); |
514 | 526 | ||
515 | /* it is in, now maybe clean up */ | 527 | /* it is in, now maybe clean up */ |
516 | dreq = NULL; | 528 | discard = NULL; |
517 | if (++cache_defer_cnt > DFR_MAX) { | 529 | if (++cache_defer_cnt > DFR_MAX) { |
518 | dreq = list_entry(cache_defer_list.prev, | 530 | discard = list_entry(cache_defer_list.prev, |
519 | struct cache_deferred_req, recent); | 531 | struct cache_deferred_req, recent); |
520 | list_del(&dreq->recent); | 532 | list_del_init(&discard->recent); |
521 | list_del(&dreq->hash); | 533 | list_del_init(&discard->hash); |
522 | cache_defer_cnt--; | 534 | cache_defer_cnt--; |
523 | } | 535 | } |
524 | spin_unlock(&cache_defer_lock); | 536 | spin_unlock(&cache_defer_lock); |
525 | 537 | ||
526 | if (dreq) { | 538 | if (discard) |
527 | /* there was one too many */ | 539 | /* there was one too many */ |
528 | dreq->revisit(dreq, 1); | 540 | discard->revisit(discard, 1); |
529 | } | 541 | |
530 | if (!test_bit(CACHE_PENDING, &item->flags)) { | 542 | if (!test_bit(CACHE_PENDING, &item->flags)) { |
531 | /* must have just been validated... */ | 543 | /* must have just been validated... */ |
532 | cache_revisit_request(item); | 544 | cache_revisit_request(item); |
545 | return -EAGAIN; | ||
533 | } | 546 | } |
534 | return 0; | 547 | return 0; |
535 | } | 548 | } |
@@ -551,7 +564,7 @@ static void cache_revisit_request(struct cache_head *item) | |||
551 | dreq = list_entry(lp, struct cache_deferred_req, hash); | 564 | dreq = list_entry(lp, struct cache_deferred_req, hash); |
552 | lp = lp->next; | 565 | lp = lp->next; |
553 | if (dreq->item == item) { | 566 | if (dreq->item == item) { |
554 | list_del(&dreq->hash); | 567 | list_del_init(&dreq->hash); |
555 | list_move(&dreq->recent, &pending); | 568 | list_move(&dreq->recent, &pending); |
556 | cache_defer_cnt--; | 569 | cache_defer_cnt--; |
557 | } | 570 | } |
@@ -577,7 +590,7 @@ void cache_clean_deferred(void *owner) | |||
577 | 590 | ||
578 | list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) { | 591 | list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) { |
579 | if (dreq->owner == owner) { | 592 | if (dreq->owner == owner) { |
580 | list_del(&dreq->hash); | 593 | list_del_init(&dreq->hash); |
581 | list_move(&dreq->recent, &pending); | 594 | list_move(&dreq->recent, &pending); |
582 | cache_defer_cnt--; | 595 | cache_defer_cnt--; |
583 | } | 596 | } |
@@ -887,7 +900,7 @@ static int cache_release(struct inode *inode, struct file *filp, | |||
887 | 900 | ||
888 | 901 | ||
889 | 902 | ||
890 | static void queue_loose(struct cache_detail *detail, struct cache_head *ch) | 903 | static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch) |
891 | { | 904 | { |
892 | struct cache_queue *cq; | 905 | struct cache_queue *cq; |
893 | spin_lock(&queue_lock); | 906 | spin_lock(&queue_lock); |