SUNRPC: Clean up rpc_verify_header()
[linux-2.6-microblaze.git] / net / sunrpc / clnt.c
index d7ec613..e973508 100644 (file)
@@ -77,8 +77,9 @@ static void   call_timeout(struct rpc_task *task);
 static void    call_connect(struct rpc_task *task);
 static void    call_connect_status(struct rpc_task *task);
 
-static __be32  *rpc_encode_header(struct rpc_task *task);
-static __be32  *rpc_verify_header(struct rpc_task *task);
+static int     rpc_encode_header(struct rpc_task *task,
+                                 struct xdr_stream *xdr);
+static __be32  *rpc_decode_header(struct rpc_task *task);
 static int     rpc_ping(struct rpc_clnt *clnt);
 
 static void rpc_register_client(struct rpc_clnt *clnt)
@@ -1728,10 +1729,7 @@ static void
 rpc_xdr_encode(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
-       kxdreproc_t     encode;
-       __be32          *p;
-
-       dprint_status(task);
+       struct xdr_stream xdr;
 
        xdr_buf_init(&req->rq_snd_buf,
                     req->rq_buffer,
@@ -1740,18 +1738,13 @@ rpc_xdr_encode(struct rpc_task *task)
                     req->rq_rbuffer,
                     req->rq_rcvsize);
 
-       p = rpc_encode_header(task);
-       if (p == NULL)
-               return;
-
-       encode = task->tk_msg.rpc_proc->p_encode;
-       if (encode == NULL)
+       req->rq_snd_buf.head[0].iov_len = 0;
+       xdr_init_encode(&xdr, &req->rq_snd_buf,
+                       req->rq_snd_buf.head[0].iov_base, req);
+       if (rpc_encode_header(task, &xdr))
                return;
 
-       task->tk_status = rpcauth_wrap_req(task, encode, req, p,
-                       task->tk_msg.rpc_argp);
-       if (task->tk_status == 0)
-               xprt_request_prepare(req);
+       task->tk_status = rpcauth_wrap_req(task, &xdr);
 }
 
 /*
@@ -1762,6 +1755,7 @@ call_encode(struct rpc_task *task)
 {
        if (!rpc_task_need_encode(task))
                goto out;
+       dprint_status(task);
        /* Encode here so that rpcsec_gss can use correct sequence number. */
        rpc_xdr_encode(task);
        /* Did the encode result in an error condition? */
@@ -1779,6 +1773,8 @@ call_encode(struct rpc_task *task)
                        rpc_exit(task, task->tk_status);
                }
                return;
+       } else {
+               xprt_request_prepare(task->tk_rqstp);
        }
 
        /* Add task to reply queue before transmission to avoid races */
@@ -2296,7 +2292,7 @@ call_decode(struct rpc_task *task)
                goto out_retry;
        }
 
-       p = rpc_verify_header(task);
+       p = rpc_decode_header(task);
        if (IS_ERR(p)) {
                if (p == ERR_PTR(-EAGAIN))
                        goto out_retry;
@@ -2312,7 +2308,7 @@ call_decode(struct rpc_task *task)
        return;
 out_retry:
        task->tk_status = 0;
-       /* Note: rpc_verify_header() may have freed the RPC slot */
+       /* Note: rpc_decode_header() may have freed the RPC slot */
        if (task->tk_rqstp == req) {
                xdr_free_bvec(&req->rq_rcv_buf);
                req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0;
@@ -2322,186 +2318,162 @@ out_retry:
        }
 }
 
-static __be32 *
-rpc_encode_header(struct rpc_task *task)
+static int
+rpc_encode_header(struct rpc_task *task, struct xdr_stream *xdr)
 {
        struct rpc_clnt *clnt = task->tk_client;
        struct rpc_rqst *req = task->tk_rqstp;
-       __be32          *p = req->rq_svec[0].iov_base;
-
-       /* FIXME: check buffer size? */
-
-       p = xprt_skip_transport_header(req->rq_xprt, p);
-       *p++ = req->rq_xid;             /* XID */
-       *p++ = htonl(RPC_CALL);         /* CALL */
-       *p++ = htonl(RPC_VERSION);      /* RPC version */
-       *p++ = htonl(clnt->cl_prog);    /* program number */
-       *p++ = htonl(clnt->cl_vers);    /* program version */
-       *p++ = htonl(task->tk_msg.rpc_proc->p_proc);    /* procedure */
-       p = rpcauth_marshcred(task, p);
-       if (p)
-               req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p);
-       return p;
+       __be32 *p;
+       int error;
+
+       error = -EMSGSIZE;
+       p = xdr_reserve_space(xdr, RPC_CALLHDRSIZE << 2);
+       if (!p)
+               goto out_fail;
+       *p++ = req->rq_xid;
+       *p++ = rpc_call;
+       *p++ = cpu_to_be32(RPC_VERSION);
+       *p++ = cpu_to_be32(clnt->cl_prog);
+       *p++ = cpu_to_be32(clnt->cl_vers);
+       *p   = cpu_to_be32(task->tk_msg.rpc_proc->p_proc);
+
+       error = rpcauth_marshcred(task, xdr);
+       if (error < 0)
+               goto out_fail;
+       return 0;
+out_fail:
+       trace_rpc_bad_callhdr(task);
+       rpc_exit(task, error);
+       return error;
 }
 
-static __be32 *
-rpc_verify_header(struct rpc_task *task)
+static noinline __be32 *
+rpc_decode_header(struct rpc_task *task)
 {
        struct rpc_clnt *clnt = task->tk_client;
        struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
        int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
        __be32  *p = iov->iov_base;
-       u32 n;
        int error = -EACCES;
 
-       if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {
-               /* RFC-1014 says that the representation of XDR data must be a
-                * multiple of four bytes
-                * - if it isn't pointer subtraction in the NFS client may give
-                *   undefined results
-                */
-               dprintk("RPC: %5u %s: XDR representation not a multiple of"
-                      " 4 bytes: 0x%x\n", task->tk_pid, __func__,
-                      task->tk_rqstp->rq_rcv_buf.len);
-               error = -EIO;
-               goto out_err;
-       }
+       /* RFC-1014 says that the representation of XDR data must be a
+        * multiple of four bytes
+        * - if it isn't pointer subtraction in the NFS client may give
+        *   undefined results
+        */
+       if (task->tk_rqstp->rq_rcv_buf.len & 3)
+               goto out_badlen;
        if ((len -= 3) < 0)
-               goto out_overflow;
+               goto out_unparsable;
 
-       p += 1; /* skip XID */
-       if ((n = ntohl(*p++)) != RPC_REPLY) {
-               dprintk("RPC: %5u %s: not an RPC reply: %x\n",
-                       task->tk_pid, __func__, n);
-               error = -EIO;
-               goto out_garbage;
-       }
+       p++;    /* skip XID */
+       if (*p++ != rpc_reply)
+               goto out_unparsable;
+       if (*p++ != rpc_msg_accepted)
+               goto out_msg_denied;
 
-       if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
-               if (--len < 0)
-                       goto out_overflow;
-               switch ((n = ntohl(*p++))) {
-               case RPC_AUTH_ERROR:
-                       break;
-               case RPC_MISMATCH:
-                       dprintk("RPC: %5u %s: RPC call version mismatch!\n",
-                               task->tk_pid, __func__);
-                       error = -EPROTONOSUPPORT;
-                       goto out_err;
-               default:
-                       dprintk("RPC: %5u %s: RPC call rejected, "
-                               "unknown error: %x\n",
-                               task->tk_pid, __func__, n);
-                       error = -EIO;
-                       goto out_err;
-               }
-               if (--len < 0)
-                       goto out_overflow;
-               switch ((n = ntohl(*p++))) {
-               case RPC_AUTH_REJECTEDCRED:
-               case RPC_AUTH_REJECTEDVERF:
-               case RPCSEC_GSS_CREDPROBLEM:
-               case RPCSEC_GSS_CTXPROBLEM:
-                       if (!task->tk_cred_retry)
-                               break;
-                       task->tk_cred_retry--;
-                       dprintk("RPC: %5u %s: retry stale creds\n",
-                                       task->tk_pid, __func__);
-                       rpcauth_invalcred(task);
-                       /* Ensure we obtain a new XID! */
-                       xprt_release(task);
-                       task->tk_action = call_reserve;
-                       goto out_retry;
-               case RPC_AUTH_BADCRED:
-               case RPC_AUTH_BADVERF:
-                       /* possibly garbled cred/verf? */
-                       if (!task->tk_garb_retry)
-                               break;
-                       task->tk_garb_retry--;
-                       dprintk("RPC: %5u %s: retry garbled creds\n",
-                                       task->tk_pid, __func__);
-                       task->tk_action = call_encode;
-                       goto out_retry;
-               case RPC_AUTH_TOOWEAK:
-                       printk(KERN_NOTICE "RPC: server %s requires stronger "
-                              "authentication.\n",
-                              task->tk_xprt->servername);
-                       break;
-               default:
-                       dprintk("RPC: %5u %s: unknown auth error: %x\n",
-                                       task->tk_pid, __func__, n);
-                       error = -EIO;
-               }
-               dprintk("RPC: %5u %s: call rejected %d\n",
-                               task->tk_pid, __func__, n);
-               goto out_err;
-       }
        p = rpcauth_checkverf(task, p);
-       if (IS_ERR(p)) {
-               error = PTR_ERR(p);
-               dprintk("RPC: %5u %s: auth check failed with %d\n",
-                               task->tk_pid, __func__, error);
-               goto out_garbage;               /* bad verifier, retry */
-       }
+       if (IS_ERR(p))
+               goto out_verifier;
+
        len = p - (__be32 *)iov->iov_base - 1;
        if (len < 0)
-               goto out_overflow;
-       switch ((n = ntohl(*p++))) {
-       case RPC_SUCCESS:
+               goto out_unparsable;
+       switch (*p++) {
+       case rpc_success:
                return p;
-       case RPC_PROG_UNAVAIL:
-               dprintk("RPC: %5u %s: program %u is unsupported "
-                               "by server %s\n", task->tk_pid, __func__,
-                               (unsigned int)clnt->cl_prog,
-                               task->tk_xprt->servername);
+       case rpc_prog_unavail:
+               trace_rpc__prog_unavail(task);
                error = -EPFNOSUPPORT;
                goto out_err;
-       case RPC_PROG_MISMATCH:
-               dprintk("RPC: %5u %s: program %u, version %u unsupported "
-                               "by server %s\n", task->tk_pid, __func__,
-                               (unsigned int)clnt->cl_prog,
-                               (unsigned int)clnt->cl_vers,
-                               task->tk_xprt->servername);
+       case rpc_prog_mismatch:
+               trace_rpc__prog_mismatch(task);
                error = -EPROTONOSUPPORT;
                goto out_err;
-       case RPC_PROC_UNAVAIL:
-               dprintk("RPC: %5u %s: proc %s unsupported by program %u, "
-                               "version %u on server %s\n",
-                               task->tk_pid, __func__,
-                               rpc_proc_name(task),
-                               clnt->cl_prog, clnt->cl_vers,
-                               task->tk_xprt->servername);
+       case rpc_proc_unavail:
+               trace_rpc__proc_unavail(task);
                error = -EOPNOTSUPP;
                goto out_err;
-       case RPC_GARBAGE_ARGS:
-               dprintk("RPC: %5u %s: server saw garbage\n",
-                               task->tk_pid, __func__);
-               break;                  /* retry */
+       case rpc_garbage_args:
+               trace_rpc__garbage_args(task);
+               break;
        default:
-               dprintk("RPC: %5u %s: server accept status: %x\n",
-                               task->tk_pid, __func__, n);
-               /* Also retry */
+               trace_rpc__unparsable(task);
        }
 
 out_garbage:
        clnt->cl_stats->rpcgarbage++;
        if (task->tk_garb_retry) {
                task->tk_garb_retry--;
-               dprintk("RPC: %5u %s: retrying\n",
-                               task->tk_pid, __func__);
                task->tk_action = call_encode;
-out_retry:
                return ERR_PTR(-EAGAIN);
        }
 out_err:
        rpc_exit(task, error);
-       dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,
-                       __func__, error);
        return ERR_PTR(error);
-out_overflow:
-       dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid,
-                       __func__);
+
+out_badlen:
+       trace_rpc__unparsable(task);
+       error = -EIO;
+       goto out_err;
+
+out_unparsable:
+       trace_rpc__unparsable(task);
+       error = -EIO;
+       goto out_garbage;
+
+out_verifier:
+       trace_rpc_bad_verifier(task);
+       error = PTR_ERR(p);
        goto out_garbage;
+
+out_msg_denied:
+       switch (*p++) {
+       case rpc_auth_error:
+               break;
+       case rpc_mismatch:
+               trace_rpc__mismatch(task);
+               error = -EPROTONOSUPPORT;
+               goto out_err;
+       default:
+               trace_rpc__unparsable(task);
+               error = -EIO;
+               goto out_err;
+       }
+
+       switch (*p++) {
+       case rpc_autherr_rejectedcred:
+       case rpc_autherr_rejectedverf:
+       case rpcsec_gsserr_credproblem:
+       case rpcsec_gsserr_ctxproblem:
+               if (!task->tk_cred_retry)
+                       break;
+               task->tk_cred_retry--;
+               trace_rpc__stale_creds(task);
+               rpcauth_invalcred(task);
+               /* Ensure we obtain a new XID! */
+               xprt_release(task);
+               task->tk_action = call_reserve;
+               return ERR_PTR(-EAGAIN);
+       case rpc_autherr_badcred:
+       case rpc_autherr_badverf:
+               /* possibly garbled cred/verf? */
+               if (!task->tk_garb_retry)
+                       break;
+               task->tk_garb_retry--;
+               trace_rpc__bad_creds(task);
+               task->tk_action = call_encode;
+               return ERR_PTR(-EAGAIN);
+       case rpc_autherr_tooweak:
+               trace_rpc__auth_tooweak(task);
+               pr_warn("RPC: server %s requires stronger authentication.\n",
+                       task->tk_xprt->servername);
+               break;
+       default:
+               trace_rpc__unparsable(task);
+               error = -EIO;
+       }
+       goto out_err;
 }
 
 static void rpcproc_encode_null(struct rpc_rqst *rqstp, struct xdr_stream *xdr,