Skip to content

Commit 51e3dfa

Browse files
Ursula Braundavem330
authored andcommitted
net/smc: fix cleanup for linkgroup setup failures
If an SMC connection to a certain peer is setup the first time, a new linkgroup is created. In case of setup failures, such a linkgroup is unusable and should disappear. As a first step the linkgroup is removed from the linkgroup list in smc_lgr_forget(). There are 2 problems: smc_listen_decline() might be called before linkgroup creation resulting in a crash due to calling smc_lgr_forget() with parameter NULL. If a setup failure occurs after linkgroup creation, the connection is never unregistered from the linkgroup, preventing linkgroup freeing. This patch introduces an enhanced smc_lgr_cleanup_early() function which * contains a linkgroup check for early smc_listen_decline() invocations * invokes smc_conn_free() to guarantee unregistering of the connection. * schedules fast linkgroup removal of the unusable linkgroup And the unused function smcd_conn_free() is removed from smc_core.h. Fixes: 3b2dec2 ("net/smc: restructure client and server code in af_smc") Fixes: 2a0674f ("net/smc: improve abnormal termination of link groups") Signed-off-by: Ursula Braun <[email protected]> Signed-off-by: Karsten Graul <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 402482a commit 51e3dfa

File tree

3 files changed

+28
-11
lines changed

3 files changed

+28
-11
lines changed

net/smc/af_smc.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -512,15 +512,18 @@ static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code)
512512
static int smc_connect_abort(struct smc_sock *smc, int reason_code,
513513
int local_contact)
514514
{
515+
bool is_smcd = smc->conn.lgr->is_smcd;
516+
515517
if (local_contact == SMC_FIRST_CONTACT)
516-
smc_lgr_forget(smc->conn.lgr);
517-
if (smc->conn.lgr->is_smcd)
518+
smc_lgr_cleanup_early(&smc->conn);
519+
else
520+
smc_conn_free(&smc->conn);
521+
if (is_smcd)
518522
/* there is only one lgr role for SMC-D; use server lock */
519523
mutex_unlock(&smc_server_lgr_pending);
520524
else
521525
mutex_unlock(&smc_client_lgr_pending);
522526

523-
smc_conn_free(&smc->conn);
524527
smc->connect_nonblock = 0;
525528
return reason_code;
526529
}
@@ -1091,7 +1094,6 @@ static void smc_listen_out_err(struct smc_sock *new_smc)
10911094
if (newsmcsk->sk_state == SMC_INIT)
10921095
sock_put(&new_smc->sk); /* passive closing */
10931096
newsmcsk->sk_state = SMC_CLOSED;
1094-
smc_conn_free(&new_smc->conn);
10951097

10961098
smc_listen_out(new_smc);
10971099
}
@@ -1102,12 +1104,13 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
11021104
{
11031105
/* RDMA setup failed, switch back to TCP */
11041106
if (local_contact == SMC_FIRST_CONTACT)
1105-
smc_lgr_forget(new_smc->conn.lgr);
1107+
smc_lgr_cleanup_early(&new_smc->conn);
1108+
else
1109+
smc_conn_free(&new_smc->conn);
11061110
if (reason_code < 0) { /* error, no fallback possible */
11071111
smc_listen_out_err(new_smc);
11081112
return;
11091113
}
1110-
smc_conn_free(&new_smc->conn);
11111114
smc_switch_to_fallback(new_smc);
11121115
new_smc->fallback_rsn = reason_code;
11131116
if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) {
@@ -1170,16 +1173,18 @@ static int smc_listen_ism_init(struct smc_sock *new_smc,
11701173
new_smc->conn.lgr->vlan_id,
11711174
new_smc->conn.lgr->smcd)) {
11721175
if (ini->cln_first_contact == SMC_FIRST_CONTACT)
1173-
smc_lgr_forget(new_smc->conn.lgr);
1174-
smc_conn_free(&new_smc->conn);
1176+
smc_lgr_cleanup_early(&new_smc->conn);
1177+
else
1178+
smc_conn_free(&new_smc->conn);
11751179
return SMC_CLC_DECL_SMCDNOTALK;
11761180
}
11771181

11781182
/* Create send and receive buffers */
11791183
if (smc_buf_create(new_smc, true)) {
11801184
if (ini->cln_first_contact == SMC_FIRST_CONTACT)
1181-
smc_lgr_forget(new_smc->conn.lgr);
1182-
smc_conn_free(&new_smc->conn);
1185+
smc_lgr_cleanup_early(&new_smc->conn);
1186+
else
1187+
smc_conn_free(&new_smc->conn);
11831188
return SMC_CLC_DECL_MEM;
11841189
}
11851190

net/smc/smc_core.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,18 @@ static void smc_lgr_unregister_conn(struct smc_connection *conn)
162162
conn->lgr = NULL;
163163
}
164164

165+
void smc_lgr_cleanup_early(struct smc_connection *conn)
166+
{
167+
struct smc_link_group *lgr = conn->lgr;
168+
169+
if (!lgr)
170+
return;
171+
172+
smc_conn_free(conn);
173+
smc_lgr_forget(lgr);
174+
smc_lgr_schedule_free_work_fast(lgr);
175+
}
176+
165177
/* Send delete link, either as client to request the initiation
166178
* of the DELETE LINK sequence from server; or as server to
167179
* initiate the delete processing. See smc_llc_rx_delete_link().

net/smc/smc_core.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ struct smc_clc_msg_accept_confirm;
296296
struct smc_clc_msg_local;
297297

298298
void smc_lgr_forget(struct smc_link_group *lgr);
299+
void smc_lgr_cleanup_early(struct smc_connection *conn);
299300
void smc_lgr_terminate(struct smc_link_group *lgr, bool soft);
300301
void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport);
301302
void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid,
@@ -316,7 +317,6 @@ int smc_vlan_by_tcpsk(struct socket *clcsock, struct smc_init_info *ini);
316317

317318
void smc_conn_free(struct smc_connection *conn);
318319
int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini);
319-
void smcd_conn_free(struct smc_connection *conn);
320320
void smc_lgr_schedule_free_work_fast(struct smc_link_group *lgr);
321321
int smc_core_init(void);
322322
void smc_core_exit(void);

0 commit comments

Comments
 (0)