Merge tag 'nfs-for-5.4-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
[sfrench/cifs-2.6.git] / net / sunrpc / clnt.c
index a07b516e503a0a8252d0f3876f38df65b812da0d..f7f78566be463ef229ffccc04b140525cf948043 100644 (file)
@@ -1837,7 +1837,7 @@ call_allocate(struct rpc_task *task)
                return;
        }
 
-       rpc_exit(task, -ERESTARTSYS);
+       rpc_call_rpcerror(task, -ERESTARTSYS);
 }
 
 static int
@@ -1862,6 +1862,7 @@ rpc_xdr_encode(struct rpc_task *task)
                     req->rq_rbuffer,
                     req->rq_rcvsize);
 
+       req->rq_reply_bytes_recvd = 0;
        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);
@@ -1881,6 +1882,8 @@ call_encode(struct rpc_task *task)
        if (!rpc_task_need_encode(task))
                goto out;
        dprint_status(task);
+       /* Dequeue task from the receive queue while we're encoding */
+       xprt_request_dequeue_xprt(task);
        /* Encode here so that rpcsec_gss can use correct sequence number. */
        rpc_xdr_encode(task);
        /* Did the encode result in an error condition? */
@@ -2479,6 +2482,7 @@ call_decode(struct rpc_task *task)
        struct rpc_clnt *clnt = task->tk_client;
        struct rpc_rqst *req = task->tk_rqstp;
        struct xdr_stream xdr;
+       int err;
 
        dprint_status(task);
 
@@ -2501,6 +2505,15 @@ call_decode(struct rpc_task *task)
         * before it changed req->rq_reply_bytes_recvd.
         */
        smp_rmb();
+
+       /*
+        * Did we ever call xprt_complete_rqst()? If not, we should assume
+        * the message is incomplete.
+        */
+       err = -EAGAIN;
+       if (!req->rq_reply_bytes_recvd)
+               goto out;
+
        req->rq_rcv_buf.len = req->rq_private_buf.len;
 
        /* Check that the softirq receive buffer is valid */
@@ -2509,7 +2522,9 @@ call_decode(struct rpc_task *task)
 
        xdr_init_decode(&xdr, &req->rq_rcv_buf,
                        req->rq_rcv_buf.head[0].iov_base, req);
-       switch (rpc_decode_header(task, &xdr)) {
+       err = rpc_decode_header(task, &xdr);
+out:
+       switch (err) {
        case 0:
                task->tk_action = rpc_exit_task;
                task->tk_status = rpcauth_unwrap_resp(task, &xdr);
@@ -2518,9 +2533,6 @@ call_decode(struct rpc_task *task)
                return;
        case -EAGAIN:
                task->tk_status = 0;
-               xdr_free_bvec(&req->rq_rcv_buf);
-               req->rq_reply_bytes_recvd = 0;
-               req->rq_rcv_buf.len = 0;
                if (task->tk_client->cl_discrtry)
                        xprt_conditional_disconnect(req->rq_xprt,
                                                    req->rq_connect_cookie);
@@ -2561,7 +2573,7 @@ rpc_encode_header(struct rpc_task *task, struct xdr_stream *xdr)
        return 0;
 out_fail:
        trace_rpc_bad_callhdr(task);
-       rpc_exit(task, error);
+       rpc_call_rpcerror(task, error);
        return error;
 }
 
@@ -2628,7 +2640,7 @@ out_garbage:
                return -EAGAIN;
        }
 out_err:
-       rpc_exit(task, error);
+       rpc_call_rpcerror(task, error);
        return error;
 
 out_unparsable: