diff options
Diffstat (limited to 'net/sunrpc/cache.c')
| -rw-r--r-- | net/sunrpc/cache.c | 180 |
1 files changed, 145 insertions, 35 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index dcaa0c4453ff..3ac4193a78ed 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/proc_fs.h> | 26 | #include <linux/proc_fs.h> |
| 27 | #include <linux/net.h> | 27 | #include <linux/net.h> |
| 28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
| 29 | #include <linux/mutex.h> | ||
| 29 | #include <asm/ioctls.h> | 30 | #include <asm/ioctls.h> |
| 30 | #include <linux/sunrpc/types.h> | 31 | #include <linux/sunrpc/types.h> |
| 31 | #include <linux/sunrpc/cache.h> | 32 | #include <linux/sunrpc/cache.h> |
| @@ -36,16 +37,138 @@ | |||
| 36 | static void cache_defer_req(struct cache_req *req, struct cache_head *item); | 37 | static void cache_defer_req(struct cache_req *req, struct cache_head *item); |
| 37 | static void cache_revisit_request(struct cache_head *item); | 38 | static void cache_revisit_request(struct cache_head *item); |
| 38 | 39 | ||
| 39 | void cache_init(struct cache_head *h) | 40 | static void cache_init(struct cache_head *h) |
| 40 | { | 41 | { |
| 41 | time_t now = get_seconds(); | 42 | time_t now = get_seconds(); |
| 42 | h->next = NULL; | 43 | h->next = NULL; |
| 43 | h->flags = 0; | 44 | h->flags = 0; |
| 44 | atomic_set(&h->refcnt, 1); | 45 | kref_init(&h->ref); |
| 45 | h->expiry_time = now + CACHE_NEW_EXPIRY; | 46 | h->expiry_time = now + CACHE_NEW_EXPIRY; |
| 46 | h->last_refresh = now; | 47 | h->last_refresh = now; |
| 47 | } | 48 | } |
| 48 | 49 | ||
| 50 | struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, | ||
| 51 | struct cache_head *key, int hash) | ||
| 52 | { | ||
| 53 | struct cache_head **head, **hp; | ||
| 54 | struct cache_head *new = NULL; | ||
| 55 | |||
| 56 | head = &detail->hash_table[hash]; | ||
| 57 | |||
| 58 | read_lock(&detail->hash_lock); | ||
| 59 | |||
| 60 | for (hp=head; *hp != NULL ; hp = &(*hp)->next) { | ||
| 61 | struct cache_head *tmp = *hp; | ||
| 62 | if (detail->match(tmp, key)) { | ||
| 63 | cache_get(tmp); | ||
| 64 | read_unlock(&detail->hash_lock); | ||
| 65 | return tmp; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | read_unlock(&detail->hash_lock); | ||
| 69 | /* Didn't find anything, insert an empty entry */ | ||
| 70 | |||
| 71 | new = detail->alloc(); | ||
| 72 | if (!new) | ||
| 73 | return NULL; | ||
| 74 | cache_init(new); | ||
| 75 | |||
| 76 | write_lock(&detail->hash_lock); | ||
| 77 | |||
| 78 | /* check if entry appeared while we slept */ | ||
| 79 | for (hp=head; *hp != NULL ; hp = &(*hp)->next) { | ||
| 80 | struct cache_head *tmp = *hp; | ||
| 81 | if (detail->match(tmp, key)) { | ||
| 82 | cache_get(tmp); | ||
| 83 | write_unlock(&detail->hash_lock); | ||
| 84 | cache_put(new, detail); | ||
| 85 | return tmp; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | detail->init(new, key); | ||
| 89 | new->next = *head; | ||
| 90 | *head = new; | ||
| 91 | detail->entries++; | ||
| 92 | cache_get(new); | ||
| 93 | write_unlock(&detail->hash_lock); | ||
| 94 | |||
| 95 | return new; | ||
| 96 | } | ||
| 97 | EXPORT_SYMBOL(sunrpc_cache_lookup); | ||
| 98 | |||
| 99 | |||
| 100 | static void queue_loose(struct cache_detail *detail, struct cache_head *ch); | ||
| 101 | |||
| 102 | static int cache_fresh_locked(struct cache_head *head, time_t expiry) | ||
| 103 | { | ||
| 104 | head->expiry_time = expiry; | ||
| 105 | head->last_refresh = get_seconds(); | ||
| 106 | return !test_and_set_bit(CACHE_VALID, &head->flags); | ||
| 107 | } | ||
| 108 | |||
| 109 | static void cache_fresh_unlocked(struct cache_head *head, | ||
| 110 | struct cache_detail *detail, int new) | ||
| 111 | { | ||
| 112 | if (new) | ||
| 113 | cache_revisit_request(head); | ||
| 114 | if (test_and_clear_bit(CACHE_PENDING, &head->flags)) { | ||
| 115 | cache_revisit_request(head); | ||
| 116 | queue_loose(detail, head); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | struct cache_head *sunrpc_cache_update(struct cache_detail *detail, | ||
| 121 | struct cache_head *new, struct cache_head *old, int hash) | ||
| 122 | { | ||
| 123 | /* The 'old' entry is to be replaced by 'new'. | ||
| 124 | * If 'old' is not VALID, we update it directly, | ||
| 125 | * otherwise we need to replace it | ||
| 126 | */ | ||
| 127 | struct cache_head **head; | ||
| 128 | struct cache_head *tmp; | ||
| 129 | int is_new; | ||
| 130 | |||
| 131 | if (!test_bit(CACHE_VALID, &old->flags)) { | ||
| 132 | write_lock(&detail->hash_lock); | ||
| 133 | if (!test_bit(CACHE_VALID, &old->flags)) { | ||
| 134 | if (test_bit(CACHE_NEGATIVE, &new->flags)) | ||
| 135 | set_bit(CACHE_NEGATIVE, &old->flags); | ||
| 136 | else | ||
| 137 | detail->update(old, new); | ||
| 138 | is_new = cache_fresh_locked(old, new->expiry_time); | ||
| 139 | write_unlock(&detail->hash_lock); | ||
| 140 | cache_fresh_unlocked(old, detail, is_new); | ||
| 141 | return old; | ||
| 142 | } | ||
| 143 | write_unlock(&detail->hash_lock); | ||
| 144 | } | ||
| 145 | /* We need to insert a new entry */ | ||
| 146 | tmp = detail->alloc(); | ||
| 147 | if (!tmp) { | ||
| 148 | cache_put(old, detail); | ||
| 149 | return NULL; | ||
| 150 | } | ||
| 151 | cache_init(tmp); | ||
| 152 | detail->init(tmp, old); | ||
| 153 | head = &detail->hash_table[hash]; | ||
| 154 | |||
| 155 | write_lock(&detail->hash_lock); | ||
| 156 | if (test_bit(CACHE_NEGATIVE, &new->flags)) | ||
| 157 | set_bit(CACHE_NEGATIVE, &tmp->flags); | ||
| 158 | else | ||
| 159 | detail->update(tmp, new); | ||
| 160 | tmp->next = *head; | ||
| 161 | *head = tmp; | ||
| 162 | cache_get(tmp); | ||
| 163 | is_new = cache_fresh_locked(tmp, new->expiry_time); | ||
| 164 | cache_fresh_locked(old, 0); | ||
| 165 | write_unlock(&detail->hash_lock); | ||
| 166 | cache_fresh_unlocked(tmp, detail, is_new); | ||
| 167 | cache_fresh_unlocked(old, detail, 0); | ||
| 168 | cache_put(old, detail); | ||
| 169 | return tmp; | ||
| 170 | } | ||
| 171 | EXPORT_SYMBOL(sunrpc_cache_update); | ||
| 49 | 172 | ||
| 50 | static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); | 173 | static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h); |
| 51 | /* | 174 | /* |
| @@ -93,7 +216,8 @@ int cache_check(struct cache_detail *detail, | |||
| 93 | clear_bit(CACHE_PENDING, &h->flags); | 216 | clear_bit(CACHE_PENDING, &h->flags); |
| 94 | if (rv == -EAGAIN) { | 217 | if (rv == -EAGAIN) { |
| 95 | set_bit(CACHE_NEGATIVE, &h->flags); | 218 | set_bit(CACHE_NEGATIVE, &h->flags); |
| 96 | cache_fresh(detail, h, get_seconds()+CACHE_NEW_EXPIRY); | 219 | cache_fresh_unlocked(h, detail, |
| 220 | cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY)); | ||
| 97 | rv = -ENOENT; | 221 | rv = -ENOENT; |
| 98 | } | 222 | } |
| 99 | break; | 223 | break; |
| @@ -109,25 +233,11 @@ int cache_check(struct cache_detail *detail, | |||
| 109 | if (rv == -EAGAIN) | 233 | if (rv == -EAGAIN) |
| 110 | cache_defer_req(rqstp, h); | 234 | cache_defer_req(rqstp, h); |
| 111 | 235 | ||
| 112 | if (rv && h) | 236 | if (rv) |
| 113 | detail->cache_put(h, detail); | 237 | cache_put(h, detail); |
| 114 | return rv; | 238 | return rv; |
| 115 | } | 239 | } |
| 116 | 240 | ||
| 117 | static void queue_loose(struct cache_detail *detail, struct cache_head *ch); | ||
| 118 | |||
| 119 | void cache_fresh(struct cache_detail *detail, | ||
| 120 | struct cache_head *head, time_t expiry) | ||
| 121 | { | ||
| 122 | |||
| 123 | head->expiry_time = expiry; | ||
| 124 | head->last_refresh = get_seconds(); | ||
| 125 | if (!test_and_set_bit(CACHE_VALID, &head->flags)) | ||
| 126 | cache_revisit_request(head); | ||
| 127 | if (test_and_clear_bit(CACHE_PENDING, &head->flags)) | ||
| 128 | queue_loose(detail, head); | ||
| 129 | } | ||
| 130 | |||
| 131 | /* | 241 | /* |
| 132 | * caches need to be periodically cleaned. | 242 | * caches need to be periodically cleaned. |
| 133 | * For this we maintain a list of cache_detail and | 243 | * For this we maintain a list of cache_detail and |
| @@ -321,7 +431,7 @@ static int cache_clean(void) | |||
| 321 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) | 431 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) |
| 322 | queue_loose(current_detail, ch); | 432 | queue_loose(current_detail, ch); |
| 323 | 433 | ||
| 324 | if (atomic_read(&ch->refcnt) == 1) | 434 | if (atomic_read(&ch->ref.refcount) == 1) |
| 325 | break; | 435 | break; |
| 326 | } | 436 | } |
| 327 | if (ch) { | 437 | if (ch) { |
| @@ -336,7 +446,7 @@ static int cache_clean(void) | |||
| 336 | current_index ++; | 446 | current_index ++; |
| 337 | spin_unlock(&cache_list_lock); | 447 | spin_unlock(&cache_list_lock); |
| 338 | if (ch) | 448 | if (ch) |
| 339 | d->cache_put(ch, d); | 449 | cache_put(ch, d); |
| 340 | } else | 450 | } else |
| 341 | spin_unlock(&cache_list_lock); | 451 | spin_unlock(&cache_list_lock); |
| 342 | 452 | ||
| @@ -452,7 +562,7 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item) | |||
| 452 | /* there was one too many */ | 562 | /* there was one too many */ |
| 453 | dreq->revisit(dreq, 1); | 563 | dreq->revisit(dreq, 1); |
| 454 | } | 564 | } |
| 455 | if (test_bit(CACHE_VALID, &item->flags)) { | 565 | if (!test_bit(CACHE_PENDING, &item->flags)) { |
| 456 | /* must have just been validated... */ | 566 | /* must have just been validated... */ |
| 457 | cache_revisit_request(item); | 567 | cache_revisit_request(item); |
| 458 | } | 568 | } |
| @@ -532,7 +642,7 @@ void cache_clean_deferred(void *owner) | |||
| 532 | */ | 642 | */ |
| 533 | 643 | ||
| 534 | static DEFINE_SPINLOCK(queue_lock); | 644 | static DEFINE_SPINLOCK(queue_lock); |
| 535 | static DECLARE_MUTEX(queue_io_sem); | 645 | static DEFINE_MUTEX(queue_io_mutex); |
| 536 | 646 | ||
| 537 | struct cache_queue { | 647 | struct cache_queue { |
| 538 | struct list_head list; | 648 | struct list_head list; |
| @@ -561,7 +671,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
| 561 | if (count == 0) | 671 | if (count == 0) |
| 562 | return 0; | 672 | return 0; |
| 563 | 673 | ||
| 564 | down(&queue_io_sem); /* protect against multiple concurrent | 674 | mutex_lock(&queue_io_mutex); /* protect against multiple concurrent |
| 565 | * readers on this file */ | 675 | * readers on this file */ |
| 566 | again: | 676 | again: |
| 567 | spin_lock(&queue_lock); | 677 | spin_lock(&queue_lock); |
| @@ -574,7 +684,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
| 574 | } | 684 | } |
| 575 | if (rp->q.list.next == &cd->queue) { | 685 | if (rp->q.list.next == &cd->queue) { |
| 576 | spin_unlock(&queue_lock); | 686 | spin_unlock(&queue_lock); |
| 577 | up(&queue_io_sem); | 687 | mutex_unlock(&queue_io_mutex); |
| 578 | BUG_ON(rp->offset); | 688 | BUG_ON(rp->offset); |
| 579 | return 0; | 689 | return 0; |
| 580 | } | 690 | } |
| @@ -613,7 +723,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
| 613 | !test_bit(CACHE_PENDING, &rq->item->flags)) { | 723 | !test_bit(CACHE_PENDING, &rq->item->flags)) { |
| 614 | list_del(&rq->q.list); | 724 | list_del(&rq->q.list); |
| 615 | spin_unlock(&queue_lock); | 725 | spin_unlock(&queue_lock); |
| 616 | cd->cache_put(rq->item, cd); | 726 | cache_put(rq->item, cd); |
| 617 | kfree(rq->buf); | 727 | kfree(rq->buf); |
| 618 | kfree(rq); | 728 | kfree(rq); |
| 619 | } else | 729 | } else |
| @@ -621,11 +731,11 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
| 621 | } | 731 | } |
| 622 | if (err == -EAGAIN) | 732 | if (err == -EAGAIN) |
| 623 | goto again; | 733 | goto again; |
| 624 | up(&queue_io_sem); | 734 | mutex_unlock(&queue_io_mutex); |
| 625 | return err ? err : count; | 735 | return err ? err : count; |
| 626 | } | 736 | } |
| 627 | 737 | ||
| 628 | static char write_buf[8192]; /* protected by queue_io_sem */ | 738 | static char write_buf[8192]; /* protected by queue_io_mutex */ |
| 629 | 739 | ||
| 630 | static ssize_t | 740 | static ssize_t |
| 631 | cache_write(struct file *filp, const char __user *buf, size_t count, | 741 | cache_write(struct file *filp, const char __user *buf, size_t count, |
| @@ -639,10 +749,10 @@ cache_write(struct file *filp, const char __user *buf, size_t count, | |||
| 639 | if (count >= sizeof(write_buf)) | 749 | if (count >= sizeof(write_buf)) |
| 640 | return -EINVAL; | 750 | return -EINVAL; |
| 641 | 751 | ||
| 642 | down(&queue_io_sem); | 752 | mutex_lock(&queue_io_mutex); |
| 643 | 753 | ||
| 644 | if (copy_from_user(write_buf, buf, count)) { | 754 | if (copy_from_user(write_buf, buf, count)) { |
| 645 | up(&queue_io_sem); | 755 | mutex_unlock(&queue_io_mutex); |
| 646 | return -EFAULT; | 756 | return -EFAULT; |
| 647 | } | 757 | } |
| 648 | write_buf[count] = '\0'; | 758 | write_buf[count] = '\0'; |
| @@ -651,7 +761,7 @@ cache_write(struct file *filp, const char __user *buf, size_t count, | |||
| 651 | else | 761 | else |
| 652 | err = -EINVAL; | 762 | err = -EINVAL; |
| 653 | 763 | ||
| 654 | up(&queue_io_sem); | 764 | mutex_unlock(&queue_io_mutex); |
| 655 | return err ? err : count; | 765 | return err ? err : count; |
| 656 | } | 766 | } |
| 657 | 767 | ||
| @@ -793,10 +903,10 @@ static void queue_loose(struct cache_detail *detail, struct cache_head *ch) | |||
| 793 | if (cr->item != ch) | 903 | if (cr->item != ch) |
| 794 | continue; | 904 | continue; |
| 795 | if (cr->readers != 0) | 905 | if (cr->readers != 0) |
| 796 | break; | 906 | continue; |
| 797 | list_del(&cr->q.list); | 907 | list_del(&cr->q.list); |
| 798 | spin_unlock(&queue_lock); | 908 | spin_unlock(&queue_lock); |
| 799 | detail->cache_put(cr->item, detail); | 909 | cache_put(cr->item, detail); |
| 800 | kfree(cr->buf); | 910 | kfree(cr->buf); |
| 801 | kfree(cr); | 911 | kfree(cr); |
| 802 | return; | 912 | return; |
| @@ -1081,8 +1191,8 @@ static int c_show(struct seq_file *m, void *p) | |||
| 1081 | return cd->cache_show(m, cd, NULL); | 1191 | return cd->cache_show(m, cd, NULL); |
| 1082 | 1192 | ||
| 1083 | ifdebug(CACHE) | 1193 | ifdebug(CACHE) |
| 1084 | seq_printf(m, "# expiry=%ld refcnt=%d\n", | 1194 | seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n", |
| 1085 | cp->expiry_time, atomic_read(&cp->refcnt)); | 1195 | cp->expiry_time, atomic_read(&cp->ref.refcount), cp->flags); |
| 1086 | cache_get(cp); | 1196 | cache_get(cp); |
| 1087 | if (cache_check(cd, cp, NULL)) | 1197 | if (cache_check(cd, cp, NULL)) |
| 1088 | /* cache_check does a cache_put on failure */ | 1198 | /* cache_check does a cache_put on failure */ |
