get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/807070/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 807070,
    "url": "http://patchwork.ozlabs.org/api/patches/807070/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/150400965727.21371.231552212599612769.stgit@warthog.procyon.org.uk/",
    "project": {
        "id": 7,
        "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api",
        "name": "Linux network development",
        "link_name": "netdev",
        "list_id": "netdev.vger.kernel.org",
        "list_email": "netdev@vger.kernel.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<150400965727.21371.231552212599612769.stgit@warthog.procyon.org.uk>",
    "list_archive_url": null,
    "date": "2017-08-29T12:27:37",
    "name": "[net-next,7/7] rxrpc: Allow failed client calls to be retried",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "7864802d45a6684d3c02f10b0b7cf665d7cb3c5c",
    "submitter": {
        "id": 59,
        "url": "http://patchwork.ozlabs.org/api/people/59/?format=api",
        "name": "David Howells",
        "email": "dhowells@redhat.com"
    },
    "delegate": {
        "id": 34,
        "url": "http://patchwork.ozlabs.org/api/users/34/?format=api",
        "username": "davem",
        "first_name": "David",
        "last_name": "Miller",
        "email": "davem@davemloft.net"
    },
    "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/150400965727.21371.231552212599612769.stgit@warthog.procyon.org.uk/mbox/",
    "series": [
        {
            "id": 358,
            "url": "http://patchwork.ozlabs.org/api/series/358/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/netdev/list/?series=358",
            "date": "2017-08-29T12:27:14",
            "name": "rxrpc: Miscellany",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/358/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/807070/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/807070/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<netdev-owner@vger.kernel.org>",
        "X-Original-To": "patchwork-incoming@ozlabs.org",
        "Delivered-To": "patchwork-incoming@ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=netdev-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)",
            "ext-mx04.extmail.prod.ext.phx2.redhat.com;\n\tdmarc=none (p=none dis=none) header.from=redhat.com",
            "ext-mx04.extmail.prod.ext.phx2.redhat.com;\n\tspf=fail smtp.mailfrom=dhowells@redhat.com"
        ],
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xhSZx3JVwz9t1t\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 29 Aug 2017 22:27:53 +1000 (AEST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1753967AbdH2M1l (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tTue, 29 Aug 2017 08:27:41 -0400",
            "from mx1.redhat.com ([209.132.183.28]:60672 \"EHLO mx1.redhat.com\"\n\trhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP\n\tid S1751737AbdH2M1j (ORCPT <rfc822;netdev@vger.kernel.org>);\n\tTue, 29 Aug 2017 08:27:39 -0400",
            "from smtp.corp.redhat.com\n\t(int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby mx1.redhat.com (Postfix) with ESMTPS id EACCD80469;\n\tTue, 29 Aug 2017 12:27:38 +0000 (UTC)",
            "from warthog.procyon.org.uk (ovpn-120-50.rdu2.redhat.com\n\t[10.10.120.50])\n\tby smtp.corp.redhat.com (Postfix) with ESMTP id E794B7064E;\n\tTue, 29 Aug 2017 12:27:37 +0000 (UTC)"
        ],
        "DMARC-Filter": "OpenDMARC Filter v1.3.2 mx1.redhat.com EACCD80469",
        "Organization": "Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley\n\tPlace, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United\n\tKingdom.\n\tRegistered in England and Wales under Company Registration No.\n\t3798903",
        "Subject": "[PATCH net-next 7/7] rxrpc: Allow failed client calls to be retried",
        "From": "David Howells <dhowells@redhat.com>",
        "To": "netdev@vger.kernel.org",
        "Cc": "dhowells@redhat.com, linux-afs@lists.infradead.org,\n\tlinux-kernel@vger.kernel.org",
        "Date": "Tue, 29 Aug 2017 13:27:37 +0100",
        "Message-ID": "<150400965727.21371.231552212599612769.stgit@warthog.procyon.org.uk>",
        "In-Reply-To": "<150400960745.21371.15455867950162722742.stgit@warthog.procyon.org.uk>",
        "References": "<150400960745.21371.15455867950162722742.stgit@warthog.procyon.org.uk>",
        "User-Agent": "StGit/0.17.1-dirty",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "7bit",
        "X-Scanned-By": "MIMEDefang 2.79 on 10.5.11.12",
        "X-Greylist": "Sender IP whitelisted, not delayed by milter-greylist-4.5.16\n\t(mx1.redhat.com [10.5.110.28]);\n\tTue, 29 Aug 2017 12:27:39 +0000 (UTC)",
        "Sender": "netdev-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<netdev.vger.kernel.org>",
        "X-Mailing-List": "netdev@vger.kernel.org"
    },
    "content": "Allow a client call that failed on network error to be retried, provided\nthat the Tx queue still holds DATA packet 1.  This allows an operation to\nbe submitted to another server or another address for the same server\nwithout having to repackage and re-encrypt the data so far processed.\n\nTwo new functions are provided:\n\n (1) rxrpc_kernel_check_call() - This is used to find out the completion\n     state of a call to guess whether it can be retried and whether it\n     should be retried.\n\n (2) rxrpc_kernel_retry_call() - Disconnect the call from its current\n     connection, reset the state and submit it as a new client call to a\n     new address.  The new address need not match the previous address.\n\nA call may be retried even if all the data hasn't been loaded into it yet;\na partially constructed will be retained at the same point it was at when\nan error condition was detected.  msg_data_left() can be used to find out\nhow much data was packaged before the error occurred.\n\nSigned-off-by: David Howells <dhowells@redhat.com>\n---\n\n Documentation/networking/rxrpc.txt |   45 ++++++++++++++++\n include/net/af_rxrpc.h             |   16 ++++++\n net/rxrpc/af_rxrpc.c               |   69 ++++++++++++++++++++++++\n net/rxrpc/ar-internal.h            |   19 ++-----\n net/rxrpc/call_object.c            |  102 ++++++++++++++++++++++++++++++++++--\n net/rxrpc/conn_client.c            |   17 +++++-\n net/rxrpc/sendmsg.c                |   24 +++++---\n 7 files changed, 261 insertions(+), 31 deletions(-)",
    "diff": "diff --git a/Documentation/networking/rxrpc.txt b/Documentation/networking/rxrpc.txt\nindex 92a3c3bd5ac3..810620153a44 100644\n--- a/Documentation/networking/rxrpc.txt\n+++ b/Documentation/networking/rxrpc.txt\n@@ -975,6 +975,51 @@ The kernel interface functions are as follows:\n      size should be set when the call is begun.  tx_total_len may not be less\n      than zero.\n \n+ (*) Check to see the completion state of a call so that the caller can assess\n+     whether it needs to be retried.\n+\n+\tenum rxrpc_call_completion {\n+\t\tRXRPC_CALL_SUCCEEDED,\n+\t\tRXRPC_CALL_REMOTELY_ABORTED,\n+\t\tRXRPC_CALL_LOCALLY_ABORTED,\n+\t\tRXRPC_CALL_LOCAL_ERROR,\n+\t\tRXRPC_CALL_NETWORK_ERROR,\n+\t};\n+\n+\tint rxrpc_kernel_check_call(struct socket *sock, struct rxrpc_call *call,\n+\t\t\t\t    enum rxrpc_call_completion *_compl,\n+\t\t\t\t    u32 *_abort_code);\n+\n+     On return, -EINPROGRESS will be returned if the call is still ongoing; if\n+     it is finished, *_compl will be set to indicate the manner of completion,\n+     *_abort_code will be set to any abort code that occurred.  0 will be\n+     returned on a successful completion, -ECONNABORTED will be returned if the\n+     client failed due to a remote abort and anything else will return an\n+     appropriate error code.\n+\n+     The caller should look at this information to decide if it's worth\n+     retrying the call.\n+\n+ (*) Retry a client call.\n+\n+\tint rxrpc_kernel_retry_call(struct socket *sock,\n+\t\t\t\t    struct rxrpc_call *call,\n+\t\t\t\t    struct sockaddr_rxrpc *srx,\n+\t\t\t\t    struct key *key);\n+\n+     This attempts to partially reinitialise a call and submit it again whilst\n+     reusing the original call's Tx queue to avoid the need to repackage and\n+     re-encrypt the data to be sent.  call indicates the call to retry, srx the\n+     new address to send it to and key the encryption key to use for signing or\n+     encrypting the packets.\n+\n+     For this to work, the first Tx data packet must still be in the transmit\n+     queue, and currently this is only permitted for local and network errors\n+     and the call must not have been aborted.  Any partially constructed Tx\n+     packet is left as is and can continue being filled afterwards.\n+\n+     It returns 0 if the call was requeued and an error otherwise.\n+\n \n =======================\n CONFIGURABLE PARAMETERS\ndiff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h\nindex 07a47ee6f783..3ac79150291f 100644\n--- a/include/net/af_rxrpc.h\n+++ b/include/net/af_rxrpc.h\n@@ -19,6 +19,18 @@ struct sock;\n struct socket;\n struct rxrpc_call;\n \n+/*\n+ * Call completion condition (state == RXRPC_CALL_COMPLETE).\n+ */\n+enum rxrpc_call_completion {\n+\tRXRPC_CALL_SUCCEEDED,\t\t/* - Normal termination */\n+\tRXRPC_CALL_REMOTELY_ABORTED,\t/* - call aborted by peer */\n+\tRXRPC_CALL_LOCALLY_ABORTED,\t/* - call aborted locally on error or close */\n+\tRXRPC_CALL_LOCAL_ERROR,\t\t/* - call failed due to local error */\n+\tRXRPC_CALL_NETWORK_ERROR,\t/* - call terminated by network error */\n+\tNR__RXRPC_CALL_COMPLETIONS\n+};\n+\n typedef void (*rxrpc_notify_rx_t)(struct sock *, struct rxrpc_call *,\n \t\t\t\t  unsigned long);\n typedef void (*rxrpc_notify_end_tx_t)(struct sock *, struct rxrpc_call *,\n@@ -51,5 +63,9 @@ void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *,\n int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t,\n \t\t\t       rxrpc_user_attach_call_t, unsigned long, gfp_t);\n void rxrpc_kernel_set_tx_length(struct socket *, struct rxrpc_call *, s64);\n+int rxrpc_kernel_retry_call(struct socket *, struct rxrpc_call *,\n+\t\t\t    struct sockaddr_rxrpc *, struct key *);\n+int rxrpc_kernel_check_call(struct socket *, struct rxrpc_call *,\n+\t\t\t    enum rxrpc_call_completion *, u32 *);\n \n #endif /* _NET_RXRPC_H */\ndiff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c\nindex 31e97f714ca9..fb17552fd292 100644\n--- a/net/rxrpc/af_rxrpc.c\n+++ b/net/rxrpc/af_rxrpc.c\n@@ -337,6 +337,75 @@ void rxrpc_kernel_end_call(struct socket *sock, struct rxrpc_call *call)\n EXPORT_SYMBOL(rxrpc_kernel_end_call);\n \n /**\n+ * rxrpc_kernel_check_call - Check a call's state\n+ * @sock: The socket the call is on\n+ * @call: The call to check\n+ * @_compl: Where to store the completion state\n+ * @_abort_code: Where to store any abort code\n+ *\n+ * Allow a kernel service to query the state of a call and find out the manner\n+ * of its termination if it has completed.  Returns -EINPROGRESS if the call is\n+ * still going, 0 if the call finished successfully, -ECONNABORTED if the call\n+ * was aborted and an appropriate error if the call failed in some other way.\n+ */\n+int rxrpc_kernel_check_call(struct socket *sock, struct rxrpc_call *call,\n+\t\t\t    enum rxrpc_call_completion *_compl, u32 *_abort_code)\n+{\n+\tif (call->state != RXRPC_CALL_COMPLETE)\n+\t\treturn -EINPROGRESS;\n+\tsmp_rmb();\n+\t*_compl = call->completion;\n+\t*_abort_code = call->abort_code;\n+\treturn call->error;\n+}\n+EXPORT_SYMBOL(rxrpc_kernel_check_call);\n+\n+/**\n+ * rxrpc_kernel_retry_call - Allow a kernel service to retry a call\n+ * @sock: The socket the call is on\n+ * @call: The call to retry\n+ * @srx: The address of the peer to contact\n+ * @key: The security context to use (defaults to socket setting)\n+ *\n+ * Allow a kernel service to try resending a client call that failed due to a\n+ * network error to a new address.  The Tx queue is maintained intact, thereby\n+ * relieving the need to re-encrypt any request data that has already been\n+ * buffered.\n+ */\n+int rxrpc_kernel_retry_call(struct socket *sock, struct rxrpc_call *call,\n+\t\t\t    struct sockaddr_rxrpc *srx, struct key *key)\n+{\n+\tstruct rxrpc_conn_parameters cp;\n+\tstruct rxrpc_sock *rx = rxrpc_sk(sock->sk);\n+\tint ret;\n+\n+\t_enter(\"%d{%d}\", call->debug_id, atomic_read(&call->usage));\n+\n+\tif (!key)\n+\t\tkey = rx->key;\n+\tif (key && !key->payload.data[0])\n+\t\tkey = NULL; /* a no-security key */\n+\n+\tmemset(&cp, 0, sizeof(cp));\n+\tcp.local\t\t= rx->local;\n+\tcp.key\t\t\t= key;\n+\tcp.security_level\t= 0;\n+\tcp.exclusive\t\t= false;\n+\tcp.service_id\t\t= srx->srx_service;\n+\n+\tmutex_lock(&call->user_mutex);\n+\n+\tret = rxrpc_prepare_call_for_retry(rx, call);\n+\tif (ret == 0)\n+\t\tret = rxrpc_retry_client_call(rx, call, &cp, srx, GFP_KERNEL);\n+\n+\tmutex_unlock(&call->user_mutex);\n+\t_leave(\" = %d\", ret);\n+\treturn ret;\n+}\n+EXPORT_SYMBOL(rxrpc_kernel_retry_call);\n+\n+/**\n  * rxrpc_kernel_new_call_notification - Get notifications of new calls\n  * @sock: The socket to intercept received messages on\n  * @notify_new_call: Function to be called when new calls appear\ndiff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h\nindex 227e24794055..ea5600b747cc 100644\n--- a/net/rxrpc/ar-internal.h\n+++ b/net/rxrpc/ar-internal.h\n@@ -445,6 +445,7 @@ enum rxrpc_call_flag {\n \tRXRPC_CALL_EXPOSED,\t\t/* The call was exposed to the world */\n \tRXRPC_CALL_RX_LAST,\t\t/* Received the last packet (at rxtx_top) */\n \tRXRPC_CALL_TX_LAST,\t\t/* Last packet in Tx buffer (at rxtx_top) */\n+\tRXRPC_CALL_TX_LASTQ,\t\t/* Last packet has been queued */\n \tRXRPC_CALL_SEND_PING,\t\t/* A ping will need to be sent */\n \tRXRPC_CALL_PINGING,\t\t/* Ping in process */\n \tRXRPC_CALL_RETRANS_TIMEOUT,\t/* Retransmission due to timeout occurred */\n@@ -482,18 +483,6 @@ enum rxrpc_call_state {\n };\n \n /*\n- * Call completion condition (state == RXRPC_CALL_COMPLETE).\n- */\n-enum rxrpc_call_completion {\n-\tRXRPC_CALL_SUCCEEDED,\t\t/* - Normal termination */\n-\tRXRPC_CALL_REMOTELY_ABORTED,\t/* - call aborted by peer */\n-\tRXRPC_CALL_LOCALLY_ABORTED,\t/* - call aborted locally on error or close */\n-\tRXRPC_CALL_LOCAL_ERROR,\t\t/* - call failed due to local error */\n-\tRXRPC_CALL_NETWORK_ERROR,\t/* - call terminated by network error */\n-\tNR__RXRPC_CALL_COMPLETIONS\n-};\n-\n-/*\n  * Call Tx congestion management modes.\n  */\n enum rxrpc_congest_mode {\n@@ -687,9 +676,15 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *,\n \t\t\t\t\t struct rxrpc_conn_parameters *,\n \t\t\t\t\t struct sockaddr_rxrpc *,\n \t\t\t\t\t unsigned long, s64, gfp_t);\n+int rxrpc_retry_client_call(struct rxrpc_sock *,\n+\t\t\t    struct rxrpc_call *,\n+\t\t\t    struct rxrpc_conn_parameters *,\n+\t\t\t    struct sockaddr_rxrpc *,\n+\t\t\t    gfp_t);\n void rxrpc_incoming_call(struct rxrpc_sock *, struct rxrpc_call *,\n \t\t\t struct sk_buff *);\n void rxrpc_release_call(struct rxrpc_sock *, struct rxrpc_call *);\n+int rxrpc_prepare_call_for_retry(struct rxrpc_sock *, struct rxrpc_call *);\n void rxrpc_release_calls_on_socket(struct rxrpc_sock *);\n bool __rxrpc_queue_call(struct rxrpc_call *);\n bool rxrpc_queue_call(struct rxrpc_call *);\ndiff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c\nindex d7809a0620b4..fcdd6555a820 100644\n--- a/net/rxrpc/call_object.c\n+++ b/net/rxrpc/call_object.c\n@@ -269,11 +269,6 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,\n \ttrace_rxrpc_call(call, rxrpc_call_connected, atomic_read(&call->usage),\n \t\t\t here, NULL);\n \n-\tspin_lock_bh(&call->conn->params.peer->lock);\n-\thlist_add_head(&call->error_link,\n-\t\t       &call->conn->params.peer->error_targets);\n-\tspin_unlock_bh(&call->conn->params.peer->lock);\n-\n \trxrpc_start_call_timer(call);\n \n \t_net(\"CALL new %d on CONN %d\", call->debug_id, call->conn->debug_id);\n@@ -304,6 +299,48 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,\n }\n \n /*\n+ * Retry a call to a new address.  It is expected that the Tx queue of the call\n+ * will contain data previously packaged for an old call.\n+ */\n+int rxrpc_retry_client_call(struct rxrpc_sock *rx,\n+\t\t\t    struct rxrpc_call *call,\n+\t\t\t    struct rxrpc_conn_parameters *cp,\n+\t\t\t    struct sockaddr_rxrpc *srx,\n+\t\t\t    gfp_t gfp)\n+{\n+\tconst void *here = __builtin_return_address(0);\n+\tint ret;\n+\n+\t/* Set up or get a connection record and set the protocol parameters,\n+\t * including channel number and call ID.\n+\t */\n+\tret = rxrpc_connect_call(call, cp, srx, gfp);\n+\tif (ret < 0)\n+\t\tgoto error;\n+\n+\ttrace_rxrpc_call(call, rxrpc_call_connected, atomic_read(&call->usage),\n+\t\t\t here, NULL);\n+\n+\trxrpc_start_call_timer(call);\n+\n+\t_net(\"CALL new %d on CONN %d\", call->debug_id, call->conn->debug_id);\n+\n+\tif (!test_and_set_bit(RXRPC_CALL_EV_RESEND, &call->events))\n+\t\trxrpc_queue_call(call);\n+\n+\t_leave(\" = 0\");\n+\treturn 0;\n+\n+error:\n+\trxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR,\n+\t\t\t\t  RX_CALL_DEAD, ret);\n+\ttrace_rxrpc_call(call, rxrpc_call_error, atomic_read(&call->usage),\n+\t\t\t here, ERR_PTR(ret));\n+\t_leave(\" = %d\", ret);\n+\treturn ret;\n+}\n+\n+/*\n  * Set up an incoming call.  call->conn points to the connection.\n  * This is called in BH context and isn't allowed to fail.\n  */\n@@ -471,6 +508,61 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)\n }\n \n /*\n+ * Prepare a kernel service call for retry.\n+ */\n+int rxrpc_prepare_call_for_retry(struct rxrpc_sock *rx, struct rxrpc_call *call)\n+{\n+\tconst void *here = __builtin_return_address(0);\n+\tint i;\n+\tu8 last = 0;\n+\n+\t_enter(\"{%d,%d}\", call->debug_id, atomic_read(&call->usage));\n+\n+\ttrace_rxrpc_call(call, rxrpc_call_release, atomic_read(&call->usage),\n+\t\t\t here, (const void *)call->flags);\n+\n+\tASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);\n+\tASSERTCMP(call->completion, !=, RXRPC_CALL_REMOTELY_ABORTED);\n+\tASSERTCMP(call->completion, !=, RXRPC_CALL_LOCALLY_ABORTED);\n+\tASSERT(list_empty(&call->recvmsg_link));\n+\n+\tdel_timer_sync(&call->timer);\n+\n+\t_debug(\"RELEASE CALL %p (%d CONN %p)\", call, call->debug_id, call->conn);\n+\n+\tif (call->conn)\n+\t\trxrpc_disconnect_call(call);\n+\n+\tif (rxrpc_is_service_call(call) ||\n+\t    !call->tx_phase ||\n+\t    call->tx_hard_ack != 0 ||\n+\t    call->rx_hard_ack != 0 ||\n+\t    call->rx_top != 0)\n+\t\treturn -EINVAL;\n+\n+\tcall->state = RXRPC_CALL_UNINITIALISED;\n+\tcall->completion = RXRPC_CALL_SUCCEEDED;\n+\tcall->call_id = 0;\n+\tcall->cid = 0;\n+\tcall->cong_cwnd = 0;\n+\tcall->cong_extra = 0;\n+\tcall->cong_ssthresh = 0;\n+\tcall->cong_mode = 0;\n+\tcall->cong_dup_acks = 0;\n+\tcall->cong_cumul_acks = 0;\n+\tcall->acks_lowest_nak = 0;\n+\n+\tfor (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) {\n+\t\tlast |= call->rxtx_annotations[i];\n+\t\tcall->rxtx_annotations[i] &= RXRPC_TX_ANNO_LAST;\n+\t\tcall->rxtx_annotations[i] |= RXRPC_TX_ANNO_RETRANS;\n+\t}\n+\n+\t_leave(\" = 0\");\n+\treturn 0;\n+}\n+\n+/*\n  * release all the calls associated with a socket\n  */\n void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)\ndiff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c\nindex eb2157680399..5f9624bd311c 100644\n--- a/net/rxrpc/conn_client.c\n+++ b/net/rxrpc/conn_client.c\n@@ -555,7 +555,10 @@ static void rxrpc_activate_one_channel(struct rxrpc_connection *conn,\n \ttrace_rxrpc_client(conn, channel, rxrpc_client_chan_activate);\n \n \twrite_lock_bh(&call->state_lock);\n-\tcall->state = RXRPC_CALL_CLIENT_SEND_REQUEST;\n+\tif (!test_bit(RXRPC_CALL_TX_LASTQ, &call->flags))\n+\t\tcall->state = RXRPC_CALL_CLIENT_SEND_REQUEST;\n+\telse\n+\t\tcall->state = RXRPC_CALL_CLIENT_AWAIT_REPLY;\n \twrite_unlock_bh(&call->state_lock);\n \n \trxrpc_see_call(call);\n@@ -688,15 +691,23 @@ int rxrpc_connect_call(struct rxrpc_call *call,\n \n \tret = rxrpc_get_client_conn(call, cp, srx, gfp);\n \tif (ret < 0)\n-\t\treturn ret;\n+\t\tgoto out;\n \n \trxrpc_animate_client_conn(rxnet, call->conn);\n \trxrpc_activate_channels(call->conn);\n \n \tret = rxrpc_wait_for_channel(call, gfp);\n-\tif (ret < 0)\n+\tif (ret < 0) {\n \t\trxrpc_disconnect_client_call(call);\n+\t\tgoto out;\n+\t}\n+\n+\tspin_lock_bh(&call->conn->params.peer->lock);\n+\thlist_add_head(&call->error_link,\n+\t\t       &call->conn->params.peer->error_targets);\n+\tspin_unlock_bh(&call->conn->params.peer->lock);\n \n+out:\n \t_leave(\" = %d\", ret);\n \treturn ret;\n }\ndiff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c\nindex 344fdce89823..9ea6f972767e 100644\n--- a/net/rxrpc/sendmsg.c\n+++ b/net/rxrpc/sendmsg.c\n@@ -128,8 +128,10 @@ static void rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,\n \n \tASSERTCMP(seq, ==, call->tx_top + 1);\n \n-\tif (last)\n+\tif (last) {\n \t\tannotation |= RXRPC_TX_ANNO_LAST;\n+\t\tset_bit(RXRPC_CALL_TX_LASTQ, &call->flags);\n+\t}\n \n \t/* We have to set the timestamp before queueing as the retransmit\n \t * algorithm can see the packet as soon as we queue it.\n@@ -326,11 +328,6 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t\t\t\tcall->tx_total_len -= copy;\n \t\t}\n \n-\t\t/* check for the far side aborting the call or a network error\n-\t\t * occurring */\n-\t\tif (call->state == RXRPC_CALL_COMPLETE)\n-\t\t\tgoto call_terminated;\n-\n \t\t/* add the packet to the send queue if it's now full */\n \t\tif (sp->remain <= 0 ||\n \t\t    (msg_data_left(msg) == 0 && !more)) {\n@@ -370,6 +367,16 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t\t\t\t\t   notify_end_tx);\n \t\t\tskb = NULL;\n \t\t}\n+\n+\t\t/* Check for the far side aborting the call or a network error\n+\t\t * occurring.  If this happens, save any packet that was under\n+\t\t * construction so that in the case of a network error, the\n+\t\t * call can be retried or redirected.\n+\t\t */\n+\t\tif (call->state == RXRPC_CALL_COMPLETE) {\n+\t\t\tret = call->error;\n+\t\t\tgoto out;\n+\t\t}\n \t} while (msg_data_left(msg) > 0);\n \n success:\n@@ -379,11 +386,6 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,\n \t_leave(\" = %d\", ret);\n \treturn ret;\n \n-call_terminated:\n-\trxrpc_free_skb(skb, rxrpc_skb_tx_freed);\n-\t_leave(\" = %d\", call->error);\n-\treturn call->error;\n-\n maybe_error:\n \tif (copied)\n \t\tgoto success;\n",
    "prefixes": [
        "net-next",
        "7/7"
    ]
}