rpc: eliminate unused variable in auth_gss upcall code
[safe/jmp/linux-2.6] / net / sunrpc / auth_gss / auth_gss.c
index f44f46f..ebfd630 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * linux/net/sunrpc/auth_gss.c
+ * linux/net/sunrpc/auth_gss/auth_gss.c
  *
  * RPCSEC_GSS client authentication.
- * 
+ *
  *  Copyright (c) 2000 The Regents of the University of Michigan.
  *  All rights reserved.
  *
 #include <linux/sunrpc/gss_api.h>
 #include <asm/uaccess.h>
 
-static struct rpc_authops authgss_ops;
+static const struct rpc_authops authgss_ops;
 
-static struct rpc_credops gss_credops;
+static const struct rpc_credops gss_credops;
+static const struct rpc_credops gss_nullops;
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY       RPCDBG_AUTH
@@ -64,77 +65,32 @@ static struct rpc_credops gss_credops;
 
 #define NFS_NGROUPS    16
 
-#define GSS_CRED_EXPIRE                (60 * HZ)       /* XXX: reasonable? */
 #define GSS_CRED_SLACK         1024            /* XXX: unused */
 /* length of a krb5 verifier (48), plus data added before arguments when
  * using integrity (two 4-byte integers): */
-#define GSS_VERF_SLACK         56
+#define GSS_VERF_SLACK         100
 
 /* XXX this define must match the gssd define
 * as it is passed to gssd to signal the use of
 * machine creds should be part of the shared rpc interface */
 
-#define CA_RUN_AS_MACHINE  0x00000200 
+#define CA_RUN_AS_MACHINE  0x00000200
 
 /* dump the buffer in `emacs-hexl' style */
 #define isprint(c)      ((c > 0x1f) && (c < 0x7f))
 
-static DEFINE_RWLOCK(gss_ctx_lock);
-
 struct gss_auth {
+       struct kref kref;
        struct rpc_auth rpc_auth;
        struct gss_api_mech *mech;
        enum rpc_gss_svc service;
-       struct list_head upcalls;
        struct rpc_clnt *client;
        struct dentry *dentry;
-       char path[48];
-       spinlock_t lock;
 };
 
-static void gss_destroy_ctx(struct gss_cl_ctx *);
+static void gss_free_ctx(struct gss_cl_ctx *);
 static struct rpc_pipe_ops gss_upcall_ops;
 
-void
-print_hexl(u32 *p, u_int length, u_int offset)
-{
-       u_int i, j, jm;
-       u8 c, *cp;
-       
-       dprintk("RPC: print_hexl: length %d\n",length);
-       dprintk("\n");
-       cp = (u8 *) p;
-       
-       for (i = 0; i < length; i += 0x10) {
-               dprintk("  %04x: ", (u_int)(i + offset));
-               jm = length - i;
-               jm = jm > 16 ? 16 : jm;
-               
-               for (j = 0; j < jm; j++) {
-                       if ((j % 2) == 1)
-                               dprintk("%02x ", (u_int)cp[i+j]);
-                       else
-                               dprintk("%02x", (u_int)cp[i+j]);
-               }
-               for (; j < 16; j++) {
-                       if ((j % 2) == 1)
-                               dprintk("   ");
-                       else
-                               dprintk("  ");
-               }
-               dprintk(" ");
-               
-               for (j = 0; j < jm; j++) {
-                       c = cp[i+j];
-                       c = isprint(c) ? c : '.';
-                       dprintk("%c", c);
-               }
-               dprintk("\n");
-       }
-}
-
-EXPORT_SYMBOL(print_hexl);
-
 static inline struct gss_cl_ctx *
 gss_get_ctx(struct gss_cl_ctx *ctx)
 {
@@ -146,34 +102,26 @@ static inline void
 gss_put_ctx(struct gss_cl_ctx *ctx)
 {
        if (atomic_dec_and_test(&ctx->count))
-               gss_destroy_ctx(ctx);
+               gss_free_ctx(ctx);
 }
 
+/* gss_cred_set_ctx:
+ * called by gss_upcall_callback and gss_create_upcall in order
+ * to set the gss context. The actual exchange of an old context
+ * and a new one is protected by the inode->i_lock.
+ */
 static void
 gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
 {
        struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
-       struct gss_cl_ctx *old;
-       write_lock(&gss_ctx_lock);
-       old = gss_cred->gc_ctx;
-       gss_cred->gc_ctx = ctx;
-       cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
-       write_unlock(&gss_ctx_lock);
-       if (old)
-               gss_put_ctx(old);
-}
 
-static int
-gss_cred_is_uptodate_ctx(struct rpc_cred *cred)
-{
-       struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
-       int res = 0;
-
-       read_lock(&gss_ctx_lock);
-       if ((cred->cr_flags & RPCAUTH_CRED_UPTODATE) && gss_cred->gc_ctx)
-               res = 1;
-       read_unlock(&gss_ctx_lock);
-       return res;
+       if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
+               return;
+       gss_get_ctx(ctx);
+       rcu_assign_pointer(gss_cred->gc_ctx, ctx);
+       set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
+       smp_mb__before_clear_bit();
+       clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
 }
 
 static const void *
@@ -198,11 +146,10 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest)
        q = (const void *)((const char *)p + len);
        if (unlikely(q > end || q < p))
                return ERR_PTR(-EFAULT);
-       dest->data = kmalloc(len, GFP_KERNEL);
+       dest->data = kmemdup(p, len, GFP_NOFS);
        if (unlikely(dest->data == NULL))
                return ERR_PTR(-ENOMEM);
        dest->len = len;
-       memcpy(dest->data, p, len);
        return q;
 }
 
@@ -212,10 +159,10 @@ gss_cred_get_ctx(struct rpc_cred *cred)
        struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
        struct gss_cl_ctx *ctx = NULL;
 
-       read_lock(&gss_ctx_lock);
+       rcu_read_lock();
        if (gss_cred->gc_ctx)
                ctx = gss_get_ctx(gss_cred->gc_ctx);
-       read_unlock(&gss_ctx_lock);
+       rcu_read_unlock();
        return ctx;
 }
 
@@ -224,9 +171,8 @@ gss_alloc_context(void)
 {
        struct gss_cl_ctx *ctx;
 
-       ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+       ctx = kzalloc(sizeof(*ctx), GFP_NOFS);
        if (ctx != NULL) {
-               memset(ctx, 0, sizeof(*ctx));
                ctx->gc_proc = RPC_GSS_PROC_DATA;
                ctx->gc_seq = 1;        /* NetApp 6.4R1 doesn't accept seq. no. 0 */
                spin_lock_init(&ctx->gc_seq_lock);
@@ -283,7 +229,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
        }
        return q;
 err:
-       dprintk("RPC:      gss_fill_context returning %ld\n", -PTR_ERR(p));
+       dprintk("RPC:       gss_fill_context returning %ld\n", -PTR_ERR(p));
        return p;
 }
 
@@ -307,49 +253,50 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
        BUG_ON(!list_empty(&gss_msg->list));
        if (gss_msg->ctx != NULL)
                gss_put_ctx(gss_msg->ctx);
+       rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
        kfree(gss_msg);
 }
 
 static struct gss_upcall_msg *
-__gss_find_upcall(struct gss_auth *gss_auth, uid_t uid)
+__gss_find_upcall(struct rpc_inode *rpci, uid_t uid)
 {
        struct gss_upcall_msg *pos;
-       list_for_each_entry(pos, &gss_auth->upcalls, list) {
+       list_for_each_entry(pos, &rpci->in_downcall, list) {
                if (pos->uid != uid)
                        continue;
                atomic_inc(&pos->count);
-               dprintk("RPC:      gss_find_upcall found msg %p\n", pos);
+               dprintk("RPC:       gss_find_upcall found msg %p\n", pos);
                return pos;
        }
-       dprintk("RPC:      gss_find_upcall found nothing\n");
+       dprintk("RPC:       gss_find_upcall found nothing\n");
        return NULL;
 }
 
-/* Try to add a upcall to the pipefs queue.
+/* Try to add an upcall to the pipefs queue.
  * If an upcall owned by our uid already exists, then we return a reference
  * to that upcall instead of adding the new upcall.
  */
 static inline struct gss_upcall_msg *
 gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg)
 {
+       struct inode *inode = gss_auth->dentry->d_inode;
+       struct rpc_inode *rpci = RPC_I(inode);
        struct gss_upcall_msg *old;
 
-       spin_lock(&gss_auth->lock);
-       old = __gss_find_upcall(gss_auth, gss_msg->uid);
+       spin_lock(&inode->i_lock);
+       old = __gss_find_upcall(rpci, gss_msg->uid);
        if (old == NULL) {
                atomic_inc(&gss_msg->count);
-               list_add(&gss_msg->list, &gss_auth->upcalls);
+               list_add(&gss_msg->list, &rpci->in_downcall);
        } else
                gss_msg = old;
-       spin_unlock(&gss_auth->lock);
+       spin_unlock(&inode->i_lock);
        return gss_msg;
 }
 
 static void
 __gss_unhash_msg(struct gss_upcall_msg *gss_msg)
 {
-       if (list_empty(&gss_msg->list))
-               return;
        list_del_init(&gss_msg->list);
        rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
        wake_up_all(&gss_msg->waitqueue);
@@ -360,10 +307,14 @@ static void
 gss_unhash_msg(struct gss_upcall_msg *gss_msg)
 {
        struct gss_auth *gss_auth = gss_msg->auth;
+       struct inode *inode = gss_auth->dentry->d_inode;
 
-       spin_lock(&gss_auth->lock);
-       __gss_unhash_msg(gss_msg);
-       spin_unlock(&gss_auth->lock);
+       if (list_empty(&gss_msg->list))
+               return;
+       spin_lock(&inode->i_lock);
+       if (!list_empty(&gss_msg->list))
+               __gss_unhash_msg(gss_msg);
+       spin_unlock(&inode->i_lock);
 }
 
 static void
@@ -372,16 +323,16 @@ gss_upcall_callback(struct rpc_task *task)
        struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred,
                        struct gss_cred, gc_base);
        struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
+       struct inode *inode = gss_msg->auth->dentry->d_inode;
 
-       BUG_ON(gss_msg == NULL);
+       spin_lock(&inode->i_lock);
        if (gss_msg->ctx)
-               gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx));
+               gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
        else
                task->tk_status = gss_msg->msg.errno;
-       spin_lock(&gss_msg->auth->lock);
        gss_cred->gc_upcall = NULL;
        rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
-       spin_unlock(&gss_msg->auth->lock);
+       spin_unlock(&inode->i_lock);
        gss_release_msg(gss_msg);
 }
 
@@ -390,9 +341,8 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid)
 {
        struct gss_upcall_msg *gss_msg;
 
-       gss_msg = kmalloc(sizeof(*gss_msg), GFP_KERNEL);
+       gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
        if (gss_msg != NULL) {
-               memset(gss_msg, 0, sizeof(*gss_msg));
                INIT_LIST_HEAD(&gss_msg->list);
                rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
                init_waitqueue_head(&gss_msg->waitqueue);
@@ -408,9 +358,16 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid)
 static struct gss_upcall_msg *
 gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred)
 {
+       struct gss_cred *gss_cred = container_of(cred,
+                       struct gss_cred, gc_base);
        struct gss_upcall_msg *gss_new, *gss_msg;
+       uid_t uid = cred->cr_uid;
+
+       /* Special case: rpc.gssd assumes that uid == 0 implies machine creds */
+       if (gss_cred->gc_machine_cred != 0)
+               uid = 0;
 
-       gss_new = gss_alloc_msg(gss_auth, cred->cr_uid);
+       gss_new = gss_alloc_msg(gss_auth, uid);
        if (gss_new == NULL)
                return ERR_PTR(-ENOMEM);
        gss_msg = gss_add_msg(gss_auth, gss_new);
@@ -429,47 +386,54 @@ static inline int
 gss_refresh_upcall(struct rpc_task *task)
 {
        struct rpc_cred *cred = task->tk_msg.rpc_cred;
-       struct gss_auth *gss_auth = container_of(task->tk_client->cl_auth,
+       struct gss_auth *gss_auth = container_of(cred->cr_auth,
                        struct gss_auth, rpc_auth);
        struct gss_cred *gss_cred = container_of(cred,
                        struct gss_cred, gc_base);
        struct gss_upcall_msg *gss_msg;
+       struct inode *inode = gss_auth->dentry->d_inode;
        int err = 0;
 
-       dprintk("RPC: %4u gss_refresh_upcall for uid %u\n", task->tk_pid, cred->cr_uid);
+       dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid,
+                                                               cred->cr_uid);
        gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred);
        if (IS_ERR(gss_msg)) {
                err = PTR_ERR(gss_msg);
                goto out;
        }
-       spin_lock(&gss_auth->lock);
+       spin_lock(&inode->i_lock);
        if (gss_cred->gc_upcall != NULL)
-               rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL);
-       else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
+               rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
+       else if (gss_msg->ctx != NULL) {
+               gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
+               gss_cred->gc_upcall = NULL;
+               rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
+       } else if (gss_msg->msg.errno >= 0) {
                task->tk_timeout = 0;
                gss_cred->gc_upcall = gss_msg;
                /* gss_upcall_callback will release the reference to gss_upcall_msg */
                atomic_inc(&gss_msg->count);
-               rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL);
+               rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback);
        } else
                err = gss_msg->msg.errno;
-       spin_unlock(&gss_auth->lock);
+       spin_unlock(&inode->i_lock);
        gss_release_msg(gss_msg);
 out:
-       dprintk("RPC: %4u gss_refresh_upcall for uid %u result %d\n", task->tk_pid,
-                       cred->cr_uid, err);
+       dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n",
+                       task->tk_pid, cred->cr_uid, err);
        return err;
 }
 
 static inline int
 gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
 {
+       struct inode *inode = gss_auth->dentry->d_inode;
        struct rpc_cred *cred = &gss_cred->gc_base;
        struct gss_upcall_msg *gss_msg;
        DEFINE_WAIT(wait);
        int err = 0;
 
-       dprintk("RPC: gss_upcall for uid %u\n", cred->cr_uid);
+       dprintk("RPC:       gss_upcall for uid %u\n", cred->cr_uid);
        gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred);
        if (IS_ERR(gss_msg)) {
                err = PTR_ERR(gss_msg);
@@ -477,12 +441,11 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
        }
        for (;;) {
                prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE);
-               spin_lock(&gss_auth->lock);
+               spin_lock(&inode->i_lock);
                if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) {
-                       spin_unlock(&gss_auth->lock);
                        break;
                }
-               spin_unlock(&gss_auth->lock);
+               spin_unlock(&inode->i_lock);
                if (signalled()) {
                        err = -ERESTARTSYS;
                        goto out_intr;
@@ -490,14 +453,16 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
                schedule();
        }
        if (gss_msg->ctx)
-               gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx));
+               gss_cred_set_ctx(cred, gss_msg->ctx);
        else
                err = gss_msg->msg.errno;
+       spin_unlock(&inode->i_lock);
 out_intr:
        finish_wait(&gss_msg->waitqueue, &wait);
        gss_release_msg(gss_msg);
 out:
-       dprintk("RPC: gss_create_upcall for uid %u result %d\n", cred->cr_uid, err);
+       dprintk("RPC:       gss_create_upcall for uid %u result %d\n",
+                       cred->cr_uid, err);
        return err;
 }
 
@@ -506,16 +471,15 @@ gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
                char __user *dst, size_t buflen)
 {
        char *data = (char *)msg->data + msg->copied;
-       ssize_t mlen = msg->len;
-       ssize_t left;
+       size_t mlen = min(msg->len, buflen);
+       unsigned long left;
 
-       if (mlen > buflen)
-               mlen = buflen;
        left = copy_to_user(dst, data, mlen);
-       if (left < 0) {
-               msg->errno = left;
-               return left;
+       if (left == mlen) {
+               msg->errno = -EFAULT;
+               return -EFAULT;
        }
+
        mlen -= left;
        msg->copied += mlen;
        msg->errno = 0;
@@ -529,22 +493,19 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
 {
        const void *p, *end;
        void *buf;
-       struct rpc_clnt *clnt;
-       struct gss_auth *gss_auth;
-       struct rpc_cred *cred;
        struct gss_upcall_msg *gss_msg;
+       struct inode *inode = filp->f_path.dentry->d_inode;
        struct gss_cl_ctx *ctx;
        uid_t uid;
-       int err = -EFBIG;
+       ssize_t err = -EFBIG;
 
        if (mlen > MSG_BUF_MAXSIZE)
                goto out;
        err = -ENOMEM;
-       buf = kmalloc(mlen, GFP_KERNEL);
+       buf = kmalloc(mlen, GFP_NOFS);
        if (!buf)
                goto out;
 
-       clnt = RPC_I(filp->f_dentry->d_inode)->private;
        err = -EFAULT;
        if (copy_from_user(buf, src, mlen))
                goto err;
@@ -560,43 +521,38 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        ctx = gss_alloc_context();
        if (ctx == NULL)
                goto err;
-       err = 0;
-       gss_auth = container_of(clnt->cl_auth, struct gss_auth, rpc_auth);
-       p = gss_fill_context(p, end, ctx, gss_auth->mech);
+
+       err = -ENOENT;
+       /* Find a matching upcall */
+       spin_lock(&inode->i_lock);
+       gss_msg = __gss_find_upcall(RPC_I(inode), uid);
+       if (gss_msg == NULL) {
+               spin_unlock(&inode->i_lock);
+               goto err_put_ctx;
+       }
+       list_del_init(&gss_msg->list);
+       spin_unlock(&inode->i_lock);
+
+       p = gss_fill_context(p, end, ctx, gss_msg->auth->mech);
        if (IS_ERR(p)) {
                err = PTR_ERR(p);
-               if (err != -EACCES)
-                       goto err_put_ctx;
-       }
-       spin_lock(&gss_auth->lock);
-       gss_msg = __gss_find_upcall(gss_auth, uid);
-       if (gss_msg) {
-               if (err == 0 && gss_msg->ctx == NULL)
-                       gss_msg->ctx = gss_get_ctx(ctx);
-               gss_msg->msg.errno = err;
-               __gss_unhash_msg(gss_msg);
-               spin_unlock(&gss_auth->lock);
-               gss_release_msg(gss_msg);
-       } else {
-               struct auth_cred acred = { .uid = uid };
-               spin_unlock(&gss_auth->lock);
-               cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0);
-               if (IS_ERR(cred)) {
-                       err = PTR_ERR(cred);
-                       goto err_put_ctx;
-               }
-               gss_cred_set_ctx(cred, gss_get_ctx(ctx));
+               gss_msg->msg.errno = (err == -EAGAIN) ? -EAGAIN : -EACCES;
+               goto err_release_msg;
        }
-       gss_put_ctx(ctx);
-       kfree(buf);
-       dprintk("RPC:      gss_pipe_downcall returning length %Zu\n", mlen);
-       return mlen;
+       gss_msg->ctx = gss_get_ctx(ctx);
+       err = mlen;
+
+err_release_msg:
+       spin_lock(&inode->i_lock);
+       __gss_unhash_msg(gss_msg);
+       spin_unlock(&inode->i_lock);
+       gss_release_msg(gss_msg);
 err_put_ctx:
        gss_put_ctx(ctx);
 err:
        kfree(buf);
 out:
-       dprintk("RPC:      gss_pipe_downcall returning %d\n", err);
+       dprintk("RPC:       gss_pipe_downcall returning %Zd\n", err);
        return err;
 }
 
@@ -604,27 +560,21 @@ static void
 gss_pipe_release(struct inode *inode)
 {
        struct rpc_inode *rpci = RPC_I(inode);
-       struct rpc_clnt *clnt;
-       struct rpc_auth *auth;
-       struct gss_auth *gss_auth;
+       struct gss_upcall_msg *gss_msg;
 
-       clnt = rpci->private;
-       auth = clnt->cl_auth;
-       gss_auth = container_of(auth, struct gss_auth, rpc_auth);
-       spin_lock(&gss_auth->lock);
-       while (!list_empty(&gss_auth->upcalls)) {
-               struct gss_upcall_msg *gss_msg;
+       spin_lock(&inode->i_lock);
+       while (!list_empty(&rpci->in_downcall)) {
 
-               gss_msg = list_entry(gss_auth->upcalls.next,
+               gss_msg = list_entry(rpci->in_downcall.next,
                                struct gss_upcall_msg, list);
                gss_msg->msg.errno = -EPIPE;
                atomic_inc(&gss_msg->count);
                __gss_unhash_msg(gss_msg);
-               spin_unlock(&gss_auth->lock);
+               spin_unlock(&inode->i_lock);
                gss_release_msg(gss_msg);
-               spin_lock(&gss_auth->lock);
+               spin_lock(&inode->i_lock);
        }
-       spin_unlock(&gss_auth->lock);
+       spin_unlock(&inode->i_lock);
 }
 
 static void
@@ -634,11 +584,11 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
        static unsigned long ratelimit;
 
        if (msg->errno < 0) {
-               dprintk("RPC:      gss_pipe_destroy_msg releasing msg %p\n",
+               dprintk("RPC:       gss_pipe_destroy_msg releasing msg %p\n",
                                gss_msg);
                atomic_inc(&gss_msg->count);
                gss_unhash_msg(gss_msg);
-               if (msg->errno == -ETIMEDOUT || msg->errno == -EPIPE) {
+               if (msg->errno == -ETIMEDOUT) {
                        unsigned long now = jiffies;
                        if (time_after(now, ratelimit)) {
                                printk(KERN_WARNING "RPC: AUTH_GSS upcall timed out.\n"
@@ -650,8 +600,8 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
        }
 }
 
-/* 
- * NOTE: we have the opportunity to use different 
+/*
+ * NOTE: we have the opportunity to use different
  * parameters based on the input flavor (which must be a pseudoflavor)
  */
 static struct rpc_auth *
@@ -661,7 +611,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
        struct rpc_auth * auth;
        int err = -ENOMEM; /* XXX? */
 
-       dprintk("RPC:      creating GSS authenticator for client %p\n",clnt);
+       dprintk("RPC:       creating GSS authenticator for client %p\n", clnt);
 
        if (!try_module_get(THIS_MODULE))
                return ERR_PTR(err);
@@ -671,36 +621,35 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
        err = -EINVAL;
        gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
        if (!gss_auth->mech) {
-               printk(KERN_WARNING "%s: Pseudoflavor %d not found!",
-                               __FUNCTION__, flavor);
+               printk(KERN_WARNING "%s: Pseudoflavor %d not found!\n",
+                               __func__, flavor);
                goto err_free;
        }
        gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
        if (gss_auth->service == 0)
                goto err_put_mech;
-       INIT_LIST_HEAD(&gss_auth->upcalls);
-       spin_lock_init(&gss_auth->lock);
        auth = &gss_auth->rpc_auth;
        auth->au_cslack = GSS_CRED_SLACK >> 2;
        auth->au_rslack = GSS_VERF_SLACK >> 2;
        auth->au_ops = &authgss_ops;
        auth->au_flavor = flavor;
        atomic_set(&auth->au_count, 1);
+       kref_init(&gss_auth->kref);
 
-       err = rpcauth_init_credcache(auth, GSS_CRED_EXPIRE);
-       if (err)
-               goto err_put_mech;
-
-       snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s",
-                       clnt->cl_pathname,
-                       gss_auth->mech->gm_name);
-       gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
+       gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name,
+                       clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
        if (IS_ERR(gss_auth->dentry)) {
                err = PTR_ERR(gss_auth->dentry);
                goto err_put_mech;
        }
 
+       err = rpcauth_init_credcache(auth);
+       if (err)
+               goto err_unlink_pipe;
+
        return auth;
+err_unlink_pipe:
+       rpc_unlink(gss_auth->dentry);
 err_put_mech:
        gss_mech_put(gss_auth->mech);
 err_free:
@@ -711,100 +660,196 @@ out_dec:
 }
 
 static void
+gss_free(struct gss_auth *gss_auth)
+{
+       rpc_unlink(gss_auth->dentry);
+       gss_auth->dentry = NULL;
+       gss_mech_put(gss_auth->mech);
+
+       kfree(gss_auth);
+       module_put(THIS_MODULE);
+}
+
+static void
+gss_free_callback(struct kref *kref)
+{
+       struct gss_auth *gss_auth = container_of(kref, struct gss_auth, kref);
+
+       gss_free(gss_auth);
+}
+
+static void
 gss_destroy(struct rpc_auth *auth)
 {
        struct gss_auth *gss_auth;
 
-       dprintk("RPC:      destroying GSS authenticator %p flavor %d\n",
-               auth, auth->au_flavor);
+       dprintk("RPC:       destroying GSS authenticator %p flavor %d\n",
+                       auth, auth->au_flavor);
+
+       rpcauth_destroy_credcache(auth);
 
        gss_auth = container_of(auth, struct gss_auth, rpc_auth);
-       rpc_unlink(gss_auth->path);
-       gss_mech_put(gss_auth->mech);
+       kref_put(&gss_auth->kref, gss_free_callback);
+}
 
-       rpcauth_free_credcache(auth);
-       kfree(gss_auth);
-       module_put(THIS_MODULE);
+/*
+ * gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call
+ * to the server with the GSS control procedure field set to
+ * RPC_GSS_PROC_DESTROY. This should normally cause the server to release
+ * all RPCSEC_GSS state associated with that context.
+ */
+static int
+gss_destroying_context(struct rpc_cred *cred)
+{
+       struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
+       struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth);
+       struct rpc_task *task;
+
+       if (gss_cred->gc_ctx == NULL ||
+           test_and_clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
+               return 0;
+
+       gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY;
+       cred->cr_ops = &gss_nullops;
+
+       /* Take a reference to ensure the cred will be destroyed either
+        * by the RPC call or by the put_rpccred() below */
+       get_rpccred(cred);
+
+       task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC|RPC_TASK_SOFT);
+       if (!IS_ERR(task))
+               rpc_put_task(task);
+
+       put_rpccred(cred);
+       return 1;
 }
 
-/* gss_destroy_cred (and gss_destroy_ctx) are used to clean up after failure
+/* gss_destroy_cred (and gss_free_ctx) are used to clean up after failure
  * to create a new cred or context, so they check that things have been
  * allocated before freeing them. */
 static void
-gss_destroy_ctx(struct gss_cl_ctx *ctx)
+gss_do_free_ctx(struct gss_cl_ctx *ctx)
 {
-       dprintk("RPC:      gss_destroy_ctx\n");
-
-       if (ctx->gc_gss_ctx)
-               gss_delete_sec_context(&ctx->gc_gss_ctx);
+       dprintk("RPC:       gss_free_ctx\n");
 
        kfree(ctx->gc_wire_ctx.data);
        kfree(ctx);
 }
 
 static void
-gss_destroy_cred(struct rpc_cred *rc)
+gss_free_ctx_callback(struct rcu_head *head)
+{
+       struct gss_cl_ctx *ctx = container_of(head, struct gss_cl_ctx, gc_rcu);
+       gss_do_free_ctx(ctx);
+}
+
+static void
+gss_free_ctx(struct gss_cl_ctx *ctx)
+{
+       struct gss_ctx *gc_gss_ctx;
+
+       gc_gss_ctx = rcu_dereference(ctx->gc_gss_ctx);
+       rcu_assign_pointer(ctx->gc_gss_ctx, NULL);
+       call_rcu(&ctx->gc_rcu, gss_free_ctx_callback);
+       if (gc_gss_ctx)
+               gss_delete_sec_context(&gc_gss_ctx);
+}
+
+static void
+gss_free_cred(struct gss_cred *gss_cred)
 {
-       struct gss_cred *cred = container_of(rc, struct gss_cred, gc_base);
+       dprintk("RPC:       gss_free_cred %p\n", gss_cred);
+       kfree(gss_cred);
+}
 
-       dprintk("RPC:      gss_destroy_cred \n");
+static void
+gss_free_cred_callback(struct rcu_head *head)
+{
+       struct gss_cred *gss_cred = container_of(head, struct gss_cred, gc_base.cr_rcu);
+       gss_free_cred(gss_cred);
+}
+
+static void
+gss_destroy_cred(struct rpc_cred *cred)
+{
+       struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
+       struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth);
+       struct gss_cl_ctx *ctx = gss_cred->gc_ctx;
 
-       if (cred->gc_ctx)
-               gss_put_ctx(cred->gc_ctx);
-       kfree(cred);
+       if (gss_destroying_context(cred))
+               return;
+       rcu_assign_pointer(gss_cred->gc_ctx, NULL);
+       call_rcu(&cred->cr_rcu, gss_free_cred_callback);
+       if (ctx)
+               gss_put_ctx(ctx);
+       kref_put(&gss_auth->kref, gss_free_callback);
 }
 
 /*
  * Lookup RPCSEC_GSS cred for the current process
  */
 static struct rpc_cred *
-gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
+gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 {
-       return rpcauth_lookup_credcache(auth, acred, taskflags);
+       return rpcauth_lookup_credcache(auth, acred, flags);
 }
 
 static struct rpc_cred *
-gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
+gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 {
        struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
        struct gss_cred *cred = NULL;
        int err = -ENOMEM;
 
-       dprintk("RPC:      gss_create_cred for uid %d, flavor %d\n",
+       dprintk("RPC:       gss_create_cred for uid %d, flavor %d\n",
                acred->uid, auth->au_flavor);
 
-       if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL)))
+       if (!(cred = kzalloc(sizeof(*cred), GFP_NOFS)))
                goto out_err;
 
-       memset(cred, 0, sizeof(*cred));
-       atomic_set(&cred->gc_count, 1);
-       cred->gc_uid = acred->uid;
+       rpcauth_init_cred(&cred->gc_base, acred, auth, &gss_credops);
        /*
         * Note: in order to force a call to call_refresh(), we deliberately
         * fail to flag the credential as RPCAUTH_CRED_UPTODATE.
         */
-       cred->gc_flags = 0;
-       cred->gc_base.cr_ops = &gss_credops;
+       cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW;
        cred->gc_service = gss_auth->service;
-       err = gss_create_upcall(gss_auth, cred);
-       if (err < 0)
-               goto out_err;
-
+       cred->gc_machine_cred = acred->machine_cred;
+       kref_get(&gss_auth->kref);
        return &cred->gc_base;
 
 out_err:
-       dprintk("RPC:      gss_create_cred failed with error %d\n", err);
-       if (cred) gss_destroy_cred(&cred->gc_base);
+       dprintk("RPC:       gss_create_cred failed with error %d\n", err);
        return ERR_PTR(err);
 }
 
 static int
-gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags)
+gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+       struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+       struct gss_cred *gss_cred = container_of(cred,struct gss_cred, gc_base);
+       int err;
+
+       do {
+               err = gss_create_upcall(gss_auth, gss_cred);
+       } while (err == -EAGAIN);
+       return err;
+}
+
+static int
+gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
 {
        struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
 
+       if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
+               goto out;
        /* Don't match with creds that have expired. */
-       if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
+       if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
+               return 0;
+       if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags))
+               return 0;
+out:
+       if (acred->machine_cred != gss_cred->gc_machine_cred)
                return 0;
        return (rc->cr_uid == acred->uid);
 }
@@ -813,21 +858,21 @@ gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags)
 * Marshal credentials.
 * Maybe we should keep a cached credential for performance reasons.
 */
-static u32 *
-gss_marshal(struct rpc_task *task, u32 *p)
+static __be32 *
+gss_marshal(struct rpc_task *task, __be32 *p)
 {
        struct rpc_cred *cred = task->tk_msg.rpc_cred;
        struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
                                                 gc_base);
        struct gss_cl_ctx       *ctx = gss_cred_get_ctx(cred);
-       u32             *cred_len;
+       __be32          *cred_len;
        struct rpc_rqst *req = task->tk_rqstp;
        u32             maj_stat = 0;
        struct xdr_netobj mic;
        struct kvec     iov;
        struct xdr_buf  verf_buf;
 
-       dprintk("RPC: %4u gss_marshal\n", task->tk_pid);
+       dprintk("RPC: %5u gss_marshal\n", task->tk_pid);
 
        *p++ = htonl(RPC_AUTH_GSS);
        cred_len = p++;
@@ -856,7 +901,7 @@ gss_marshal(struct rpc_task *task, u32 *p)
        mic.data = (u8 *)(p + 1);
        maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
        if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
-               cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+               clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
        } else if (maj_stat != 0) {
                printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat);
                goto out_put_ctx;
@@ -869,35 +914,74 @@ out_put_ctx:
        return NULL;
 }
 
+static int gss_renew_cred(struct rpc_task *task)
+{
+       struct rpc_cred *oldcred = task->tk_msg.rpc_cred;
+       struct gss_cred *gss_cred = container_of(oldcred,
+                                                struct gss_cred,
+                                                gc_base);
+       struct rpc_auth *auth = oldcred->cr_auth;
+       struct auth_cred acred = {
+               .uid = oldcred->cr_uid,
+               .machine_cred = gss_cred->gc_machine_cred,
+       };
+       struct rpc_cred *new;
+
+       new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW);
+       if (IS_ERR(new))
+               return PTR_ERR(new);
+       task->tk_msg.rpc_cred = new;
+       put_rpccred(oldcred);
+       return 0;
+}
+
 /*
 * Refresh credentials. XXX - finish
 */
 static int
 gss_refresh(struct rpc_task *task)
 {
+       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       int ret = 0;
+
+       if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
+                       !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) {
+               ret = gss_renew_cred(task);
+               if (ret < 0)
+                       goto out;
+               cred = task->tk_msg.rpc_cred;
+       }
 
-       if (!gss_cred_is_uptodate_ctx(task->tk_msg.rpc_cred))
-               return gss_refresh_upcall(task);
-       return 0;
+       if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
+               ret = gss_refresh_upcall(task);
+out:
+       return ret;
+}
+
+/* Dummy refresh routine: used only when destroying the context */
+static int
+gss_refresh_null(struct rpc_task *task)
+{
+       return -EACCES;
 }
 
-static u32 *
-gss_validate(struct rpc_task *task, u32 *p)
+static __be32 *
+gss_validate(struct rpc_task *task, __be32 *p)
 {
        struct rpc_cred *cred = task->tk_msg.rpc_cred;
        struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
-       u32             seq;
+       __be32          seq;
        struct kvec     iov;
        struct xdr_buf  verf_buf;
        struct xdr_netobj mic;
        u32             flav,len;
        u32             maj_stat;
 
-       dprintk("RPC: %4u gss_validate\n", task->tk_pid);
+       dprintk("RPC: %5u gss_validate\n", task->tk_pid);
 
        flav = ntohl(*p++);
        if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE)
-                goto out_bad;
+               goto out_bad;
        if (flav != RPC_AUTH_GSS)
                goto out_bad;
        seq = htonl(task->tk_rqstp->rq_seqno);
@@ -909,31 +993,35 @@ gss_validate(struct rpc_task *task, u32 *p)
 
        maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
        if (maj_stat == GSS_S_CONTEXT_EXPIRED)
-               cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
-       if (maj_stat)
+               clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
+       if (maj_stat) {
+               dprintk("RPC: %5u gss_validate: gss_verify_mic returned "
+                               "error 0x%08x\n", task->tk_pid, maj_stat);
                goto out_bad;
+       }
        /* We leave it to unwrap to calculate au_rslack. For now we just
         * calculate the length of the verifier: */
-       task->tk_auth->au_verfsize = XDR_QUADLEN(len) + 2;
+       cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2;
        gss_put_ctx(ctx);
-       dprintk("RPC: %4u GSS gss_validate: gss_verify_mic succeeded.\n",
+       dprintk("RPC: %5u gss_validate: gss_verify_mic succeeded.\n",
                        task->tk_pid);
        return p + XDR_QUADLEN(len);
 out_bad:
        gss_put_ctx(ctx);
-       dprintk("RPC: %4u gss_validate failed.\n", task->tk_pid);
+       dprintk("RPC: %5u gss_validate failed.\n", task->tk_pid);
        return NULL;
 }
 
 static inline int
 gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
-               kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj)
+               kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
 {
        struct xdr_buf  *snd_buf = &rqstp->rq_snd_buf;
        struct xdr_buf  integ_buf;
-       u32             *integ_len = NULL;
+       __be32          *integ_len = NULL;
        struct xdr_netobj mic;
-       u32             offset, *q;
+       u32             offset;
+       __be32          *q;
        struct kvec     *iov;
        u32             maj_stat = 0;
        int             status = -EIO;
@@ -942,7 +1030,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
        offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
        *p++ = htonl(rqstp->rq_seqno);
 
-       status = encode(rqstp, p, obj);
+       status = rpc_call_xdrproc(encode, rqstp, p, obj);
        if (status)
                return status;
 
@@ -952,7 +1040,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
        *integ_len = htonl(integ_buf.len);
 
        /* guess whether we're in the head or the tail: */
-       if (snd_buf->page_len || snd_buf->tail[0].iov_len) 
+       if (snd_buf->page_len || snd_buf->tail[0].iov_len)
                iov = snd_buf->tail;
        else
                iov = snd_buf->head;
@@ -962,7 +1050,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
        maj_stat = gss_get_mic(ctx->gc_gss_ctx, &integ_buf, &mic);
        status = -EIO; /* XXX? */
        if (maj_stat == GSS_S_CONTEXT_EXPIRED)
-               cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+               clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
        else if (maj_stat)
                return status;
        q = xdr_encode_opaque(p, NULL, mic.len);
@@ -1019,13 +1107,13 @@ out:
 
 static inline int
 gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
-               kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj)
+               kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
 {
        struct xdr_buf  *snd_buf = &rqstp->rq_snd_buf;
        u32             offset;
        u32             maj_stat;
        int             status;
-       u32             *opaque_len;
+       __be32          *opaque_len;
        struct page     **inpages;
        int             first;
        int             pad;
@@ -1036,7 +1124,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
        offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
        *p++ = htonl(rqstp->rq_seqno);
 
-       status = encode(rqstp, p, obj);
+       status = rpc_call_xdrproc(encode, rqstp, p, obj);
        if (status)
                return status;
 
@@ -1057,11 +1145,11 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
        maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages);
        /* RPC_SLACK_SPACE should prevent this ever happening: */
        BUG_ON(snd_buf->len > snd_buf->buflen);
-        status = -EIO;
+       status = -EIO;
        /* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was
         * done anyway, so it's safe to put the request on the wire: */
        if (maj_stat == GSS_S_CONTEXT_EXPIRED)
-               cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+               clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
        else if (maj_stat)
                return status;
 
@@ -1082,7 +1170,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
 
 static int
 gss_wrap_req(struct rpc_task *task,
-            kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
+            kxdrproc_t encode, void *rqstp, __be32 *p, void *obj)
 {
        struct rpc_cred *cred = task->tk_msg.rpc_cred;
        struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
@@ -1090,36 +1178,36 @@ gss_wrap_req(struct rpc_task *task,
        struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
        int             status = -EIO;
 
-       dprintk("RPC: %4u gss_wrap_req\n", task->tk_pid);
+       dprintk("RPC: %5u gss_wrap_req\n", task->tk_pid);
        if (ctx->gc_proc != RPC_GSS_PROC_DATA) {
                /* The spec seems a little ambiguous here, but I think that not
                 * wrapping context destruction requests makes the most sense.
                 */
-               status = encode(rqstp, p, obj);
+               status = rpc_call_xdrproc(encode, rqstp, p, obj);
                goto out;
        }
        switch (gss_cred->gc_service) {
                case RPC_GSS_SVC_NONE:
-                       status = encode(rqstp, p, obj);
+                       status = rpc_call_xdrproc(encode, rqstp, p, obj);
                        break;
                case RPC_GSS_SVC_INTEGRITY:
                        status = gss_wrap_req_integ(cred, ctx, encode,
                                                                rqstp, p, obj);
                        break;
-                       case RPC_GSS_SVC_PRIVACY:
+               case RPC_GSS_SVC_PRIVACY:
                        status = gss_wrap_req_priv(cred, ctx, encode,
                                        rqstp, p, obj);
                        break;
        }
 out:
        gss_put_ctx(ctx);
-       dprintk("RPC: %4u gss_wrap_req returning %d\n", task->tk_pid, status);
+       dprintk("RPC: %5u gss_wrap_req returning %d\n", task->tk_pid, status);
        return status;
 }
 
 static inline int
 gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
-               struct rpc_rqst *rqstp, u32 **p)
+               struct rpc_rqst *rqstp, __be32 **p)
 {
        struct xdr_buf  *rcv_buf = &rqstp->rq_rcv_buf;
        struct xdr_buf integ_buf;
@@ -1148,7 +1236,7 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
 
        maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic);
        if (maj_stat == GSS_S_CONTEXT_EXPIRED)
-               cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+               clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
        if (maj_stat != GSS_S_COMPLETE)
                return status;
        return 0;
@@ -1156,7 +1244,7 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
 
 static inline int
 gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
-               struct rpc_rqst *rqstp, u32 **p)
+               struct rpc_rqst *rqstp, __be32 **p)
 {
        struct xdr_buf  *rcv_buf = &rqstp->rq_rcv_buf;
        u32 offset;
@@ -1173,7 +1261,7 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
 
        maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf);
        if (maj_stat == GSS_S_CONTEXT_EXPIRED)
-               cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+               clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
        if (maj_stat != GSS_S_COMPLETE)
                return status;
        if (ntohl(*(*p)++) != rqstp->rq_seqno)
@@ -1185,13 +1273,13 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
 
 static int
 gss_unwrap_resp(struct rpc_task *task,
-               kxdrproc_t decode, void *rqstp, u32 *p, void *obj)
+               kxdrproc_t decode, void *rqstp, __be32 *p, void *obj)
 {
        struct rpc_cred *cred = task->tk_msg.rpc_cred;
        struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
                        gc_base);
        struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
-       u32             *savedp = p;
+       __be32          *savedp = p;
        struct kvec     *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head;
        int             savedlen = head->iov_len;
        int             status = -EIO;
@@ -1206,39 +1294,39 @@ gss_unwrap_resp(struct rpc_task *task,
                        if (status)
                                goto out;
                        break;
-                       case RPC_GSS_SVC_PRIVACY:
+               case RPC_GSS_SVC_PRIVACY:
                        status = gss_unwrap_resp_priv(cred, ctx, rqstp, &p);
                        if (status)
                                goto out;
                        break;
        }
        /* take into account extra slack for integrity and privacy cases: */
-       task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp)
+       cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp)
                                                + (savedlen - head->iov_len);
 out_decode:
-       status = decode(rqstp, p, obj);
+       status = rpc_call_xdrproc(decode, rqstp, p, obj);
 out:
        gss_put_ctx(ctx);
-       dprintk("RPC: %4u gss_unwrap_resp returning %d\n", task->tk_pid,
+       dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid,
                        status);
        return status;
 }
-  
-static struct rpc_authops authgss_ops = {
+
+static const struct rpc_authops authgss_ops = {
        .owner          = THIS_MODULE,
        .au_flavor      = RPC_AUTH_GSS,
-#ifdef RPC_DEBUG
        .au_name        = "RPCSEC_GSS",
-#endif
        .create         = gss_create,
        .destroy        = gss_destroy,
        .lookup_cred    = gss_lookup_cred,
        .crcreate       = gss_create_cred
 };
 
-static struct rpc_credops gss_credops = {
+static const struct rpc_credops gss_credops = {
        .cr_name        = "AUTH_GSS",
        .crdestroy      = gss_destroy_cred,
+       .cr_init        = gss_cred_init,
+       .crbind         = rpcauth_generic_bind_cred,
        .crmatch        = gss_match,
        .crmarshal      = gss_marshal,
        .crrefresh      = gss_refresh,
@@ -1247,6 +1335,18 @@ static struct rpc_credops gss_credops = {
        .crunwrap_resp  = gss_unwrap_resp,
 };
 
+static const struct rpc_credops gss_nullops = {
+       .cr_name        = "AUTH_GSS",
+       .crdestroy      = gss_destroy_cred,
+       .crbind         = rpcauth_generic_bind_cred,
+       .crmatch        = gss_match,
+       .crmarshal      = gss_marshal,
+       .crrefresh      = gss_refresh_null,
+       .crvalidate     = gss_validate,
+       .crwrap_req     = gss_wrap_req,
+       .crunwrap_resp  = gss_unwrap_resp,
+};
+
 static struct rpc_pipe_ops gss_upcall_ops = {
        .upcall         = gss_pipe_upcall,
        .downcall       = gss_pipe_downcall,