net/smc: cancel send and receive for terminated socket
authorUrsula Braun <ubraun@linux.ibm.com>
Mon, 21 Oct 2019 14:13:08 +0000 (16:13 +0200)
committerJakub Kicinski <jakub.kicinski@netronome.com>
Tue, 22 Oct 2019 18:23:43 +0000 (11:23 -0700)
The resources for a terminated socket are being cleaned up.
This patch makes sure
* no more data is received for an actively terminated socket
* no more data is sent for an actively or passively terminated socket

Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
net/smc/smc.h
net/smc/smc_cdc.c
net/smc/smc_close.c
net/smc/smc_core.c
net/smc/smc_rx.c
net/smc/smc_tx.c

index 878313f..be11ba4 100644 (file)
@@ -188,6 +188,7 @@ struct smc_connection {
                                                 * 0 for SMC-R, 32 for SMC-D
                                                 */
        u64                     peer_token;     /* SMC-D token of peer */
+       u8                      killed : 1;     /* abnormal termination */
 };
 
 struct smc_sock {                              /* smc sock container */
index d0b0f4c..7dc07ec 100644 (file)
@@ -63,7 +63,7 @@ int smc_cdc_get_free_slot(struct smc_connection *conn,
        rc = smc_wr_tx_get_free_slot(link, smc_cdc_tx_handler, wr_buf,
                                     wr_rdma_buf,
                                     (struct smc_wr_tx_pend_priv **)pend);
-       if (!conn->alert_token_local)
+       if (conn->killed)
                /* abnormal termination */
                rc = -EPIPE;
        return rc;
@@ -328,7 +328,7 @@ static void smcd_cdc_rx_tsklet(unsigned long data)
        struct smcd_cdc_msg cdc;
        struct smc_sock *smc;
 
-       if (!conn)
+       if (!conn || conn->killed)
                return;
 
        data_cdc = (struct smcd_cdc_msg *)conn->rmb_desc->cpu_addr;
index 1a858e5..1d706c5 100644 (file)
@@ -66,7 +66,8 @@ static void smc_close_stream_wait(struct smc_sock *smc, long timeout)
                rc = sk_wait_event(sk, &timeout,
                                   !smc_tx_prepared_sends(&smc->conn) ||
                                   sk->sk_err == ECONNABORTED ||
-                                  sk->sk_err == ECONNRESET,
+                                  sk->sk_err == ECONNRESET ||
+                                  smc->conn.killed,
                                   &wait);
                if (rc)
                        break;
@@ -95,6 +96,8 @@ static int smc_close_final(struct smc_connection *conn)
                conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1;
        else
                conn->local_tx_ctrl.conn_state_flags.peer_conn_closed = 1;
+       if (conn->killed)
+               return -EPIPE;
 
        return smc_cdc_get_slot_and_msg_send(conn);
 }
@@ -326,7 +329,7 @@ static void smc_close_passive_work(struct work_struct *work)
        lock_sock(sk);
        old_state = sk->sk_state;
 
-       if (!conn->alert_token_local) {
+       if (conn->killed) {
                /* abnormal termination */
                smc_close_active_abort(smc);
                goto wakeup;
index de9bf03..4ee0e33 100644 (file)
@@ -500,6 +500,7 @@ static void __smc_lgr_terminate(struct smc_link_group *lgr)
                conn = rb_entry(node, struct smc_connection, alert_node);
                smc = container_of(conn, struct smc_sock, conn);
                sock_hold(&smc->sk); /* sock_put in close work */
+               conn->killed = 1;
                conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1;
                __smc_lgr_unregister_conn(conn);
                conn->lgr = NULL;
index 97e8369..39d7b34 100644 (file)
@@ -201,6 +201,8 @@ int smc_rx_wait(struct smc_sock *smc, long *timeo,
 {
        DEFINE_WAIT_FUNC(wait, woken_wake_function);
        struct smc_connection *conn = &smc->conn;
+       struct smc_cdc_conn_state_flags *cflags =
+                                       &conn->local_tx_ctrl.conn_state_flags;
        struct sock *sk = &smc->sk;
        int rc;
 
@@ -210,7 +212,9 @@ int smc_rx_wait(struct smc_sock *smc, long *timeo,
        add_wait_queue(sk_sleep(sk), &wait);
        rc = sk_wait_event(sk, timeo,
                           sk->sk_err ||
+                          cflags->peer_conn_abort ||
                           sk->sk_shutdown & RCV_SHUTDOWN ||
+                          conn->killed ||
                           fcrit(conn),
                           &wait);
        remove_wait_queue(sk_sleep(sk), &wait);
@@ -314,11 +318,13 @@ int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg,
                if (read_done >= target || (pipe && read_done))
                        break;
 
+               if (conn->killed)
+                       break;
+
                if (smc_rx_recvmsg_data_available(smc))
                        goto copy;
 
-               if (sk->sk_shutdown & RCV_SHUTDOWN ||
-                   conn->local_tx_ctrl.conn_state_flags.peer_conn_abort) {
+               if (sk->sk_shutdown & RCV_SHUTDOWN) {
                        /* smc_cdc_msg_recv_action() could have run after
                         * above smc_rx_recvmsg_data_available()
                         */
index 6c8f09c..824f096 100644 (file)
@@ -86,6 +86,7 @@ static int smc_tx_wait(struct smc_sock *smc, int flags)
                sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
                if (sk->sk_err ||
                    (sk->sk_shutdown & SEND_SHUTDOWN) ||
+                   conn->killed ||
                    conn->local_tx_ctrl.conn_state_flags.peer_done_writing) {
                        rc = -EPIPE;
                        break;
@@ -155,7 +156,7 @@ int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len)
                        return -ENOTCONN;
                if (smc->sk.sk_shutdown & SEND_SHUTDOWN ||
                    (smc->sk.sk_err == ECONNABORTED) ||
-                   conn->local_tx_ctrl.conn_state_flags.peer_conn_abort)
+                   conn->killed)
                        return -EPIPE;
                if (smc_cdc_rxed_any_close(conn))
                        return send_done ?: -ECONNRESET;
@@ -282,10 +283,8 @@ static int smc_tx_rdma_write(struct smc_connection *conn, int peer_rmbe_offset,
                peer_rmbe_offset;
        rdma_wr->rkey = lgr->rtokens[conn->rtoken_idx][SMC_SINGLE_LINK].rkey;
        rc = ib_post_send(link->roce_qp, &rdma_wr->wr, NULL);
-       if (rc) {
-               conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1;
+       if (rc)
                smc_lgr_terminate(lgr);
-       }
        return rc;
 }
 
@@ -495,10 +494,11 @@ static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn)
 
                        if (smc->sk.sk_err == ECONNABORTED)
                                return sock_error(&smc->sk);
+                       if (conn->killed)
+                               return -EPIPE;
                        rc = 0;
-                       if (conn->alert_token_local) /* connection healthy */
-                               mod_delayed_work(system_wq, &conn->tx_work,
-                                                SMC_TX_WORK_DELAY);
+                       mod_delayed_work(system_wq, &conn->tx_work,
+                                        SMC_TX_WORK_DELAY);
                }
                return rc;
        }
@@ -547,6 +547,9 @@ int smc_tx_sndbuf_nonempty(struct smc_connection *conn)
 {
        int rc;
 
+       if (conn->killed ||
+           conn->local_rx_ctrl.conn_state_flags.peer_conn_abort)
+               return -EPIPE;  /* connection being aborted */
        if (conn->lgr->is_smcd)
                rc = smcd_tx_sndbuf_nonempty(conn);
        else
@@ -573,9 +576,7 @@ void smc_tx_work(struct work_struct *work)
        int rc;
 
        lock_sock(&smc->sk);
-       if (smc->sk.sk_err ||
-           !conn->alert_token_local ||
-           conn->local_rx_ctrl.conn_state_flags.peer_conn_abort)
+       if (smc->sk.sk_err)
                goto out;
 
        rc = smc_tx_sndbuf_nonempty(conn);
@@ -608,8 +609,11 @@ void smc_tx_consumer_update(struct smc_connection *conn, bool force)
            ((to_confirm > conn->rmbe_update_limit) &&
             ((sender_free <= (conn->rmb_desc->len / 2)) ||
              conn->local_rx_ctrl.prod_flags.write_blocked))) {
+               if (conn->killed ||
+                   conn->local_rx_ctrl.conn_state_flags.peer_conn_abort)
+                       return;
                if ((smc_cdc_get_slot_and_msg_send(conn) < 0) &&
-                   conn->alert_token_local) { /* connection healthy */
+                   !conn->killed) {
                        schedule_delayed_work(&conn->tx_work,
                                              SMC_TX_WORK_DELAY);
                        return;