diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 221643624ace..7f762bb31879 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -3147,7 +3147,8 @@ int smc_setsockopt(struct socket *sock, int level, int optname, if (val) { SMC_STAT_INC(smc, ndly_cnt); smc_tx_pending(&smc->conn); - cancel_delayed_work(&smc->conn.tx_work); + if (cancel_delayed_work(&smc->conn.tx_work)) + sock_put(sk); } } break; @@ -3158,7 +3159,8 @@ int smc_setsockopt(struct socket *sock, int level, int optname, if (!val) { SMC_STAT_INC(smc, cork_cnt); smc_tx_pending(&smc->conn); - cancel_delayed_work(&smc->conn.tx_work); + if (cancel_delayed_work(&smc->conn.tx_work)) + sock_put(sk); } } break; diff --git a/net/smc/smc_close.c b/net/smc/smc_close.c index bb0313ef5f7c..a8d4b4b65f24 100644 --- a/net/smc/smc_close.c +++ b/net/smc/smc_close.c @@ -118,7 +118,8 @@ static void smc_close_cancel_work(struct smc_sock *smc) release_sock(sk); if (cancel_work_sync(&smc->conn.close_work)) sock_put(sk); - cancel_delayed_work_sync(&smc->conn.tx_work); + if (cancel_delayed_work_sync(&smc->conn.tx_work)) + sock_put(sk); lock_sock(sk); } @@ -230,7 +231,8 @@ again: case SMC_ACTIVE: smc_close_stream_wait(smc, timeout); release_sock(sk); - cancel_delayed_work_sync(&conn->tx_work); + if (cancel_delayed_work_sync(&conn->tx_work)) + sock_put(sk); lock_sock(sk); if (sk->sk_state == SMC_ACTIVE) { /* send close request */ @@ -264,7 +266,8 @@ again: if (!smc_cdc_rxed_any_close(conn)) smc_close_stream_wait(smc, timeout); release_sock(sk); - cancel_delayed_work_sync(&conn->tx_work); + if (cancel_delayed_work_sync(&conn->tx_work)) + sock_put(sk); lock_sock(sk); if (sk->sk_state != SMC_APPCLOSEWAIT1 && sk->sk_state != SMC_APPCLOSEWAIT2) @@ -372,7 +375,8 @@ static void smc_close_passive_work(struct work_struct *work) /* peer has not received all data */ smc_close_passive_abort_received(smc); release_sock(sk); - cancel_delayed_work_sync(&conn->tx_work); + if (cancel_delayed_work_sync(&conn->tx_work)) + sock_put(sk); lock_sock(sk); goto wakeup; } @@ -462,7 +466,8 @@ again: case SMC_ACTIVE: smc_close_stream_wait(smc, timeout); release_sock(sk); - cancel_delayed_work_sync(&conn->tx_work); + if (cancel_delayed_work_sync(&conn->tx_work)) + sock_put(sk); lock_sock(sk); if (sk->sk_state != SMC_ACTIVE) goto again; @@ -475,7 +480,8 @@ again: if (!smc_cdc_rxed_any_close(conn)) smc_close_stream_wait(smc, timeout); release_sock(sk); - cancel_delayed_work_sync(&conn->tx_work); + if (cancel_delayed_work_sync(&conn->tx_work)) + sock_put(sk); lock_sock(sk); if (sk->sk_state != SMC_APPCLOSEWAIT1) goto again; diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index 9974149659c2..6021322253e9 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -1070,7 +1070,9 @@ static int smc_switch_cursor(struct smc_sock *smc, struct smc_cdc_tx_pend *pend, smc->sk.sk_state != SMC_CLOSED) { rc = smcr_cdc_msg_send_validation(conn, pend, wr_buf); if (!rc) { - queue_delayed_work(conn->lgr->tx_wq, &conn->tx_work, 0); + sock_hold(&smc->sk); + if (!queue_delayed_work(conn->lgr->tx_wq, &conn->tx_work, 0)) + sock_put(&smc->sk); smc->sk.sk_data_ready(&smc->sk); } } else { diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c index 3144b4b1fe29..c5c00c63ce4c 100644 --- a/net/smc/smc_tx.c +++ b/net/smc/smc_tx.c @@ -570,8 +570,10 @@ static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn) if (conn->killed) return -EPIPE; rc = 0; - mod_delayed_work(conn->lgr->tx_wq, &conn->tx_work, - SMC_TX_WORK_DELAY); + sock_hold(&smc->sk); + if (!queue_delayed_work(conn->lgr->tx_wq, &conn->tx_work, + SMC_TX_WORK_DELAY)) + sock_put(&smc->sk); } return rc; } @@ -667,7 +669,7 @@ void smc_tx_pending(struct smc_connection *conn) struct smc_sock *smc = container_of(conn, struct smc_sock, conn); int rc; - if (smc->sk.sk_err) + if (smc->sk.sk_err || conn->freed) return; rc = smc_tx_sndbuf_nonempty(conn); @@ -690,6 +692,7 @@ void smc_tx_work(struct work_struct *work) lock_sock(&smc->sk); smc_tx_pending(conn); release_sock(&smc->sk); + sock_put(&smc->sk); } void smc_tx_consumer_update(struct smc_connection *conn, bool force) @@ -718,8 +721,13 @@ void smc_tx_consumer_update(struct smc_connection *conn, bool force) return; if ((smc_cdc_get_slot_and_msg_send(conn) < 0) && !conn->killed) { - queue_delayed_work(conn->lgr->tx_wq, &conn->tx_work, - SMC_TX_WORK_DELAY); + struct smc_sock *smc = + container_of(conn, struct smc_sock, conn); + + sock_hold(&smc->sk); + if (!queue_delayed_work(conn->lgr->tx_wq, &conn->tx_work, + SMC_TX_WORK_DELAY)) + sock_put(&smc->sk); return; } }