vserver 2.0 rc7
[linux-2.6.git] / net / sunrpc / auth.c
index 5d13e7b..71bd7a1 100644 (file)
@@ -68,12 +68,9 @@ rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
 
        if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor]))
                return NULL;
-       if (!try_module_get(ops->owner))
-               return NULL;
        auth = ops->create(clnt, pseudoflavor);
        if (!auth)
                return NULL;
-       atomic_set(&auth->au_count, 1);
        if (clnt->cl_auth)
                rpcauth_destroy(clnt->cl_auth);
        clnt->cl_auth = auth;
@@ -86,8 +83,6 @@ rpcauth_destroy(struct rpc_auth *auth)
        if (!atomic_dec_and_test(&auth->au_count))
                return;
        auth->au_ops->destroy(auth);
-       module_put(auth->au_ops->owner);
-       kfree(auth);
 }
 
 static DEFINE_SPINLOCK(rpc_credcache_lock);
@@ -95,42 +90,35 @@ static DEFINE_SPINLOCK(rpc_credcache_lock);
 /*
  * Initialize RPC credential cache
  */
-void
-rpcauth_init_credcache(struct rpc_auth *auth)
+int
+rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire)
 {
+       struct rpc_cred_cache *new;
        int i;
-       for (i = 0; i < RPC_CREDCACHE_NR; i++)
-               INIT_LIST_HEAD(&auth->au_credcache[i]);
-       auth->au_nextgc = jiffies + (auth->au_expire >> 1);
-}
 
-/*
- * Destroy an unreferenced credential
- */
-static inline void
-rpcauth_crdestroy(struct rpc_cred *cred)
-{
-#ifdef RPC_DEBUG
-       BUG_ON(cred->cr_magic != RPCAUTH_CRED_MAGIC ||
-                       atomic_read(&cred->cr_count) ||
-                       !list_empty(&cred->cr_hash));
-       cred->cr_magic = 0;
-#endif
-       cred->cr_ops->crdestroy(cred);
+       new = (struct rpc_cred_cache *)kmalloc(sizeof(*new), GFP_KERNEL);
+       if (!new)
+               return -ENOMEM;
+       for (i = 0; i < RPC_CREDCACHE_NR; i++)
+               INIT_HLIST_HEAD(&new->hashtable[i]);
+       new->expire = expire;
+       new->nextgc = jiffies + (expire >> 1);
+       auth->au_credcache = new;
+       return 0;
 }
 
 /*
  * Destroy a list of credentials
  */
 static inline
-void rpcauth_destroy_credlist(struct list_head *head)
+void rpcauth_destroy_credlist(struct hlist_head *head)
 {
        struct rpc_cred *cred;
 
-       while (!list_empty(head)) {
-               cred = list_entry(head->next, struct rpc_cred, cr_hash);
-               list_del_init(&cred->cr_hash);
-               rpcauth_crdestroy(cred);
+       while (!hlist_empty(head)) {
+               cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
+               hlist_del_init(&cred->cr_hash);
+               put_rpccred(cred);
        }
 }
 
@@ -141,56 +129,56 @@ void rpcauth_destroy_credlist(struct list_head *head)
 void
 rpcauth_free_credcache(struct rpc_auth *auth)
 {
-       LIST_HEAD(free);
-       struct list_head *pos, *next;
+       struct rpc_cred_cache *cache = auth->au_credcache;
+       HLIST_HEAD(free);
+       struct hlist_node *pos, *next;
        struct rpc_cred *cred;
        int             i;
 
        spin_lock(&rpc_credcache_lock);
        for (i = 0; i < RPC_CREDCACHE_NR; i++) {
-               list_for_each_safe(pos, next, &auth->au_credcache[i]) {
-                       cred = list_entry(pos, struct rpc_cred, cr_hash);
-                       cred->cr_auth = NULL;
-                       list_del_init(&cred->cr_hash);
-                       if (atomic_read(&cred->cr_count) == 0)
-                               list_add(&cred->cr_hash, &free);
+               hlist_for_each_safe(pos, next, &cache->hashtable[i]) {
+                       cred = hlist_entry(pos, struct rpc_cred, cr_hash);
+                       __hlist_del(&cred->cr_hash);
+                       hlist_add_head(&cred->cr_hash, &free);
                }
        }
        spin_unlock(&rpc_credcache_lock);
        rpcauth_destroy_credlist(&free);
 }
 
-static inline int
-rpcauth_prune_expired(struct rpc_cred *cred, struct list_head *free)
+static void
+rpcauth_prune_expired(struct rpc_auth *auth, struct rpc_cred *cred, struct hlist_head *free)
 {
-       if (atomic_read(&cred->cr_count) != 0)
-              return 0;
-       if (time_before(jiffies, cred->cr_expire))
-               return 0;
-       cred->cr_auth = NULL;
-       list_del(&cred->cr_hash);
-       list_add(&cred->cr_hash, free);
-       return 1;
+       if (atomic_read(&cred->cr_count) != 1)
+              return;
+       if (time_after(jiffies, cred->cr_expire + auth->au_credcache->expire))
+               cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+       if (!(cred->cr_flags & RPCAUTH_CRED_UPTODATE)) {
+               __hlist_del(&cred->cr_hash);
+               hlist_add_head(&cred->cr_hash, free);
+       }
 }
 
 /*
  * Remove stale credentials. Avoid sleeping inside the loop.
  */
 static void
-rpcauth_gc_credcache(struct rpc_auth *auth, struct list_head *free)
+rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free)
 {
-       struct list_head *pos, *next;
+       struct rpc_cred_cache *cache = auth->au_credcache;
+       struct hlist_node *pos, *next;
        struct rpc_cred *cred;
        int             i;
 
        dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth);
        for (i = 0; i < RPC_CREDCACHE_NR; i++) {
-               list_for_each_safe(pos, next, &auth->au_credcache[i]) {
-                       cred = list_entry(pos, struct rpc_cred, cr_hash);
-                       rpcauth_prune_expired(cred, free);
+               hlist_for_each_safe(pos, next, &cache->hashtable[i]) {
+                       cred = hlist_entry(pos, struct rpc_cred, cr_hash);
+                       rpcauth_prune_expired(auth, cred, free);
                }
        }
-       auth->au_nextgc = jiffies + auth->au_expire;
+       cache->nextgc = jiffies + cache->expire;
 }
 
 /*
@@ -200,8 +188,9 @@ struct rpc_cred *
 rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
                int taskflags)
 {
-       LIST_HEAD(free);
-       struct list_head *pos, *next;
+       struct rpc_cred_cache *cache = auth->au_credcache;
+       HLIST_HEAD(free);
+       struct hlist_node *pos, *next;
        struct rpc_cred *new = NULL,
                        *cred = NULL;
        int             nr = 0;
@@ -210,28 +199,26 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
                nr = acred->uid & RPC_CREDCACHE_MASK;
 retry:
        spin_lock(&rpc_credcache_lock);
-       if (time_before(auth->au_nextgc, jiffies))
+       if (time_before(cache->nextgc, jiffies))
                rpcauth_gc_credcache(auth, &free);
-       list_for_each_safe(pos, next, &auth->au_credcache[nr]) {
+       hlist_for_each_safe(pos, next, &cache->hashtable[nr]) {
                struct rpc_cred *entry;
-               entry = list_entry(pos, struct rpc_cred, cr_hash);
-               if (rpcauth_prune_expired(entry, &free))
-                       continue;
+               entry = hlist_entry(pos, struct rpc_cred, cr_hash);
                if (entry->cr_ops->crmatch(acred, entry, taskflags)) {
-                       list_del(&entry->cr_hash);
+                       hlist_del(&entry->cr_hash);
                        cred = entry;
                        break;
                }
+               rpcauth_prune_expired(auth, entry, &free);
        }
        if (new) {
                if (cred)
-                       list_add(&new->cr_hash, &free);
+                       hlist_add_head(&new->cr_hash, &free);
                else
                        cred = new;
        }
        if (cred) {
-               list_add(&cred->cr_hash, &auth->au_credcache[nr]);
-               cred->cr_auth = auth;
+               hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]);
                get_rpccred(cred);
        }
        spin_unlock(&rpc_credcache_lock);
@@ -240,12 +227,13 @@ retry:
 
        if (!cred) {
                new = auth->au_ops->crcreate(auth, acred, taskflags);
-               if (new) {
+               if (!IS_ERR(new)) {
 #ifdef RPC_DEBUG
                        new->cr_magic = RPCAUTH_CRED_MAGIC;
 #endif
                        goto retry;
-               }
+               } else
+                       cred = new;
        }
 
        return (struct rpc_cred *) cred;
@@ -254,19 +242,19 @@ retry:
 struct rpc_cred *
 rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
 {
-       struct auth_cred acred;
+       struct auth_cred acred = {
+               .uid = current->fsuid,
+               .gid = current->fsgid,
+               .xid = vx_current_xid(),
+               .group_info = current->group_info,
+       };
        struct rpc_cred *ret;
 
-       get_group_info(current->group_info);
-       acred.uid = current->fsuid;
-       acred.gid = current->fsgid;
-       acred.xid = vx_current_xid();
-       acred.group_info = current->group_info;
-
        dprintk("RPC:     looking up %s cred\n",
                auth->au_ops->au_name);
-       ret = rpcauth_lookup_credcache(auth, &acred, taskflags);
-       put_group_info(current->group_info);
+       get_group_info(acred.group_info);
+       ret = auth->au_ops->lookup_cred(auth, &acred, taskflags);
+       put_group_info(acred.group_info);
        return ret;
 }
 
@@ -274,22 +262,23 @@ struct rpc_cred *
 rpcauth_bindcred(struct rpc_task *task)
 {
        struct rpc_auth *auth = task->tk_auth;
-       struct auth_cred acred;
+       struct auth_cred acred = {
+               .uid = current->fsuid,
+               .gid = current->fsgid,
+               .xid = vx_current_xid(),
+               .group_info = current->group_info,
+       };
        struct rpc_cred *ret;
 
-       get_group_info(current->group_info);
-       acred.uid = current->fsuid;
-       acred.gid = current->fsgid;
-       acred.xid = vx_current_xid();
-       acred.group_info = current->group_info;
-
        dprintk("RPC: %4d looking up %s cred\n",
                task->tk_pid, task->tk_auth->au_ops->au_name);
-       task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, &acred, task->tk_flags);
-       if (task->tk_msg.rpc_cred == 0)
-               task->tk_status = -ENOMEM;
-       ret = task->tk_msg.rpc_cred;
-       put_group_info(current->group_info);
+       get_group_info(acred.group_info);
+       ret = auth->au_ops->lookup_cred(auth, &acred, task->tk_flags);
+       if (!IS_ERR(ret))
+               task->tk_msg.rpc_cred = ret;
+       else
+               task->tk_status = PTR_ERR(ret);
+       put_group_info(acred.group_info);
        return ret;
 }
 
@@ -305,16 +294,10 @@ rpcauth_holdcred(struct rpc_task *task)
 void
 put_rpccred(struct rpc_cred *cred)
 {
-       if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
-               return;
-
-       if (list_empty(&cred->cr_hash)) {
-               spin_unlock(&rpc_credcache_lock);
-               rpcauth_crdestroy(cred);
+       cred->cr_expire = jiffies;
+       if (!atomic_dec_and_test(&cred->cr_count))
                return;
-       }
-       cred->cr_expire = jiffies + cred->cr_auth->au_expire;
-       spin_unlock(&rpc_credcache_lock);
+       cred->cr_ops->crdestroy(cred);
 }
 
 void
@@ -338,8 +321,7 @@ rpcauth_marshcred(struct rpc_task *task, u32 *p)
 
        dprintk("RPC: %4d marshaling %s cred %p\n",
                task->tk_pid, auth->au_ops->au_name, cred);
-       return cred->cr_ops->crmarshal(task, p,
-                               task->tk_flags & RPC_CALL_REALUID);
+       return cred->cr_ops->crmarshal(task, p);
 }
 
 u32 *
@@ -360,7 +342,7 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
        struct rpc_cred *cred = task->tk_msg.rpc_cred;
 
        dprintk("RPC: %4d using %s cred %p to wrap rpc data\n",
-                       task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
+                       task->tk_pid, cred->cr_ops->cr_name, cred);
        if (cred->cr_ops->crwrap_req)
                return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
        /* By default, we encode the arguments normally. */
@@ -374,7 +356,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
        struct rpc_cred *cred = task->tk_msg.rpc_cred;
 
        dprintk("RPC: %4d using %s cred %p to unwrap rpc data\n",
-                       task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
+                       task->tk_pid, cred->cr_ops->cr_name, cred);
        if (cred->cr_ops->crunwrap_resp)
                return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
                                                   data, obj);
@@ -387,11 +369,14 @@ rpcauth_refreshcred(struct rpc_task *task)
 {
        struct rpc_auth *auth = task->tk_auth;
        struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       int err;
 
        dprintk("RPC: %4d refreshing %s cred %p\n",
                task->tk_pid, auth->au_ops->au_name, cred);
-       task->tk_status = cred->cr_ops->crrefresh(task);
-       return task->tk_status;
+       err = cred->cr_ops->crrefresh(task);
+       if (err < 0)
+               task->tk_status = err;
+       return err;
 }
 
 void