diff options
Diffstat (limited to 'net/sunrpc')
| -rw-r--r-- | net/sunrpc/auth.c | 91 | ||||
| -rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 22 | ||||
| -rw-r--r-- | net/sunrpc/auth_unix.c | 18 |
3 files changed, 88 insertions, 43 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 | ||
| 113 | static DEFINE_SPINLOCK(rpc_credcache_lock); | 113 | static DEFINE_SPINLOCK(rpc_credcache_lock); |
| 114 | 114 | ||
| 115 | static void | ||
| 116 | rpcauth_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) | |||
| 218 | static void | 224 | static void |
| 219 | rpcauth_gc_credcache(struct rpc_cred_cache *cache, struct list_head *free) | 225 | rpcauth_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; |
| 244 | retry: | 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); | ||
| 294 | found: | ||
| 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; | 305 | out: |
| 306 | return cred; | ||
| 283 | } | 307 | } |
| 284 | 308 | ||
| 285 | struct rpc_cred * | 309 | struct rpc_cred * |
| @@ -357,21 +381,20 @@ void | |||
| 357 | put_rpccred(struct rpc_cred *cred) | 381 | put_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 | |||
| 367 | need_lock: | 390 | need_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 | ||
| 696 | static void | 696 | static void |
| 697 | gss_destroy_cred(struct rpc_cred *rc) | 697 | gss_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"); | 705 | static void |
| 706 | gss_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) | 712 | static void |
| 704 | gss_put_ctx(cred->gc_ctx); | 713 | gss_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 | ||
| 95 | static void | 95 | static void |
| 96 | unx_destroy_cred(struct rpc_cred *rcred) | 96 | unx_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 | |||
| 102 | static void | ||
| 103 | unx_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); | 109 | static void |
| 110 | unx_destroy_cred(struct rpc_cred *cred) | ||
| 111 | { | ||
| 112 | call_rcu(&cred->cr_rcu, unx_free_cred_callback); | ||
| 101 | } | 113 | } |
| 102 | 114 | ||
| 103 | /* | 115 | /* |
