rxrpc: Fix connection-level abort handling
authorDavid Howells <dhowells@redhat.com>
Mon, 8 Oct 2018 14:46:17 +0000 (15:46 +0100)
committerDavid Howells <dhowells@redhat.com>
Mon, 8 Oct 2018 21:42:04 +0000 (22:42 +0100)
Fix connection-level abort handling to cache the abort and error codes
properly so that a new incoming call can be properly aborted if it races
with the parent connection being aborted by another CPU.

The abort_code and error parameters can then be dropped from
rxrpc_abort_calls().

Fixes: f5c17aaeb2ae ("rxrpc: Calls should only have one terminal state")
Signed-off-by: David Howells <dhowells@redhat.com>
net/rxrpc/ar-internal.h
net/rxrpc/call_accept.c
net/rxrpc/conn_event.c

index ab60c0313fd47e5c062381b9bb6e2e708f0396f7..45307463b7ddc58fe62e85b205fde3d65195499a 100644 (file)
@@ -442,8 +442,7 @@ struct rxrpc_connection {
        spinlock_t              state_lock;     /* state-change lock */
        enum rxrpc_conn_cache_state cache_state;
        enum rxrpc_conn_proto_state state;      /* current state of connection */
-       u32                     local_abort;    /* local abort code */
-       u32                     remote_abort;   /* remote abort code */
+       u32                     abort_code;     /* Abort code of connection abort */
        int                     debug_id;       /* debug ID for printks */
        atomic_t                serial;         /* packet serial number counter */
        unsigned int            hi_serial;      /* highest serial number received */
@@ -453,6 +452,7 @@ struct rxrpc_connection {
        u8                      security_size;  /* security header size */
        u8                      security_ix;    /* security type */
        u8                      out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */
+       short                   error;          /* Local error code */
 };
 
 static inline bool rxrpc_to_server(const struct rxrpc_skb_priv *sp)
index f55f67894465e70288e519d6ead1e1151ceb36eb..1c4ebc0cb25b70775fd4264ed55da51119717147 100644 (file)
@@ -405,11 +405,11 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
 
        case RXRPC_CONN_REMOTELY_ABORTED:
                rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED,
-                                         conn->remote_abort, -ECONNABORTED);
+                                         conn->abort_code, conn->error);
                break;
        case RXRPC_CONN_LOCALLY_ABORTED:
                rxrpc_abort_call("CON", call, sp->hdr.seq,
-                                conn->local_abort, -ECONNABORTED);
+                                conn->abort_code, conn->error);
                break;
        default:
                BUG();
index 6df56ce68861670a7352e37a0a6095fd979d30fd..b6fca8ebb1173f4de1047e96315c26072666c2e9 100644 (file)
@@ -126,7 +126,7 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
 
        switch (chan->last_type) {
        case RXRPC_PACKET_TYPE_ABORT:
-               _proto("Tx ABORT %%%u { %d } [re]", serial, conn->local_abort);
+               _proto("Tx ABORT %%%u { %d } [re]", serial, conn->abort_code);
                break;
        case RXRPC_PACKET_TYPE_ACK:
                trace_rxrpc_tx_ack(chan->call_debug_id, serial,
@@ -153,13 +153,12 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
  * pass a connection-level abort onto all calls on that connection
  */
 static void rxrpc_abort_calls(struct rxrpc_connection *conn,
-                             enum rxrpc_call_completion compl,
-                             u32 abort_code, int error)
+                             enum rxrpc_call_completion compl)
 {
        struct rxrpc_call *call;
        int i;
 
-       _enter("{%d},%x", conn->debug_id, abort_code);
+       _enter("{%d},%x", conn->debug_id, conn->abort_code);
 
        spin_lock(&conn->channel_lock);
 
@@ -172,9 +171,11 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn,
                                trace_rxrpc_abort(call->debug_id,
                                                  "CON", call->cid,
                                                  call->call_id, 0,
-                                                 abort_code, error);
+                                                 conn->abort_code,
+                                                 conn->error);
                        if (rxrpc_set_call_completion(call, compl,
-                                                     abort_code, error))
+                                                     conn->abort_code,
+                                                     conn->error))
                                rxrpc_notify_socket(call);
                }
        }
@@ -207,10 +208,12 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
                return 0;
        }
 
+       conn->error = error;
+       conn->abort_code = abort_code;
        conn->state = RXRPC_CONN_LOCALLY_ABORTED;
        spin_unlock_bh(&conn->state_lock);
 
-       rxrpc_abort_calls(conn, RXRPC_CALL_LOCALLY_ABORTED, abort_code, error);
+       rxrpc_abort_calls(conn, RXRPC_CALL_LOCALLY_ABORTED);
 
        msg.msg_name    = &conn->params.peer->srx.transport;
        msg.msg_namelen = conn->params.peer->srx.transport_len;
@@ -229,7 +232,7 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
        whdr._rsvd      = 0;
        whdr.serviceId  = htons(conn->service_id);
 
-       word            = htonl(conn->local_abort);
+       word            = htonl(conn->abort_code);
 
        iov[0].iov_base = &whdr;
        iov[0].iov_len  = sizeof(whdr);
@@ -240,7 +243,7 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
 
        serial = atomic_inc_return(&conn->serial);
        whdr.serial = htonl(serial);
-       _proto("Tx CONN ABORT %%%u { %d }", serial, conn->local_abort);
+       _proto("Tx CONN ABORT %%%u { %d }", serial, conn->abort_code);
 
        ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
        if (ret < 0) {
@@ -315,9 +318,10 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
                abort_code = ntohl(wtmp);
                _proto("Rx ABORT %%%u { ac=%d }", sp->hdr.serial, abort_code);
 
+               conn->error = -ECONNABORTED;
+               conn->abort_code = abort_code;
                conn->state = RXRPC_CONN_REMOTELY_ABORTED;
-               rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED,
-                                 abort_code, -ECONNABORTED);
+               rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED);
                return -ECONNABORTED;
 
        case RXRPC_PACKET_TYPE_CHALLENGE: