diff options
Diffstat (limited to 'net/sunrpc/cache.c')
-rw-r--r-- | net/sunrpc/cache.c | 163 |
1 files changed, 136 insertions, 27 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 0acccfeeb284..3ac4193a78ed 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
@@ -37,16 +37,138 @@ | |||
37 | 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); |
38 | static void cache_revisit_request(struct cache_head *item); | 38 | static void cache_revisit_request(struct cache_head *item); |
39 | 39 | ||
40 | void cache_init(struct cache_head *h) | 40 | static void cache_init(struct cache_head *h) |
41 | { | 41 | { |
42 | time_t now = get_seconds(); | 42 | time_t now = get_seconds(); |
43 | h->next = NULL; | 43 | h->next = NULL; |
44 | h->flags = 0; | 44 | h->flags = 0; |
45 | atomic_set(&h->refcnt, 1); | 45 | kref_init(&h->ref); |
46 | h->expiry_time = now + CACHE_NEW_EXPIRY; | 46 | h->expiry_time = now + CACHE_NEW_EXPIRY; |
47 | h->last_refresh = now; | 47 | h->last_refresh = now; |
48 | } | 48 | } |
49 | 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); | ||
50 | 172 | ||
51 | 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); |
52 | /* | 174 | /* |
@@ -94,7 +216,8 @@ int cache_check(struct cache_detail *detail, | |||
94 | clear_bit(CACHE_PENDING, &h->flags); | 216 | clear_bit(CACHE_PENDING, &h->flags); |
95 | if (rv == -EAGAIN) { | 217 | if (rv == -EAGAIN) { |
96 | set_bit(CACHE_NEGATIVE, &h->flags); | 218 | set_bit(CACHE_NEGATIVE, &h->flags); |
97 | 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)); | ||
98 | rv = -ENOENT; | 221 | rv = -ENOENT; |
99 | } | 222 | } |
100 | break; | 223 | break; |
@@ -110,25 +233,11 @@ int cache_check(struct cache_detail *detail, | |||
110 | if (rv == -EAGAIN) | 233 | if (rv == -EAGAIN) |
111 | cache_defer_req(rqstp, h); | 234 | cache_defer_req(rqstp, h); |
112 | 235 | ||
113 | if (rv && h) | 236 | if (rv) |
114 | detail->cache_put(h, detail); | 237 | cache_put(h, detail); |
115 | return rv; | 238 | return rv; |
116 | } | 239 | } |
117 | 240 | ||
118 | static void queue_loose(struct cache_detail *detail, struct cache_head *ch); | ||
119 | |||
120 | void cache_fresh(struct cache_detail *detail, | ||
121 | struct cache_head *head, time_t expiry) | ||
122 | { | ||
123 | |||
124 | head->expiry_time = expiry; | ||
125 | head->last_refresh = get_seconds(); | ||
126 | if (!test_and_set_bit(CACHE_VALID, &head->flags)) | ||
127 | cache_revisit_request(head); | ||
128 | if (test_and_clear_bit(CACHE_PENDING, &head->flags)) | ||
129 | queue_loose(detail, head); | ||
130 | } | ||
131 | |||
132 | /* | 241 | /* |
133 | * caches need to be periodically cleaned. | 242 | * caches need to be periodically cleaned. |
134 | * For this we maintain a list of cache_detail and | 243 | * For this we maintain a list of cache_detail and |
@@ -322,7 +431,7 @@ static int cache_clean(void) | |||
322 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) | 431 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) |
323 | queue_loose(current_detail, ch); | 432 | queue_loose(current_detail, ch); |
324 | 433 | ||
325 | if (atomic_read(&ch->refcnt) == 1) | 434 | if (atomic_read(&ch->ref.refcount) == 1) |
326 | break; | 435 | break; |
327 | } | 436 | } |
328 | if (ch) { | 437 | if (ch) { |
@@ -337,7 +446,7 @@ static int cache_clean(void) | |||
337 | current_index ++; | 446 | current_index ++; |
338 | spin_unlock(&cache_list_lock); | 447 | spin_unlock(&cache_list_lock); |
339 | if (ch) | 448 | if (ch) |
340 | d->cache_put(ch, d); | 449 | cache_put(ch, d); |
341 | } else | 450 | } else |
342 | spin_unlock(&cache_list_lock); | 451 | spin_unlock(&cache_list_lock); |
343 | 452 | ||
@@ -453,7 +562,7 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item) | |||
453 | /* there was one too many */ | 562 | /* there was one too many */ |
454 | dreq->revisit(dreq, 1); | 563 | dreq->revisit(dreq, 1); |
455 | } | 564 | } |
456 | if (test_bit(CACHE_VALID, &item->flags)) { | 565 | if (!test_bit(CACHE_PENDING, &item->flags)) { |
457 | /* must have just been validated... */ | 566 | /* must have just been validated... */ |
458 | cache_revisit_request(item); | 567 | cache_revisit_request(item); |
459 | } | 568 | } |
@@ -614,7 +723,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
614 | !test_bit(CACHE_PENDING, &rq->item->flags)) { | 723 | !test_bit(CACHE_PENDING, &rq->item->flags)) { |
615 | list_del(&rq->q.list); | 724 | list_del(&rq->q.list); |
616 | spin_unlock(&queue_lock); | 725 | spin_unlock(&queue_lock); |
617 | cd->cache_put(rq->item, cd); | 726 | cache_put(rq->item, cd); |
618 | kfree(rq->buf); | 727 | kfree(rq->buf); |
619 | kfree(rq); | 728 | kfree(rq); |
620 | } else | 729 | } else |
@@ -794,10 +903,10 @@ static void queue_loose(struct cache_detail *detail, struct cache_head *ch) | |||
794 | if (cr->item != ch) | 903 | if (cr->item != ch) |
795 | continue; | 904 | continue; |
796 | if (cr->readers != 0) | 905 | if (cr->readers != 0) |
797 | break; | 906 | continue; |
798 | list_del(&cr->q.list); | 907 | list_del(&cr->q.list); |
799 | spin_unlock(&queue_lock); | 908 | spin_unlock(&queue_lock); |
800 | detail->cache_put(cr->item, detail); | 909 | cache_put(cr->item, detail); |
801 | kfree(cr->buf); | 910 | kfree(cr->buf); |
802 | kfree(cr); | 911 | kfree(cr); |
803 | return; | 912 | return; |
@@ -1082,8 +1191,8 @@ static int c_show(struct seq_file *m, void *p) | |||
1082 | return cd->cache_show(m, cd, NULL); | 1191 | return cd->cache_show(m, cd, NULL); |
1083 | 1192 | ||
1084 | ifdebug(CACHE) | 1193 | ifdebug(CACHE) |
1085 | seq_printf(m, "# expiry=%ld refcnt=%d\n", | 1194 | seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n", |
1086 | cp->expiry_time, atomic_read(&cp->refcnt)); | 1195 | cp->expiry_time, atomic_read(&cp->ref.refcount), cp->flags); |
1087 | cache_get(cp); | 1196 | cache_get(cp); |
1088 | if (cache_check(cd, cp, NULL)) | 1197 | if (cache_check(cd, cp, NULL)) |
1089 | /* cache_check does a cache_put on failure */ | 1198 | /* cache_check does a cache_put on failure */ |