aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sunrpc/auth.h3
-rw-r--r--net/sunrpc/auth.c91
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c22
-rw-r--r--net/sunrpc/auth_unix.c18
4 files changed, 91 insertions, 43 deletions
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 4e78f0c5f014..5974e8a493c4 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -16,6 +16,7 @@
16#include <linux/sunrpc/xdr.h> 16#include <linux/sunrpc/xdr.h>
17 17
18#include <asm/atomic.h> 18#include <asm/atomic.h>
19#include <linux/rcupdate.h>
19 20
20/* size of the nodename buffer */ 21/* size of the nodename buffer */
21#define UNX_MAXNODENAME 32 22#define UNX_MAXNODENAME 32
@@ -35,6 +36,7 @@ struct rpc_credops;
35struct rpc_cred { 36struct rpc_cred {
36 struct hlist_node cr_hash; /* hash chain */ 37 struct hlist_node cr_hash; /* hash chain */
37 struct list_head cr_lru; /* lru garbage collection */ 38 struct list_head cr_lru; /* lru garbage collection */
39 struct rcu_head cr_rcu;
38 struct rpc_auth * cr_auth; 40 struct rpc_auth * cr_auth;
39 const struct rpc_credops *cr_ops; 41 const struct rpc_credops *cr_ops;
40#ifdef RPC_DEBUG 42#ifdef RPC_DEBUG
@@ -50,6 +52,7 @@ struct rpc_cred {
50}; 52};
51#define RPCAUTH_CRED_NEW 0 53#define RPCAUTH_CRED_NEW 0
52#define RPCAUTH_CRED_UPTODATE 1 54#define RPCAUTH_CRED_UPTODATE 1
55#define RPCAUTH_CRED_HASHED 2
53 56
54#define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 57#define RPCAUTH_CRED_MAGIC 0x0f4aa4f0
55 58
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);
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 55c47ae0a258..068fa6dfb64e 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -694,15 +694,25 @@ gss_destroy_ctx(struct gss_cl_ctx *ctx)
694} 694}
695 695
696static void 696static void
697gss_destroy_cred(struct rpc_cred *rc) 697gss_free_cred(struct gss_cred *gss_cred)
698{ 698{
699 struct gss_cred *cred = container_of(rc, struct gss_cred, gc_base); 699 dprintk("RPC: gss_free_cred %p\n", gss_cred);
700 if (gss_cred->gc_ctx)
701 gss_put_ctx(gss_cred->gc_ctx);
702 kfree(gss_cred);
703}
700 704
701 dprintk("RPC: gss_destroy_cred \n"); 705static void
706gss_free_cred_callback(struct rcu_head *head)
707{
708 struct gss_cred *gss_cred = container_of(head, struct gss_cred, gc_base.cr_rcu);
709 gss_free_cred(gss_cred);
710}
702 711
703 if (cred->gc_ctx) 712static void
704 gss_put_ctx(cred->gc_ctx); 713gss_destroy_cred(struct rpc_cred *cred)
705 kfree(cred); 714{
715 call_rcu(&cred->cr_rcu, gss_free_cred_callback);
706} 716}
707 717
708/* 718/*
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index 29d50ffa69d6..f7ff6ad3259e 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -93,11 +93,23 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
93} 93}
94 94
95static void 95static void
96unx_destroy_cred(struct rpc_cred *rcred) 96unx_free_cred(struct unx_cred *unx_cred)
97{ 97{
98 struct unx_cred *cred = container_of(rcred, struct unx_cred, uc_base); 98 dprintk("RPC: unx_free_cred %p\n", unx_cred);
99 kfree(unx_cred);
100}
101
102static void
103unx_free_cred_callback(struct rcu_head *head)
104{
105 struct unx_cred *unx_cred = container_of(head, struct unx_cred, uc_base.cr_rcu);
106 unx_free_cred(unx_cred);
107}
99 108
100 kfree(cred); 109static void
110unx_destroy_cred(struct rpc_cred *cred)
111{
112 call_rcu(&cred->cr_rcu, unx_free_cred_callback);
101} 113}
102 114
103/* 115/*