net/smc: cancel send and receive for terminated socket

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>
This commit is contained in:
Ursula Braun 2019-10-21 16:13:08 +02:00 committed by Jakub Kicinski
parent fe28afe23e
commit b290098092
6 changed files with 32 additions and 17 deletions

View File

@ -188,6 +188,7 @@ struct smc_connection {
* 0 for SMC-R, 32 for SMC-D * 0 for SMC-R, 32 for SMC-D
*/ */
u64 peer_token; /* SMC-D token of peer */ u64 peer_token; /* SMC-D token of peer */
u8 killed : 1; /* abnormal termination */
}; };
struct smc_sock { /* smc sock container */ struct smc_sock { /* smc sock container */

View 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, rc = smc_wr_tx_get_free_slot(link, smc_cdc_tx_handler, wr_buf,
wr_rdma_buf, wr_rdma_buf,
(struct smc_wr_tx_pend_priv **)pend); (struct smc_wr_tx_pend_priv **)pend);
if (!conn->alert_token_local) if (conn->killed)
/* abnormal termination */ /* abnormal termination */
rc = -EPIPE; rc = -EPIPE;
return rc; return rc;
@ -328,7 +328,7 @@ static void smcd_cdc_rx_tsklet(unsigned long data)
struct smcd_cdc_msg cdc; struct smcd_cdc_msg cdc;
struct smc_sock *smc; struct smc_sock *smc;
if (!conn) if (!conn || conn->killed)
return; return;
data_cdc = (struct smcd_cdc_msg *)conn->rmb_desc->cpu_addr; data_cdc = (struct smcd_cdc_msg *)conn->rmb_desc->cpu_addr;

View File

@ -66,7 +66,8 @@ static void smc_close_stream_wait(struct smc_sock *smc, long timeout)
rc = sk_wait_event(sk, &timeout, rc = sk_wait_event(sk, &timeout,
!smc_tx_prepared_sends(&smc->conn) || !smc_tx_prepared_sends(&smc->conn) ||
sk->sk_err == ECONNABORTED || sk->sk_err == ECONNABORTED ||
sk->sk_err == ECONNRESET, sk->sk_err == ECONNRESET ||
smc->conn.killed,
&wait); &wait);
if (rc) if (rc)
break; 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; conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1;
else else
conn->local_tx_ctrl.conn_state_flags.peer_conn_closed = 1; 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); 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); lock_sock(sk);
old_state = sk->sk_state; old_state = sk->sk_state;
if (!conn->alert_token_local) { if (conn->killed) {
/* abnormal termination */ /* abnormal termination */
smc_close_active_abort(smc); smc_close_active_abort(smc);
goto wakeup; goto wakeup;

View File

@ -500,6 +500,7 @@ static void __smc_lgr_terminate(struct smc_link_group *lgr)
conn = rb_entry(node, struct smc_connection, alert_node); conn = rb_entry(node, struct smc_connection, alert_node);
smc = container_of(conn, struct smc_sock, conn); smc = container_of(conn, struct smc_sock, conn);
sock_hold(&smc->sk); /* sock_put in close work */ sock_hold(&smc->sk); /* sock_put in close work */
conn->killed = 1;
conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1; conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1;
__smc_lgr_unregister_conn(conn); __smc_lgr_unregister_conn(conn);
conn->lgr = NULL; conn->lgr = NULL;

View File

@ -201,6 +201,8 @@ int smc_rx_wait(struct smc_sock *smc, long *timeo,
{ {
DEFINE_WAIT_FUNC(wait, woken_wake_function); DEFINE_WAIT_FUNC(wait, woken_wake_function);
struct smc_connection *conn = &smc->conn; 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; struct sock *sk = &smc->sk;
int rc; int rc;
@ -210,7 +212,9 @@ int smc_rx_wait(struct smc_sock *smc, long *timeo,
add_wait_queue(sk_sleep(sk), &wait); add_wait_queue(sk_sleep(sk), &wait);
rc = sk_wait_event(sk, timeo, rc = sk_wait_event(sk, timeo,
sk->sk_err || sk->sk_err ||
cflags->peer_conn_abort ||
sk->sk_shutdown & RCV_SHUTDOWN || sk->sk_shutdown & RCV_SHUTDOWN ||
conn->killed ||
fcrit(conn), fcrit(conn),
&wait); &wait);
remove_wait_queue(sk_sleep(sk), &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)) if (read_done >= target || (pipe && read_done))
break; break;
if (conn->killed)
break;
if (smc_rx_recvmsg_data_available(smc)) if (smc_rx_recvmsg_data_available(smc))
goto copy; goto copy;
if (sk->sk_shutdown & RCV_SHUTDOWN || if (sk->sk_shutdown & RCV_SHUTDOWN) {
conn->local_tx_ctrl.conn_state_flags.peer_conn_abort) {
/* smc_cdc_msg_recv_action() could have run after /* smc_cdc_msg_recv_action() could have run after
* above smc_rx_recvmsg_data_available() * above smc_rx_recvmsg_data_available()
*/ */

View File

@ -86,6 +86,7 @@ static int smc_tx_wait(struct smc_sock *smc, int flags)
sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
if (sk->sk_err || if (sk->sk_err ||
(sk->sk_shutdown & SEND_SHUTDOWN) || (sk->sk_shutdown & SEND_SHUTDOWN) ||
conn->killed ||
conn->local_tx_ctrl.conn_state_flags.peer_done_writing) { conn->local_tx_ctrl.conn_state_flags.peer_done_writing) {
rc = -EPIPE; rc = -EPIPE;
break; break;
@ -155,7 +156,7 @@ int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len)
return -ENOTCONN; return -ENOTCONN;
if (smc->sk.sk_shutdown & SEND_SHUTDOWN || if (smc->sk.sk_shutdown & SEND_SHUTDOWN ||
(smc->sk.sk_err == ECONNABORTED) || (smc->sk.sk_err == ECONNABORTED) ||
conn->local_tx_ctrl.conn_state_flags.peer_conn_abort) conn->killed)
return -EPIPE; return -EPIPE;
if (smc_cdc_rxed_any_close(conn)) if (smc_cdc_rxed_any_close(conn))
return send_done ?: -ECONNRESET; 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; peer_rmbe_offset;
rdma_wr->rkey = lgr->rtokens[conn->rtoken_idx][SMC_SINGLE_LINK].rkey; rdma_wr->rkey = lgr->rtokens[conn->rtoken_idx][SMC_SINGLE_LINK].rkey;
rc = ib_post_send(link->roce_qp, &rdma_wr->wr, NULL); rc = ib_post_send(link->roce_qp, &rdma_wr->wr, NULL);
if (rc) { if (rc)
conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1;
smc_lgr_terminate(lgr); smc_lgr_terminate(lgr);
}
return rc; return rc;
} }
@ -495,8 +494,9 @@ static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn)
if (smc->sk.sk_err == ECONNABORTED) if (smc->sk.sk_err == ECONNABORTED)
return sock_error(&smc->sk); return sock_error(&smc->sk);
if (conn->killed)
return -EPIPE;
rc = 0; rc = 0;
if (conn->alert_token_local) /* connection healthy */
mod_delayed_work(system_wq, &conn->tx_work, mod_delayed_work(system_wq, &conn->tx_work,
SMC_TX_WORK_DELAY); SMC_TX_WORK_DELAY);
} }
@ -547,6 +547,9 @@ int smc_tx_sndbuf_nonempty(struct smc_connection *conn)
{ {
int rc; 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) if (conn->lgr->is_smcd)
rc = smcd_tx_sndbuf_nonempty(conn); rc = smcd_tx_sndbuf_nonempty(conn);
else else
@ -573,9 +576,7 @@ void smc_tx_work(struct work_struct *work)
int rc; int rc;
lock_sock(&smc->sk); lock_sock(&smc->sk);
if (smc->sk.sk_err || if (smc->sk.sk_err)
!conn->alert_token_local ||
conn->local_rx_ctrl.conn_state_flags.peer_conn_abort)
goto out; goto out;
rc = smc_tx_sndbuf_nonempty(conn); 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) && ((to_confirm > conn->rmbe_update_limit) &&
((sender_free <= (conn->rmb_desc->len / 2)) || ((sender_free <= (conn->rmb_desc->len / 2)) ||
conn->local_rx_ctrl.prod_flags.write_blocked))) { 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) && if ((smc_cdc_get_slot_and_msg_send(conn) < 0) &&
conn->alert_token_local) { /* connection healthy */ !conn->killed) {
schedule_delayed_work(&conn->tx_work, schedule_delayed_work(&conn->tx_work,
SMC_TX_WORK_DELAY); SMC_TX_WORK_DELAY);
return; return;