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); |
