SUNRPC: Move the bound cred to struct rpc_rqst
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Sat, 31 Jul 2010 18:29:08 +0000 (14:29 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 4 Aug 2010 12:54:09 +0000 (08:54 -0400)
This will allow us to save the original generic cred in rpc_message, so
that if we migrate from one server to another, we can generate a new bound
cred without having to punt back to the NFS layer.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
12 files changed:
fs/nfs/nfs2xdr.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4xdr.c
include/linux/sunrpc/auth.h
include/linux/sunrpc/xprt.h
net/sunrpc/auth.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_null.c
net/sunrpc/auth_unix.c
net/sunrpc/clnt.c
net/sunrpc/sched.c
net/sunrpc/xprt.c

index 81cf142579167e9654b3332348e92e3eee48c37b..db8846a0e82eb686f4722b51dd5f2dbef3c6960d 100644 (file)
@@ -233,7 +233,7 @@ nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs
 static int
 nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
 {
-       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+       struct rpc_auth *auth = req->rq_cred->cr_auth;
        unsigned int replen;
        u32 offset = (u32)args->offset;
        u32 count = args->count;
@@ -393,8 +393,7 @@ nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *arg
 static int
 nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
 {
-       struct rpc_task *task = req->rq_task;
-       struct rpc_auth *auth = task->tk_msg.rpc_cred->cr_auth;
+       struct rpc_auth *auth = req->rq_cred->cr_auth;
        unsigned int replen;
        u32 count = args->count;
 
@@ -575,7 +574,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
 static int
 nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
 {
-       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+       struct rpc_auth *auth = req->rq_cred->cr_auth;
        unsigned int replen;
 
        p = xdr_encode_fhandle(p, args->fh);
index 75dcfc7da365ef21de70057f1eb833cbb50c8682..9769704f8ce626c6fa4c215c494d5dfab1adc7c1 100644 (file)
@@ -330,7 +330,7 @@ nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *arg
 static int
 nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
 {
-       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+       struct rpc_auth *auth = req->rq_cred->cr_auth;
        unsigned int replen;
        u32 count = args->count;
 
@@ -471,7 +471,7 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
 static int
 nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
 {
-       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+       struct rpc_auth *auth = req->rq_cred->cr_auth;
        unsigned int replen;
        u32 count = args->count;
 
@@ -675,7 +675,7 @@ static int
 nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
                    struct nfs3_getaclargs *args)
 {
-       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+       struct rpc_auth *auth = req->rq_cred->cr_auth;
        unsigned int replen;
 
        p = xdr_encode_fhandle(p, args->fh);
@@ -802,7 +802,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
 static int
 nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
 {
-       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+       struct rpc_auth *auth = req->rq_cred->cr_auth;
        unsigned int replen;
 
        p = xdr_encode_fhandle(p, args->fh);
index 257c1811feb445bffe0c47909a8ebcb3c2b1d37a..08ef912911324d550285299d112164b11f45689b 100644 (file)
@@ -758,7 +758,7 @@ static void encode_compound_hdr(struct xdr_stream *xdr,
                                struct compound_hdr *hdr)
 {
        __be32 *p;
-       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+       struct rpc_auth *auth = req->rq_cred->cr_auth;
 
        /* initialize running count of expected bytes in reply.
         * NOTE: the replied tag SHOULD be the same is the one sent,
index 90e4c3827ac0787b2b011e20271d61c206501bba..5bbc447175dce88239097002e403a7957d4e42a2 100644 (file)
@@ -135,10 +135,8 @@ void                       rpcauth_release(struct rpc_auth *);
 struct rpc_cred *      rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int);
 void                   rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
 struct rpc_cred *      rpcauth_lookupcred(struct rpc_auth *, int);
-int                    rpcauth_bindcred(struct rpc_task *, struct rpc_cred *, int);
 struct rpc_cred *      rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *, int);
 void                   put_rpccred(struct rpc_cred *);
-void                   rpcauth_unbindcred(struct rpc_task *);
 __be32 *               rpcauth_marshcred(struct rpc_task *, __be32 *);
 __be32 *               rpcauth_checkverf(struct rpc_task *, __be32 *);
 int                    rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, __be32 *data, void *obj);
index b51470302399aa6e5ac37c8577b138ec81c7bbf7..ff5a77b28c50c61044e150591d2148c76414cdf3 100644 (file)
@@ -64,6 +64,7 @@ struct rpc_rqst {
         * This is the private part
         */
        struct rpc_task *       rq_task;        /* RPC task data */
+       struct rpc_cred *       rq_cred;        /* Bound cred */
        __be32                  rq_xid;         /* request XID */
        int                     rq_cong;        /* has incremented xprt->cong */
        u32                     rq_seqno;       /* gss seq no. used on req. */
index d8968faf5ccf685a05c8c6628e4850f5f87a70fc..95721426296d2b810a92fff46d7f8609c2853306 100644 (file)
@@ -477,9 +477,10 @@ rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags)
        return rpcauth_lookupcred(auth, lookupflags);
 }
 
-int
+static int
 rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags)
 {
+       struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_cred *new;
        int lookupflags = 0;
 
@@ -493,9 +494,9 @@ rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags)
                new = rpcauth_bind_new_cred(task, lookupflags);
        if (IS_ERR(new))
                return PTR_ERR(new);
-       if (task->tk_msg.rpc_cred != NULL)
-               put_rpccred(task->tk_msg.rpc_cred);
-       task->tk_msg.rpc_cred = new;
+       if (req->rq_cred != NULL)
+               put_rpccred(req->rq_cred);
+       req->rq_cred = new;
        return 0;
 }
 
@@ -535,22 +536,10 @@ out_nodestroy:
 }
 EXPORT_SYMBOL_GPL(put_rpccred);
 
-void
-rpcauth_unbindcred(struct rpc_task *task)
-{
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
-
-       dprintk("RPC: %5u releasing %s cred %p\n",
-               task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
-
-       put_rpccred(cred);
-       task->tk_msg.rpc_cred = NULL;
-}
-
 __be32 *
 rpcauth_marshcred(struct rpc_task *task, __be32 *p)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 
        dprintk("RPC: %5u marshaling %s cred %p\n",
                task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
@@ -561,7 +550,7 @@ rpcauth_marshcred(struct rpc_task *task, __be32 *p)
 __be32 *
 rpcauth_checkverf(struct rpc_task *task, __be32 *p)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 
        dprintk("RPC: %5u validating %s cred %p\n",
                task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
@@ -573,7 +562,7 @@ int
 rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
                __be32 *data, void *obj)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 
        dprintk("RPC: %5u using %s cred %p to wrap rpc data\n",
                        task->tk_pid, cred->cr_ops->cr_name, cred);
@@ -587,7 +576,7 @@ int
 rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
                __be32 *data, void *obj)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 
        dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n",
                        task->tk_pid, cred->cr_ops->cr_name, cred);
@@ -601,13 +590,21 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
 int
 rpcauth_refreshcred(struct rpc_task *task)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
        int err;
 
+       cred = task->tk_rqstp->rq_cred;
+       if (cred == NULL) {
+               err = rpcauth_bindcred(task, task->tk_msg.rpc_cred, task->tk_flags);
+               if (err < 0)
+                       goto out;
+               cred = task->tk_rqstp->rq_cred;
+       };
        dprintk("RPC: %5u refreshing %s cred %p\n",
                task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
 
        err = cred->cr_ops->crrefresh(task);
+out:
        if (err < 0)
                task->tk_status = err;
        return err;
@@ -616,7 +613,7 @@ rpcauth_refreshcred(struct rpc_task *task)
 void
 rpcauth_invalcred(struct rpc_task *task)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 
        dprintk("RPC: %5u invalidating %s cred %p\n",
                task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
@@ -627,7 +624,7 @@ rpcauth_invalcred(struct rpc_task *task)
 int
 rpcauth_uptodatecred(struct rpc_task *task)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 
        return cred == NULL ||
                test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0;
index 8da2a0e68574d80bf7e3e37ca6814d804015fbf7..096e1260bc679c1a537ed6d39579bd2690c992ec 100644 (file)
@@ -373,7 +373,7 @@ gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss
 static void
 gss_upcall_callback(struct rpc_task *task)
 {
-       struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred,
+       struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred,
                        struct gss_cred, gc_base);
        struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
        struct inode *inode = &gss_msg->inode->vfs_inode;
@@ -502,7 +502,7 @@ static void warn_gssd(void)
 static inline int
 gss_refresh_upcall(struct rpc_task *task)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
        struct gss_auth *gss_auth = container_of(cred->cr_auth,
                        struct gss_auth, rpc_auth);
        struct gss_cred *gss_cred = container_of(cred,
@@ -1064,12 +1064,12 @@ out:
 static __be32 *
 gss_marshal(struct rpc_task *task, __be32 *p)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_rqst *req = task->tk_rqstp;
+       struct rpc_cred *cred = req->rq_cred;
        struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
                                                 gc_base);
        struct gss_cl_ctx       *ctx = gss_cred_get_ctx(cred);
        __be32          *cred_len;
-       struct rpc_rqst *req = task->tk_rqstp;
        u32             maj_stat = 0;
        struct xdr_netobj mic;
        struct kvec     iov;
@@ -1119,7 +1119,7 @@ out_put_ctx:
 
 static int gss_renew_cred(struct rpc_task *task)
 {
-       struct rpc_cred *oldcred = task->tk_msg.rpc_cred;
+       struct rpc_cred *oldcred = task->tk_rqstp->rq_cred;
        struct gss_cred *gss_cred = container_of(oldcred,
                                                 struct gss_cred,
                                                 gc_base);
@@ -1133,7 +1133,7 @@ static int gss_renew_cred(struct rpc_task *task)
        new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW);
        if (IS_ERR(new))
                return PTR_ERR(new);
-       task->tk_msg.rpc_cred = new;
+       task->tk_rqstp->rq_cred = new;
        put_rpccred(oldcred);
        return 0;
 }
@@ -1161,7 +1161,7 @@ static int gss_cred_is_negative_entry(struct rpc_cred *cred)
 static int
 gss_refresh(struct rpc_task *task)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
        int ret = 0;
 
        if (gss_cred_is_negative_entry(cred))
@@ -1172,7 +1172,7 @@ gss_refresh(struct rpc_task *task)
                ret = gss_renew_cred(task);
                if (ret < 0)
                        goto out;
-               cred = task->tk_msg.rpc_cred;
+               cred = task->tk_rqstp->rq_cred;
        }
 
        if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
@@ -1191,7 +1191,7 @@ gss_refresh_null(struct rpc_task *task)
 static __be32 *
 gss_validate(struct rpc_task *task, __be32 *p)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
        struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
        __be32          seq;
        struct kvec     iov;
@@ -1400,7 +1400,7 @@ static int
 gss_wrap_req(struct rpc_task *task,
             kxdrproc_t encode, void *rqstp, __be32 *p, void *obj)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
        struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
                        gc_base);
        struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
@@ -1503,7 +1503,7 @@ static int
 gss_unwrap_resp(struct rpc_task *task,
                kxdrproc_t decode, void *rqstp, __be32 *p, void *obj)
 {
-       struct rpc_cred *cred = task->tk_msg.rpc_cred;
+       struct rpc_cred *cred = task->tk_rqstp->rq_cred;
        struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
                        gc_base);
        struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
index 1db618f56ecb5e59b6869abaa730894ba4a654e6..a5c36c01707baa3379bd32b29e23d0f5142887a3 100644 (file)
@@ -75,7 +75,7 @@ nul_marshal(struct rpc_task *task, __be32 *p)
 static int
 nul_refresh(struct rpc_task *task)
 {
-       set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags);
+       set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags);
        return 0;
 }
 
index d5e37dbf207bd101307ad16600324da42a72b4b9..4cb70dc6e7ad26e3008ab9be4f617af79e3cc0d1 100644 (file)
@@ -140,7 +140,7 @@ static __be32 *
 unx_marshal(struct rpc_task *task, __be32 *p)
 {
        struct rpc_clnt *clnt = task->tk_client;
-       struct unx_cred *cred = container_of(task->tk_msg.rpc_cred, struct unx_cred, uc_base);
+       struct unx_cred *cred = container_of(task->tk_rqstp->rq_cred, struct unx_cred, uc_base);
        __be32          *base, *hold;
        int             i;
 
@@ -173,7 +173,7 @@ unx_marshal(struct rpc_task *task, __be32 *p)
 static int
 unx_refresh(struct rpc_task *task)
 {
-       set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags);
+       set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags);
        return 0;
 }
 
@@ -196,7 +196,7 @@ unx_validate(struct rpc_task *task, __be32 *p)
                printk("RPC: giant verf size: %u\n", size);
                return NULL;
        }
-       task->tk_msg.rpc_cred->cr_auth->au_rslack = (size >> 2) + 2;
+       task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2;
        p += (size >> 2);
 
        return p;
index f34b5e3823c0813d227454411392f4433a59ea4a..2388d83b68ff75dc4644d1b5808ef19224cd469b 100644 (file)
@@ -605,8 +605,8 @@ rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg)
                task->tk_msg.rpc_proc = msg->rpc_proc;
                task->tk_msg.rpc_argp = msg->rpc_argp;
                task->tk_msg.rpc_resp = msg->rpc_resp;
-               /* Bind the user cred */
-               task->tk_status = rpcauth_bindcred(task, msg->rpc_cred, task->tk_flags);
+               if (msg->rpc_cred != NULL)
+                       task->tk_msg.rpc_cred = get_rpccred(msg->rpc_cred);
        }
 }
 
@@ -909,11 +909,6 @@ call_reserve(struct rpc_task *task)
 {
        dprint_status(task);
 
-       if (!rpcauth_uptodatecred(task)) {
-               task->tk_action = call_refresh;
-               return;
-       }
-
        task->tk_status  = 0;
        task->tk_action  = call_reserveresult;
        xprt_reserve(task);
@@ -977,7 +972,7 @@ call_reserveresult(struct rpc_task *task)
 static void
 call_allocate(struct rpc_task *task)
 {
-       unsigned int slack = task->tk_msg.rpc_cred->cr_auth->au_cslack;
+       unsigned int slack = task->tk_client->cl_auth->au_cslack;
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_xprt *xprt = task->tk_xprt;
        struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
@@ -985,7 +980,7 @@ call_allocate(struct rpc_task *task)
        dprint_status(task);
 
        task->tk_status = 0;
-       task->tk_action = call_bind;
+       task->tk_action = call_refresh;
 
        if (req->rq_buffer)
                return;
@@ -1022,6 +1017,47 @@ call_allocate(struct rpc_task *task)
        rpc_exit(task, -ERESTARTSYS);
 }
 
+/*
+ * 2a. Bind and/or refresh the credentials
+ */
+static void
+call_refresh(struct rpc_task *task)
+{
+       dprint_status(task);
+
+       task->tk_action = call_refreshresult;
+       task->tk_status = 0;
+       task->tk_client->cl_stats->rpcauthrefresh++;
+       rpcauth_refreshcred(task);
+}
+
+/*
+ * 2b. Process the results of a credential refresh
+ */
+static void
+call_refreshresult(struct rpc_task *task)
+{
+       int status = task->tk_status;
+
+       dprint_status(task);
+
+       task->tk_status = 0;
+       task->tk_action = call_bind;
+       if (status >= 0 && rpcauth_uptodatecred(task))
+               return;
+       switch (status) {
+       case -EACCES:
+               rpc_exit(task, -EACCES);
+               return;
+       case -ENOMEM:
+               rpc_exit(task, -ENOMEM);
+               return;
+       case -ETIMEDOUT:
+               rpc_delay(task, 3*HZ);
+       }
+       task->tk_action = call_refresh;
+}
+
 static inline int
 rpc_task_need_encode(struct rpc_task *task)
 {
@@ -1557,43 +1593,6 @@ out_retry:
        }
 }
 
-/*
- * 8.  Refresh the credentials if rejected by the server
- */
-static void
-call_refresh(struct rpc_task *task)
-{
-       dprint_status(task);
-
-       task->tk_action = call_refreshresult;
-       task->tk_status = 0;
-       task->tk_client->cl_stats->rpcauthrefresh++;
-       rpcauth_refreshcred(task);
-}
-
-/*
- * 8a. Process the results of a credential refresh
- */
-static void
-call_refreshresult(struct rpc_task *task)
-{
-       int status = task->tk_status;
-
-       dprint_status(task);
-
-       task->tk_status = 0;
-       task->tk_action = call_reserve;
-       if (status >= 0 && rpcauth_uptodatecred(task))
-               return;
-       if (status == -EACCES) {
-               rpc_exit(task, -EACCES);
-               return;
-       }
-       task->tk_action = call_refresh;
-       if (status != -ETIMEDOUT)
-               rpc_delay(task, 3*HZ);
-}
-
 static __be32 *
 rpc_encode_header(struct rpc_task *task)
 {
index a42296db2ecd6a0d11517c528d766c43cc056381..f6db6131fb2ebe544aed938a861e29f0b4fc42ea 100644 (file)
@@ -864,7 +864,7 @@ void rpc_put_task(struct rpc_task *task)
        if (task->tk_rqstp)
                xprt_release(task);
        if (task->tk_msg.rpc_cred)
-               rpcauth_unbindcred(task);
+               put_rpccred(task->tk_msg.rpc_cred);
        rpc_task_release_client(task);
        if (task->tk_workqueue != NULL) {
                INIT_WORK(&task->u.tk_work, rpc_async_release);
index dcd0132396ba37ad231d23f6af1cc63047fa3d62..70297836a1919f02d55c966418ba767d1def2480 100644 (file)
@@ -1032,6 +1032,8 @@ void xprt_release(struct rpc_task *task)
        spin_unlock_bh(&xprt->transport_lock);
        if (req->rq_buffer)
                xprt->ops->buf_free(req->rq_buffer);
+       if (req->rq_cred != NULL)
+               put_rpccred(req->rq_cred);
        task->tk_rqstp = NULL;
        if (req->rq_release_snd_buf)
                req->rq_release_snd_buf(req);