]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - net/sunrpc/auth.c
IPv6: fix race between cleanup and add/delete address
[linux-2.6.git] / net / sunrpc / auth.c
index a045a1253d49652b17076dc87fbbfd447bf63a6c..f394fc190a496f81125a467ec4723862da12c5f2 100644 (file)
@@ -123,16 +123,19 @@ rpcauth_unhash_cred_locked(struct rpc_cred *cred)
        clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
 }
 
-static void
+static int
 rpcauth_unhash_cred(struct rpc_cred *cred)
 {
        spinlock_t *cache_lock;
+       int ret;
 
        cache_lock = &cred->cr_auth->au_credcache->lock;
        spin_lock(cache_lock);
-       if (atomic_read(&cred->cr_count) == 0)
+       ret = atomic_read(&cred->cr_count) == 0;
+       if (ret)
                rpcauth_unhash_cred_locked(cred);
        spin_unlock(cache_lock);
+       return ret;
 }
 
 /*
@@ -234,7 +237,7 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
        list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) {
 
                /* Enforce a 60 second garbage collection moratorium */
-               if (time_in_range(cred->cr_expire, expired, jiffies) &&
+               if (time_in_range_open(cred->cr_expire, expired, jiffies) &&
                    test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0)
                        continue;
 
@@ -332,9 +335,9 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
                list_add_tail(&new->cr_lru, &free);
        spin_unlock(&cache->lock);
 found:
-       if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)
-                       && cred->cr_ops->cr_init != NULL
-                       && !(flags & RPCAUTH_LOOKUP_NEW)) {
+       if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
+           cred->cr_ops->cr_init != NULL &&
+           !(flags & RPCAUTH_LOOKUP_NEW)) {
                int res = cred->cr_ops->cr_init(auth, cred);
                if (res < 0) {
                        put_rpccred(cred);
@@ -350,16 +353,18 @@ EXPORT_SYMBOL_GPL(rpcauth_lookup_credcache);
 struct rpc_cred *
 rpcauth_lookupcred(struct rpc_auth *auth, int flags)
 {
-       struct auth_cred acred = {
-               .uid = current->fsuid,
-               .gid = current->fsgid,
-               .group_info = current->group_info,
-       };
+       struct auth_cred acred;
        struct rpc_cred *ret;
+       const struct cred *cred = current_cred();
 
        dprintk("RPC:       looking up %s cred\n",
                auth->au_ops->au_name);
-       get_group_info(acred.group_info);
+
+       memset(&acred, 0, sizeof(acred));
+       acred.uid = cred->fsuid;
+       acred.gid = cred->fsgid;
+       acred.group_info = get_group_info(((struct cred *)cred)->group_info);
+
        ret = auth->au_ops->lookup_cred(auth, &acred, flags);
        put_group_info(acred.group_info);
        return ret;
@@ -383,7 +388,7 @@ rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
 EXPORT_SYMBOL_GPL(rpcauth_init_cred);
 
 void
-rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred)
+rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags)
 {
        task->tk_msg.rpc_cred = get_rpccred(cred);
        dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid,
@@ -392,7 +397,7 @@ rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred)
 EXPORT_SYMBOL_GPL(rpcauth_generic_bind_cred);
 
 static void
-rpcauth_bind_root_cred(struct rpc_task *task)
+rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags)
 {
        struct rpc_auth *auth = task->tk_client->cl_auth;
        struct auth_cred acred = {
@@ -403,7 +408,7 @@ rpcauth_bind_root_cred(struct rpc_task *task)
 
        dprintk("RPC: %5u looking up %s cred\n",
                task->tk_pid, task->tk_client->cl_auth->au_ops->au_name);
-       ret = auth->au_ops->lookup_cred(auth, &acred, 0);
+       ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags);
        if (!IS_ERR(ret))
                task->tk_msg.rpc_cred = ret;
        else
@@ -411,14 +416,14 @@ rpcauth_bind_root_cred(struct rpc_task *task)
 }
 
 static void
-rpcauth_bind_new_cred(struct rpc_task *task)
+rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags)
 {
        struct rpc_auth *auth = task->tk_client->cl_auth;
        struct rpc_cred *ret;
 
        dprintk("RPC: %5u looking up %s cred\n",
                task->tk_pid, auth->au_ops->au_name);
-       ret = rpcauth_lookupcred(auth, 0);
+       ret = rpcauth_lookupcred(auth, lookupflags);
        if (!IS_ERR(ret))
                task->tk_msg.rpc_cred = ret;
        else
@@ -428,43 +433,51 @@ rpcauth_bind_new_cred(struct rpc_task *task)
 void
 rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags)
 {
+       int lookupflags = 0;
+
+       if (flags & RPC_TASK_ASYNC)
+               lookupflags |= RPCAUTH_LOOKUP_NEW;
        if (cred != NULL)
-               cred->cr_ops->crbind(task, cred);
+               cred->cr_ops->crbind(task, cred, lookupflags);
        else if (flags & RPC_TASK_ROOTCREDS)
-               rpcauth_bind_root_cred(task);
+               rpcauth_bind_root_cred(task, lookupflags);
        else
-               rpcauth_bind_new_cred(task);
+               rpcauth_bind_new_cred(task, lookupflags);
 }
 
 void
 put_rpccred(struct rpc_cred *cred)
 {
        /* Fast path for unhashed credentials */
-       if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0)
-               goto need_lock;
-
-       if (!atomic_dec_and_test(&cred->cr_count))
+       if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) == 0) {
+               if (atomic_dec_and_test(&cred->cr_count))
+                       cred->cr_ops->crdestroy(cred);
                return;
-       goto out_destroy;
-need_lock:
+       }
+
        if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
                return;
        if (!list_empty(&cred->cr_lru)) {
                number_cred_unused--;
                list_del_init(&cred->cr_lru);
        }
-       if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
-               rpcauth_unhash_cred(cred);
-       else if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) {
-               cred->cr_expire = jiffies;
-               list_add_tail(&cred->cr_lru, &cred_unused);
-               number_cred_unused++;
-               spin_unlock(&rpc_credcache_lock);
-               return;
+       if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) {
+               if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) {
+                       cred->cr_expire = jiffies;
+                       list_add_tail(&cred->cr_lru, &cred_unused);
+                       number_cred_unused++;
+                       goto out_nodestroy;
+               }
+               if (!rpcauth_unhash_cred(cred)) {
+                       /* We were hashed and someone looked us up... */
+                       goto out_nodestroy;
+               }
        }
        spin_unlock(&rpc_credcache_lock);
-out_destroy:
        cred->cr_ops->crdestroy(cred);
+       return;
+out_nodestroy:
+       spin_unlock(&rpc_credcache_lock);
 }
 EXPORT_SYMBOL_GPL(put_rpccred);
 
@@ -513,7 +526,7 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
        if (cred->cr_ops->crwrap_req)
                return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
        /* By default, we encode the arguments normally. */
-       return rpc_call_xdrproc(encode, rqstp, data, obj);
+       return encode(rqstp, data, obj);
 }
 
 int
@@ -528,7 +541,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
                return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
                                                   data, obj);
        /* By default, we decode the arguments normally. */
-       return rpc_call_xdrproc(decode, rqstp, data, obj);
+       return decode(rqstp, data, obj);
 }
 
 int