SUNRPC: Don't reuse bvec on retransmission of the request
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 27 Jul 2022 17:02:27 +0000 (13:02 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 27 Jul 2022 20:26:17 +0000 (16:26 -0400)
If a request is re-encoded and then retransmitted, we need to make sure
that we also re-encode the bvec, in case the page lists have changed.

Fixes: ff053dbbaffe ("SUNRPC: Move the call to xprt_send_pagedata() out of xprt_sock_sendmsg()")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
include/linux/sunrpc/xprt.h
net/sunrpc/clnt.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c

index 0d51b9f9ea379330cc12d3179573657fc1f47e87..b9f59aabee53bf75efa20a5dafee20cefcb65d2d 100644 (file)
@@ -144,7 +144,8 @@ struct rpc_xprt_ops {
        unsigned short  (*get_srcport)(struct rpc_xprt *xprt);
        int             (*buf_alloc)(struct rpc_task *task);
        void            (*buf_free)(struct rpc_task *task);
-       int             (*prepare_request)(struct rpc_rqst *req);
+       int             (*prepare_request)(struct rpc_rqst *req,
+                                          struct xdr_buf *buf);
        int             (*send_request)(struct rpc_rqst *req);
        void            (*wait_for_reply_request)(struct rpc_task *task);
        void            (*timer)(struct rpc_xprt *xprt, struct rpc_task *task);
index bbfc47f0348037431ddf172a69f18571bbf682d0..b098e707ad4155f235046b02a355fb2e043d592a 100644 (file)
@@ -1870,7 +1870,6 @@ rpc_xdr_encode(struct rpc_task *task)
        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);
-       xdr_free_bvec(&req->rq_snd_buf);
        if (rpc_encode_header(task, &xdr))
                return;
 
index 44348c9f4b000afbf07d12090e206c41c37f3a6e..d71eec494826b269a76c887cfa82972fd805e59b 100644 (file)
@@ -73,7 +73,7 @@ static void   xprt_init(struct rpc_xprt *xprt, struct net *net);
 static __be32  xprt_alloc_xid(struct rpc_xprt *xprt);
 static void    xprt_destroy(struct rpc_xprt *xprt);
 static void    xprt_request_init(struct rpc_task *task);
-static int     xprt_request_prepare(struct rpc_rqst *req);
+static int     xprt_request_prepare(struct rpc_rqst *req, struct xdr_buf *buf);
 
 static DEFINE_SPINLOCK(xprt_list_lock);
 static LIST_HEAD(xprt_list);
@@ -1149,7 +1149,7 @@ xprt_request_enqueue_receive(struct rpc_task *task)
        if (!xprt_request_need_enqueue_receive(task, req))
                return 0;
 
-       ret = xprt_request_prepare(task->tk_rqstp);
+       ret = xprt_request_prepare(task->tk_rqstp, &req->rq_rcv_buf);
        if (ret)
                return ret;
        spin_lock(&xprt->queue_lock);
@@ -1179,8 +1179,11 @@ xprt_request_dequeue_receive_locked(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
 
-       if (test_and_clear_bit(RPC_TASK_NEED_RECV, &task->tk_runstate))
+       if (test_and_clear_bit(RPC_TASK_NEED_RECV, &task->tk_runstate)) {
                xprt_request_rb_remove(req->rq_xprt, req);
+               xdr_free_bvec(&req->rq_rcv_buf);
+               req->rq_private_buf.bvec = NULL;
+       }
 }
 
 /**
@@ -1336,8 +1339,14 @@ xprt_request_enqueue_transmit(struct rpc_task *task)
 {
        struct rpc_rqst *pos, *req = task->tk_rqstp;
        struct rpc_xprt *xprt = req->rq_xprt;
+       int ret;
 
        if (xprt_request_need_enqueue_transmit(task, req)) {
+               ret = xprt_request_prepare(task->tk_rqstp, &req->rq_snd_buf);
+               if (ret) {
+                       task->tk_status = ret;
+                       return;
+               }
                req->rq_bytes_sent = 0;
                spin_lock(&xprt->queue_lock);
                /*
@@ -1397,6 +1406,7 @@ xprt_request_dequeue_transmit_locked(struct rpc_task *task)
        } else
                list_del(&req->rq_xmit2);
        atomic_long_dec(&req->rq_xprt->xmit_queuelen);
+       xdr_free_bvec(&req->rq_snd_buf);
 }
 
 /**
@@ -1433,8 +1443,6 @@ xprt_request_dequeue_xprt(struct rpc_task *task)
            test_bit(RPC_TASK_NEED_RECV, &task->tk_runstate) ||
            xprt_is_pinned_rqst(req)) {
                spin_lock(&xprt->queue_lock);
-               xprt_request_dequeue_transmit_locked(task);
-               xprt_request_dequeue_receive_locked(task);
                while (xprt_is_pinned_rqst(req)) {
                        set_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate);
                        spin_unlock(&xprt->queue_lock);
@@ -1442,6 +1450,8 @@ xprt_request_dequeue_xprt(struct rpc_task *task)
                        spin_lock(&xprt->queue_lock);
                        clear_bit(RPC_TASK_MSG_PIN_WAIT, &task->tk_runstate);
                }
+               xprt_request_dequeue_transmit_locked(task);
+               xprt_request_dequeue_receive_locked(task);
                spin_unlock(&xprt->queue_lock);
        }
 }
@@ -1449,18 +1459,19 @@ xprt_request_dequeue_xprt(struct rpc_task *task)
 /**
  * xprt_request_prepare - prepare an encoded request for transport
  * @req: pointer to rpc_rqst
+ * @buf: pointer to send/rcv xdr_buf
  *
  * Calls into the transport layer to do whatever is needed to prepare
  * the request for transmission or receive.
  * Returns error, or zero.
  */
 static int
-xprt_request_prepare(struct rpc_rqst *req)
+xprt_request_prepare(struct rpc_rqst *req, struct xdr_buf *buf)
 {
        struct rpc_xprt *xprt = req->rq_xprt;
 
        if (xprt->ops->prepare_request)
-               return xprt->ops->prepare_request(req);
+               return xprt->ops->prepare_request(req, buf);
        return 0;
 }
 
@@ -1961,8 +1972,6 @@ void xprt_release(struct rpc_task *task)
        spin_unlock(&xprt->transport_lock);
        if (req->rq_buffer)
                xprt->ops->buf_free(task);
-       xdr_free_bvec(&req->rq_rcv_buf);
-       xdr_free_bvec(&req->rq_snd_buf);
        if (req->rq_cred != NULL)
                put_rpccred(req->rq_cred);
        if (req->rq_release_snd_buf)
index eba1be9984f89ff6952bae6db23fcab4c17e514b..e976007f4fd00f2c6238c9756370dd3231f2c98a 100644 (file)
@@ -822,17 +822,9 @@ static int xs_stream_nospace(struct rpc_rqst *req, bool vm_wait)
        return ret;
 }
 
-static int
-xs_stream_prepare_request(struct rpc_rqst *req)
+static int xs_stream_prepare_request(struct rpc_rqst *req, struct xdr_buf *buf)
 {
-       gfp_t gfp = rpc_task_gfp_mask();
-       int ret;
-
-       ret = xdr_alloc_bvec(&req->rq_snd_buf, gfp);
-       if (ret < 0)
-               return ret;
-       xdr_free_bvec(&req->rq_rcv_buf);
-       return xdr_alloc_bvec(&req->rq_rcv_buf, gfp);
+       return xdr_alloc_bvec(buf, rpc_task_gfp_mask());
 }
 
 /*