SUNRPC: Don't receive TCP data into a request buffer that has been reset
authorTrond Myklebust <trondmy@gmail.com>
Thu, 12 Sep 2019 12:04:25 +0000 (08:04 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Tue, 17 Sep 2019 19:14:11 +0000 (15:14 -0400)
If we've removed the request from the receive list, and have added
it back after resetting the request receive buffer, then we should
only receive message data if it is a new reply (i.e. if
transport->recv.copied is zero).

Fixes: 277e4ab7d530b ("SUNRPC: Simplify TCP receive code by switching...")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
net/sunrpc/xprtsock.c

index e2176c167a57918240b7b379621d1fe0c48cee97..9ac88722fa83ab953ba006a9c7777e7077fca532 100644 (file)
@@ -562,10 +562,14 @@ xs_read_stream_call(struct sock_xprt *transport, struct msghdr *msg, int flags)
                printk(KERN_WARNING "Callback slot table overflowed\n");
                return -ESHUTDOWN;
        }
+       if (transport->recv.copied && !req->rq_private_buf.len)
+               return -ESHUTDOWN;
 
        ret = xs_read_stream_request(transport, msg, flags, req);
        if (msg->msg_flags & (MSG_EOR|MSG_TRUNC))
                xprt_complete_bc_request(req, transport->recv.copied);
+       else
+               req->rq_private_buf.len = transport->recv.copied;
 
        return ret;
 }
@@ -587,7 +591,7 @@ xs_read_stream_reply(struct sock_xprt *transport, struct msghdr *msg, int flags)
        /* Look up and lock the request corresponding to the given XID */
        spin_lock(&xprt->queue_lock);
        req = xprt_lookup_rqst(xprt, transport->recv.xid);
-       if (!req) {
+       if (!req || (transport->recv.copied && !req->rq_private_buf.len)) {
                msg->msg_flags |= MSG_TRUNC;
                goto out;
        }
@@ -599,6 +603,8 @@ xs_read_stream_reply(struct sock_xprt *transport, struct msghdr *msg, int flags)
        spin_lock(&xprt->queue_lock);
        if (msg->msg_flags & (MSG_EOR|MSG_TRUNC))
                xprt_complete_rqst(req->rq_task, transport->recv.copied);
+       else
+               req->rq_private_buf.len = transport->recv.copied;
        xprt_unpin_rqst(req);
 out:
        spin_unlock(&xprt->queue_lock);