Merge tag 'acpi-5.1-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[sfrench/cifs-2.6.git] / net / sunrpc / clnt.c
index 4216fe33204a8e3f2634cae5ed2329335b1885da..187d10443a1584e196245afc9837add06daa1c86 100644 (file)
@@ -1730,7 +1730,12 @@ call_allocate(struct rpc_task *task)
        req->rq_callsize = RPC_CALLHDRSIZE + (auth->au_cslack << 1) +
                           proc->p_arglen;
        req->rq_callsize <<= 2;
-       req->rq_rcvsize = RPC_REPHDRSIZE + auth->au_rslack + proc->p_replen;
+       /*
+        * Note: the reply buffer must at minimum allocate enough space
+        * for the 'struct accepted_reply' from RFC5531.
+        */
+       req->rq_rcvsize = RPC_REPHDRSIZE + auth->au_rslack + \
+                       max_t(size_t, proc->p_replen, 2);
        req->rq_rcvsize <<= 2;
 
        status = xprt->ops->buf_alloc(task);
@@ -2306,6 +2311,15 @@ out_exit:
        rpc_exit(task, status);
 }
 
+static bool
+rpc_check_connected(const struct rpc_rqst *req)
+{
+       /* No allocated request or transport? return true */
+       if (!req || !req->rq_xprt)
+               return true;
+       return xprt_connected(req->rq_xprt);
+}
+
 static void
 rpc_check_timeout(struct rpc_task *task)
 {
@@ -2317,10 +2331,11 @@ rpc_check_timeout(struct rpc_task *task)
        dprintk("RPC: %5u call_timeout (major)\n", task->tk_pid);
        task->tk_timeouts++;
 
-       if (RPC_IS_SOFTCONN(task)) {
+       if (RPC_IS_SOFTCONN(task) && !rpc_check_connected(task->tk_rqstp)) {
                rpc_exit(task, -ETIMEDOUT);
                return;
        }
+
        if (RPC_IS_SOFT(task)) {
                if (clnt->cl_chatty) {
                        printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
@@ -2387,9 +2402,6 @@ call_decode(struct rpc_task *task)
        WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
                                sizeof(req->rq_rcv_buf)) != 0);
 
-       if (req->rq_rcv_buf.len < 12)
-               goto out_retry;
-
        xdr_init_decode(&xdr, &req->rq_rcv_buf,
                        req->rq_rcv_buf.head[0].iov_base, req);
        switch (rpc_decode_header(task, &xdr)) {
@@ -2400,7 +2412,6 @@ call_decode(struct rpc_task *task)
                        task->tk_pid, __func__, task->tk_status);
                return;
        case -EAGAIN:
-out_retry:
                task->tk_status = 0;
                /* Note: rpc_decode_header() may have freed the RPC slot */
                if (task->tk_rqstp == req) {
@@ -2449,7 +2460,7 @@ static noinline int
 rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr)
 {
        struct rpc_clnt *clnt = task->tk_client;
-       int error = -EACCES;
+       int error;
        __be32 *p;
 
        /* RFC-1014 says that the representation of XDR data must be a
@@ -2458,7 +2469,7 @@ rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr)
         *   undefined results
         */
        if (task->tk_rqstp->rq_rcv_buf.len & 3)
-               goto out_badlen;
+               goto out_unparsable;
 
        p = xdr_inline_decode(xdr, 3 * sizeof(*p));
        if (!p)
@@ -2492,10 +2503,12 @@ rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr)
                error = -EOPNOTSUPP;
                goto out_err;
        case rpc_garbage_args:
+       case rpc_system_err:
                trace_rpc__garbage_args(task);
+               error = -EIO;
                break;
        default:
-               trace_rpc__unparsable(task);
+               goto out_unparsable;
        }
 
 out_garbage:
@@ -2509,11 +2522,6 @@ out_err:
        rpc_exit(task, error);
        return error;
 
-out_badlen:
-       trace_rpc__unparsable(task);
-       error = -EIO;
-       goto out_err;
-
 out_unparsable:
        trace_rpc__unparsable(task);
        error = -EIO;
@@ -2524,6 +2532,7 @@ out_verifier:
        goto out_garbage;
 
 out_msg_denied:
+       error = -EACCES;
        p = xdr_inline_decode(xdr, sizeof(*p));
        if (!p)
                goto out_unparsable;
@@ -2535,9 +2544,7 @@ out_msg_denied:
                error = -EPROTONOSUPPORT;
                goto out_err;
        default:
-               trace_rpc__unparsable(task);
-               error = -EIO;
-               goto out_err;
+               goto out_unparsable;
        }
 
        p = xdr_inline_decode(xdr, sizeof(*p));
@@ -2572,8 +2579,7 @@ out_msg_denied:
                        task->tk_xprt->servername);
                break;
        default:
-               trace_rpc__unparsable(task);
-               error = -EIO;
+               goto out_unparsable;
        }
        goto out_err;
 }