SUNRPC: Add a transport callback to handle dequeuing of an RPC request
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Tue, 12 Dec 2023 15:13:22 +0000 (16:13 +0100)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 28 Feb 2024 20:00:14 +0000 (15:00 -0500)
Add a transport level callback to allow it to handle the consequences of
dequeuing the request that was in the process of being transmitted.
For something like a TCP connection, we may need to disconnect if the
request was partially transmitted.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
include/linux/sunrpc/xprt.h
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c

index 464f6a9492ab7e2e3b8e0e5f5edc0d4f456c6636..81b952649d35e3ad4fa8c7e77388ac2ceb44ce60 100644 (file)
@@ -152,6 +152,7 @@ struct rpc_xprt_ops {
        int             (*prepare_request)(struct rpc_rqst *req,
                                           struct xdr_buf *buf);
        int             (*send_request)(struct rpc_rqst *req);
+       void            (*abort_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);
        void            (*release_request)(struct rpc_task *task);
index db3754a3298f9df7c9ef870bc588aaf19a9a119d..09f245cda5262a572c450237419c80b183a83568 100644 (file)
@@ -1398,6 +1398,12 @@ xprt_request_dequeue_transmit_locked(struct rpc_task *task)
        if (!test_and_clear_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate))
                return;
        if (!list_empty(&req->rq_xmit)) {
+               struct rpc_xprt *xprt = req->rq_xprt;
+
+               if (list_is_first(&req->rq_xmit, &xprt->xmit_queue) &&
+                   xprt->ops->abort_send_request)
+                       xprt->ops->abort_send_request(req);
+
                list_del(&req->rq_xmit);
                if (!list_empty(&req->rq_xmit2)) {
                        struct rpc_rqst *next = list_first_entry(&req->rq_xmit2,
index 1a961314b7377e6b76e1e0eac3c080934497c8ba..bb81050c870e011de2f19dd7f90c9643ff1ab6f8 100644 (file)
@@ -884,6 +884,17 @@ static int xs_stream_prepare_request(struct rpc_rqst *req, struct xdr_buf *buf)
        return xdr_alloc_bvec(buf, rpc_task_gfp_mask());
 }
 
+static void xs_stream_abort_send_request(struct rpc_rqst *req)
+{
+       struct rpc_xprt *xprt = req->rq_xprt;
+       struct sock_xprt *transport =
+               container_of(xprt, struct sock_xprt, xprt);
+
+       if (transport->xmit.offset != 0 &&
+           !test_bit(XPRT_CLOSE_WAIT, &xprt->state))
+               xprt_force_disconnect(xprt);
+}
+
 /*
  * Determine if the previous message in the stream was aborted before it
  * could complete transmission.
@@ -3029,6 +3040,7 @@ static const struct rpc_xprt_ops xs_local_ops = {
        .buf_free               = rpc_free,
        .prepare_request        = xs_stream_prepare_request,
        .send_request           = xs_local_send_request,
+       .abort_send_request     = xs_stream_abort_send_request,
        .wait_for_reply_request = xprt_wait_for_reply_request_def,
        .close                  = xs_close,
        .destroy                = xs_destroy,
@@ -3076,6 +3088,7 @@ static const struct rpc_xprt_ops xs_tcp_ops = {
        .buf_free               = rpc_free,
        .prepare_request        = xs_stream_prepare_request,
        .send_request           = xs_tcp_send_request,
+       .abort_send_request     = xs_stream_abort_send_request,
        .wait_for_reply_request = xprt_wait_for_reply_request_def,
        .close                  = xs_tcp_shutdown,
        .destroy                = xs_destroy,