Commit e092bdcd939416ef911090890096fe07d0281a5e
1 parent
fc432dd907
Exists in
master
and in
7 other branches
SUNRPC: cleanup rpc credential cache garbage collection
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 3 changed files with 74 additions and 49 deletions Side-by-side Diff
include/linux/sunrpc/auth.h
net/sunrpc/auth.c
... | ... | @@ -25,6 +25,8 @@ |
25 | 25 | NULL, /* others can be loadable modules */ |
26 | 26 | }; |
27 | 27 | |
28 | +static LIST_HEAD(cred_unused); | |
29 | + | |
28 | 30 | static u32 |
29 | 31 | pseudoflavor_to_flavor(u32 flavor) { |
30 | 32 | if (flavor >= RPC_AUTH_MAXFLAVOR) |
31 | 33 | |
... | ... | @@ -134,13 +136,13 @@ |
134 | 136 | * Destroy a list of credentials |
135 | 137 | */ |
136 | 138 | static inline |
137 | -void rpcauth_destroy_credlist(struct hlist_head *head) | |
139 | +void rpcauth_destroy_credlist(struct list_head *head) | |
138 | 140 | { |
139 | 141 | struct rpc_cred *cred; |
140 | 142 | |
141 | - while (!hlist_empty(head)) { | |
142 | - cred = hlist_entry(head->first, struct rpc_cred, cr_hash); | |
143 | - hlist_del_init(&cred->cr_hash); | |
143 | + while (!list_empty(head)) { | |
144 | + cred = list_entry(head->next, struct rpc_cred, cr_lru); | |
145 | + list_del_init(&cred->cr_lru); | |
144 | 146 | put_rpccred(cred); |
145 | 147 | } |
146 | 148 | } |
147 | 149 | |
... | ... | @@ -152,17 +154,20 @@ |
152 | 154 | void |
153 | 155 | rpcauth_clear_credcache(struct rpc_cred_cache *cache) |
154 | 156 | { |
155 | - HLIST_HEAD(free); | |
156 | - struct hlist_node *pos, *next; | |
157 | + LIST_HEAD(free); | |
158 | + struct hlist_head *head; | |
157 | 159 | struct rpc_cred *cred; |
158 | 160 | int i; |
159 | 161 | |
160 | 162 | spin_lock(&rpc_credcache_lock); |
161 | 163 | for (i = 0; i < RPC_CREDCACHE_NR; i++) { |
162 | - hlist_for_each_safe(pos, next, &cache->hashtable[i]) { | |
163 | - cred = hlist_entry(pos, struct rpc_cred, cr_hash); | |
164 | - __hlist_del(&cred->cr_hash); | |
165 | - hlist_add_head(&cred->cr_hash, &free); | |
164 | + head = &cache->hashtable[i]; | |
165 | + while (!hlist_empty(head)) { | |
166 | + cred = hlist_entry(head->first, struct rpc_cred, cr_hash); | |
167 | + get_rpccred(cred); | |
168 | + list_move_tail(&cred->cr_lru, &free); | |
169 | + smp_wmb(); | |
170 | + hlist_del_init(&cred->cr_hash); | |
166 | 171 | } |
167 | 172 | } |
168 | 173 | spin_unlock(&rpc_credcache_lock); |
169 | 174 | |
170 | 175 | |
171 | 176 | |
172 | 177 | |
173 | 178 | |
174 | 179 | |
... | ... | @@ -184,38 +189,39 @@ |
184 | 189 | } |
185 | 190 | } |
186 | 191 | |
192 | +/* | |
193 | + * Remove stale credentials. Avoid sleeping inside the loop. | |
194 | + */ | |
187 | 195 | static void |
188 | -rpcauth_prune_expired(struct rpc_auth *auth, struct rpc_cred *cred, struct hlist_head *free) | |
196 | +rpcauth_prune_expired(struct list_head *free) | |
189 | 197 | { |
190 | - if (atomic_read(&cred->cr_count) != 1) | |
191 | - return; | |
192 | - if (time_after(jiffies, cred->cr_expire + auth->au_credcache->expire)) | |
193 | - clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | |
194 | - if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) { | |
195 | - __hlist_del(&cred->cr_hash); | |
196 | - hlist_add_head(&cred->cr_hash, free); | |
198 | + struct rpc_cred *cred; | |
199 | + | |
200 | + while (!list_empty(&cred_unused)) { | |
201 | + cred = list_entry(cred_unused.next, struct rpc_cred, cr_lru); | |
202 | + if (time_after(jiffies, cred->cr_expire + | |
203 | + cred->cr_auth->au_credcache->expire)) | |
204 | + break; | |
205 | + list_del_init(&cred->cr_lru); | |
206 | + if (atomic_read(&cred->cr_count) != 0) | |
207 | + continue; | |
208 | + get_rpccred(cred); | |
209 | + list_add_tail(&cred->cr_lru, free); | |
210 | + smp_wmb(); | |
211 | + hlist_del_init(&cred->cr_hash); | |
197 | 212 | } |
198 | 213 | } |
199 | 214 | |
200 | 215 | /* |
201 | - * Remove stale credentials. Avoid sleeping inside the loop. | |
216 | + * Run garbage collector. | |
202 | 217 | */ |
203 | 218 | static void |
204 | -rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free) | |
219 | +rpcauth_gc_credcache(struct rpc_cred_cache *cache, struct list_head *free) | |
205 | 220 | { |
206 | - struct rpc_cred_cache *cache = auth->au_credcache; | |
207 | - struct hlist_node *pos, *next; | |
208 | - struct rpc_cred *cred; | |
209 | - int i; | |
210 | - | |
211 | - dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth); | |
212 | - for (i = 0; i < RPC_CREDCACHE_NR; i++) { | |
213 | - hlist_for_each_safe(pos, next, &cache->hashtable[i]) { | |
214 | - cred = hlist_entry(pos, struct rpc_cred, cr_hash); | |
215 | - rpcauth_prune_expired(auth, cred, free); | |
216 | - } | |
217 | - } | |
221 | + if (time_before(jiffies, cache->nextgc)) | |
222 | + return; | |
218 | 223 | cache->nextgc = jiffies + cache->expire; |
224 | + rpcauth_prune_expired(free); | |
219 | 225 | } |
220 | 226 | |
221 | 227 | /* |
222 | 228 | |
223 | 229 | |
224 | 230 | |
225 | 231 | |
226 | 232 | |
227 | 233 | |
... | ... | @@ -225,39 +231,35 @@ |
225 | 231 | rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, |
226 | 232 | int flags) |
227 | 233 | { |
234 | + LIST_HEAD(free); | |
228 | 235 | struct rpc_cred_cache *cache = auth->au_credcache; |
229 | - HLIST_HEAD(free); | |
230 | - struct hlist_node *pos, *next; | |
236 | + struct hlist_node *pos; | |
231 | 237 | struct rpc_cred *new = NULL, |
232 | - *cred = NULL; | |
238 | + *cred = NULL, | |
239 | + *entry; | |
233 | 240 | int nr = 0; |
234 | 241 | |
235 | 242 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) |
236 | 243 | nr = acred->uid & RPC_CREDCACHE_MASK; |
237 | 244 | retry: |
238 | 245 | spin_lock(&rpc_credcache_lock); |
239 | - if (time_before(cache->nextgc, jiffies)) | |
240 | - rpcauth_gc_credcache(auth, &free); | |
241 | - hlist_for_each_safe(pos, next, &cache->hashtable[nr]) { | |
242 | - struct rpc_cred *entry; | |
243 | - entry = hlist_entry(pos, struct rpc_cred, cr_hash); | |
244 | - if (entry->cr_ops->crmatch(acred, entry, flags)) { | |
245 | - hlist_del(&entry->cr_hash); | |
246 | - cred = entry; | |
247 | - break; | |
248 | - } | |
249 | - rpcauth_prune_expired(auth, entry, &free); | |
246 | + hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) { | |
247 | + if (!entry->cr_ops->crmatch(acred, entry, flags)) | |
248 | + continue; | |
249 | + cred = get_rpccred(entry); | |
250 | + hlist_del(&entry->cr_hash); | |
251 | + break; | |
250 | 252 | } |
251 | 253 | if (new) { |
252 | 254 | if (cred) |
253 | - hlist_add_head(&new->cr_hash, &free); | |
255 | + list_add_tail(&new->cr_lru, &free); | |
254 | 256 | else |
255 | 257 | cred = new; |
256 | 258 | } |
257 | 259 | if (cred) { |
258 | 260 | hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]); |
259 | - get_rpccred(cred); | |
260 | 261 | } |
262 | + rpcauth_gc_credcache(cache, &free); | |
261 | 263 | spin_unlock(&rpc_credcache_lock); |
262 | 264 | |
263 | 265 | rpcauth_destroy_credlist(&free); |
... | ... | @@ -303,6 +305,7 @@ |
303 | 305 | struct rpc_auth *auth, const struct rpc_credops *ops) |
304 | 306 | { |
305 | 307 | INIT_HLIST_NODE(&cred->cr_hash); |
308 | + INIT_LIST_HEAD(&cred->cr_lru); | |
306 | 309 | atomic_set(&cred->cr_count, 1); |
307 | 310 | cred->cr_auth = auth; |
308 | 311 | cred->cr_ops = ops; |
309 | 312 | |
... | ... | @@ -353,9 +356,29 @@ |
353 | 356 | void |
354 | 357 | put_rpccred(struct rpc_cred *cred) |
355 | 358 | { |
356 | - cred->cr_expire = jiffies; | |
359 | + /* Fast path for unhashed credentials */ | |
360 | + if (!hlist_unhashed(&cred->cr_hash)) | |
361 | + goto need_lock; | |
362 | + | |
357 | 363 | if (!atomic_dec_and_test(&cred->cr_count)) |
358 | 364 | return; |
365 | + goto out_destroy; | |
366 | + | |
367 | +need_lock: | |
368 | + if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock)) | |
369 | + return; | |
370 | + if (!list_empty(&cred->cr_lru)) | |
371 | + list_del_init(&cred->cr_lru); | |
372 | + if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) | |
373 | + hlist_del(&cred->cr_hash); | |
374 | + else if (!hlist_unhashed(&cred->cr_hash)) { | |
375 | + cred->cr_expire = jiffies; | |
376 | + list_add_tail(&cred->cr_lru, &cred_unused); | |
377 | + spin_unlock(&rpc_credcache_lock); | |
378 | + return; | |
379 | + } | |
380 | + spin_unlock(&rpc_credcache_lock); | |
381 | +out_destroy: | |
359 | 382 | cred->cr_ops->crdestroy(cred); |
360 | 383 | } |
361 | 384 |