aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/auth.c')
-rw-r--r--net/sunrpc/auth.c91
1 files changed, 57 insertions, 34 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 00f9649b0901..ad7bde2c437e 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -112,6 +112,14 @@ rpcauth_release(struct rpc_auth *auth)
112 112
113static DEFINE_SPINLOCK(rpc_credcache_lock); 113static DEFINE_SPINLOCK(rpc_credcache_lock);
114 114
115static void
116rpcauth_unhash_cred_locked(struct rpc_cred *cred)
117{
118 hlist_del_rcu(&cred->cr_hash);
119 smp_mb__before_clear_bit();
120 clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
121}
122
115/* 123/*
116 * Initialize RPC credential cache 124 * Initialize RPC credential cache
117 */ 125 */
@@ -166,8 +174,7 @@ rpcauth_clear_credcache(struct rpc_cred_cache *cache)
166 cred = hlist_entry(head->first, struct rpc_cred, cr_hash); 174 cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
167 get_rpccred(cred); 175 get_rpccred(cred);
168 list_move_tail(&cred->cr_lru, &free); 176 list_move_tail(&cred->cr_lru, &free);
169 smp_wmb(); 177 rpcauth_unhash_cred_locked(cred);
170 hlist_del_init(&cred->cr_hash);
171 } 178 }
172 } 179 }
173 spin_unlock(&rpc_credcache_lock); 180 spin_unlock(&rpc_credcache_lock);
@@ -207,8 +214,7 @@ rpcauth_prune_expired(struct list_head *free)
207 continue; 214 continue;
208 get_rpccred(cred); 215 get_rpccred(cred);
209 list_add_tail(&cred->cr_lru, free); 216 list_add_tail(&cred->cr_lru, free);
210 smp_wmb(); 217 rpcauth_unhash_cred_locked(cred);
211 hlist_del_init(&cred->cr_hash);
212 } 218 }
213} 219}
214 220
@@ -218,10 +224,12 @@ rpcauth_prune_expired(struct list_head *free)
218static void 224static void
219rpcauth_gc_credcache(struct rpc_cred_cache *cache, struct list_head *free) 225rpcauth_gc_credcache(struct rpc_cred_cache *cache, struct list_head *free)
220{ 226{
221 if (time_before(jiffies, cache->nextgc)) 227 if (list_empty(&cred_unused) || time_before(jiffies, cache->nextgc))
222 return; 228 return;
229 spin_lock(&rpc_credcache_lock);
223 cache->nextgc = jiffies + cache->expire; 230 cache->nextgc = jiffies + cache->expire;
224 rpcauth_prune_expired(free); 231 rpcauth_prune_expired(free);
232 spin_unlock(&rpc_credcache_lock);
225} 233}
226 234
227/* 235/*
@@ -234,42 +242,57 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
234 LIST_HEAD(free); 242 LIST_HEAD(free);
235 struct rpc_cred_cache *cache = auth->au_credcache; 243 struct rpc_cred_cache *cache = auth->au_credcache;
236 struct hlist_node *pos; 244 struct hlist_node *pos;
237 struct rpc_cred *new = NULL, 245 struct rpc_cred *cred = NULL,
238 *cred = NULL, 246 *entry, *new;
239 *entry;
240 int nr = 0; 247 int nr = 0;
241 248
242 if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) 249 if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS))
243 nr = acred->uid & RPC_CREDCACHE_MASK; 250 nr = acred->uid & RPC_CREDCACHE_MASK;
244retry: 251
245 spin_lock(&rpc_credcache_lock); 252 rcu_read_lock();
246 hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) { 253 hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) {
247 if (!entry->cr_ops->crmatch(acred, entry, flags)) 254 if (!entry->cr_ops->crmatch(acred, entry, flags))
248 continue; 255 continue;
256 spin_lock(&rpc_credcache_lock);
257 if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) {
258 spin_unlock(&rpc_credcache_lock);
259 continue;
260 }
249 cred = get_rpccred(entry); 261 cred = get_rpccred(entry);
250 hlist_del(&entry->cr_hash); 262 spin_unlock(&rpc_credcache_lock);
251 break; 263 break;
252 } 264 }
253 if (new) { 265 rcu_read_unlock();
254 if (cred) 266
255 list_add_tail(&new->cr_lru, &free); 267 if (cred != NULL) {
256 else 268 rpcauth_gc_credcache(cache, &free);
257 cred = new; 269 goto found;
258 }
259 if (cred) {
260 hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]);
261 } 270 }
262 rpcauth_gc_credcache(cache, &free);
263 spin_unlock(&rpc_credcache_lock);
264 271
265 rpcauth_destroy_credlist(&free); 272 new = auth->au_ops->crcreate(auth, acred, flags);
273 if (IS_ERR(new)) {
274 cred = new;
275 goto out;
276 }
266 277
267 if (!cred) { 278 spin_lock(&rpc_credcache_lock);
268 new = auth->au_ops->crcreate(auth, acred, flags); 279 hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) {
269 if (!IS_ERR(new)) 280 if (!entry->cr_ops->crmatch(acred, entry, flags))
270 goto retry; 281 continue;
282 cred = get_rpccred(entry);
283 break;
284 }
285 if (cred == NULL) {
271 cred = new; 286 cred = new;
272 } else if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) 287 set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
288 hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]);
289 } else
290 list_add_tail(&new->cr_lru, &free);
291 rpcauth_prune_expired(&free);
292 cache->nextgc = jiffies + cache->expire;
293 spin_unlock(&rpc_credcache_lock);
294found:
295 if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)
273 && cred->cr_ops->cr_init != NULL 296 && cred->cr_ops->cr_init != NULL
274 && !(flags & RPCAUTH_LOOKUP_NEW)) { 297 && !(flags & RPCAUTH_LOOKUP_NEW)) {
275 int res = cred->cr_ops->cr_init(auth, cred); 298 int res = cred->cr_ops->cr_init(auth, cred);
@@ -278,8 +301,9 @@ retry:
278 cred = ERR_PTR(res); 301 cred = ERR_PTR(res);
279 } 302 }
280 } 303 }
281 304 rpcauth_destroy_credlist(&free);
282 return (struct rpc_cred *) cred; 305out:
306 return cred;
283} 307}
284 308
285struct rpc_cred * 309struct rpc_cred *
@@ -357,21 +381,20 @@ void
357put_rpccred(struct rpc_cred *cred) 381put_rpccred(struct rpc_cred *cred)
358{ 382{
359 /* Fast path for unhashed credentials */ 383 /* Fast path for unhashed credentials */
360 if (!hlist_unhashed(&cred->cr_hash)) 384 if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0)
361 goto need_lock; 385 goto need_lock;
362 386
363 if (!atomic_dec_and_test(&cred->cr_count)) 387 if (!atomic_dec_and_test(&cred->cr_count))
364 return; 388 return;
365 goto out_destroy; 389 goto out_destroy;
366
367need_lock: 390need_lock:
368 if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock)) 391 if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
369 return; 392 return;
370 if (!list_empty(&cred->cr_lru)) 393 if (!list_empty(&cred->cr_lru))
371 list_del_init(&cred->cr_lru); 394 list_del_init(&cred->cr_lru);
372 if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) 395 if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
373 hlist_del(&cred->cr_hash); 396 rpcauth_unhash_cred_locked(cred);
374 else if (!hlist_unhashed(&cred->cr_hash)) { 397 else if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) {
375 cred->cr_expire = jiffies; 398 cred->cr_expire = jiffies;
376 list_add_tail(&cred->cr_lru, &cred_unused); 399 list_add_tail(&cred->cr_lru, &cred_unused);
377 spin_unlock(&rpc_credcache_lock); 400 spin_unlock(&rpc_credcache_lock);