Skip to content

Commit b286a06

Browse files
karstengrdavem330
authored andcommitted
net/smc: handle incoming CDC validation message
Call smc_cdc_msg_validate() when a CDC message with the failover validation bit enabled was received. Validate that the sequence number sent with the message is one we already have received. If not, messages were lost and the connection is terminated using a new abort_work. Signed-off-by: Karsten Graul <[email protected]> Reviewed-by: Ursula Braun <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 29bd73d commit b286a06

File tree

3 files changed

+48
-6
lines changed

3 files changed

+48
-6
lines changed

net/smc/smc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,14 @@ struct smc_connection {
188188
spinlock_t acurs_lock; /* protect cursors */
189189
#endif
190190
struct work_struct close_work; /* peer sent some closing */
191+
struct work_struct abort_work; /* abort the connection */
191192
struct tasklet_struct rx_tsklet; /* Receiver tasklet for SMC-D */
192193
u8 rx_off; /* receive offset:
193194
* 0 for SMC-R, 32 for SMC-D
194195
*/
195196
u64 peer_token; /* SMC-D token of peer */
196197
u8 killed : 1; /* abnormal termination */
198+
u8 out_of_sync : 1; /* out of sync with peer */
197199
};
198200

199201
struct smc_sock { /* smc sock container */

net/smc/smc_cdc.c

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,28 @@ static void smc_cdc_handle_urg_data_arrival(struct smc_sock *smc,
282282
sk_send_sigurg(&smc->sk);
283283
}
284284

285+
static void smc_cdc_msg_validate(struct smc_sock *smc, struct smc_cdc_msg *cdc,
286+
struct smc_link *link)
287+
{
288+
struct smc_connection *conn = &smc->conn;
289+
u16 recv_seq = ntohs(cdc->seqno);
290+
s16 diff;
291+
292+
/* check that seqnum was seen before */
293+
diff = conn->local_rx_ctrl.seqno - recv_seq;
294+
if (diff < 0) { /* diff larger than 0x7fff */
295+
/* drop connection */
296+
conn->out_of_sync = 1; /* prevent any further receives */
297+
spin_lock_bh(&conn->send_lock);
298+
conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1;
299+
conn->lnk = link;
300+
spin_unlock_bh(&conn->send_lock);
301+
sock_hold(&smc->sk); /* sock_put in abort_work */
302+
if (!schedule_work(&conn->abort_work))
303+
sock_put(&smc->sk);
304+
}
305+
}
306+
285307
static void smc_cdc_msg_recv_action(struct smc_sock *smc,
286308
struct smc_cdc_msg *cdc)
287309
{
@@ -412,16 +434,19 @@ static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf)
412434
read_lock_bh(&lgr->conns_lock);
413435
conn = smc_lgr_find_conn(ntohl(cdc->token), lgr);
414436
read_unlock_bh(&lgr->conns_lock);
415-
if (!conn)
437+
if (!conn || conn->out_of_sync)
416438
return;
417439
smc = container_of(conn, struct smc_sock, conn);
418440

419-
if (!cdc->prod_flags.failover_validation) {
420-
if (smc_cdc_before(ntohs(cdc->seqno),
421-
conn->local_rx_ctrl.seqno))
422-
/* received seqno is old */
423-
return;
441+
if (cdc->prod_flags.failover_validation) {
442+
smc_cdc_msg_validate(smc, cdc, link);
443+
return;
424444
}
445+
if (smc_cdc_before(ntohs(cdc->seqno),
446+
conn->local_rx_ctrl.seqno))
447+
/* received seqno is old */
448+
return;
449+
425450
smc_cdc_msg_recv(smc, cdc);
426451
}
427452

net/smc/smc_core.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,8 @@ void smc_conn_free(struct smc_connection *conn)
615615
tasklet_kill(&conn->rx_tsklet);
616616
} else {
617617
smc_cdc_tx_dismiss_slots(conn);
618+
if (current_work() != &conn->abort_work)
619+
cancel_work_sync(&conn->abort_work);
618620
}
619621
if (!list_empty(&lgr->list)) {
620622
smc_lgr_unregister_conn(conn);
@@ -996,6 +998,18 @@ void smc_smcr_terminate_all(struct smc_ib_device *smcibdev)
996998
}
997999
}
9981000

1001+
/* abort connection, abort_work scheduled from tasklet context */
1002+
static void smc_conn_abort_work(struct work_struct *work)
1003+
{
1004+
struct smc_connection *conn = container_of(work,
1005+
struct smc_connection,
1006+
abort_work);
1007+
struct smc_sock *smc = container_of(conn, struct smc_sock, conn);
1008+
1009+
smc_conn_kill(conn, true);
1010+
sock_put(&smc->sk); /* sock_hold done by schedulers of abort_work */
1011+
}
1012+
9991013
/* link is up - establish alternate link if applicable */
10001014
static void smcr_link_up(struct smc_link_group *lgr,
10011015
struct smc_ib_device *smcibdev, u8 ibport)
@@ -1302,6 +1316,7 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
13021316
conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE;
13031317
conn->local_tx_ctrl.len = SMC_WR_TX_SIZE;
13041318
conn->urg_state = SMC_URG_READ;
1319+
INIT_WORK(&smc->conn.abort_work, smc_conn_abort_work);
13051320
if (ini->is_smcd) {
13061321
conn->rx_off = sizeof(struct smcd_cdc_msg);
13071322
smcd_cdc_rx_init(conn); /* init tasklet for this conn */

0 commit comments

Comments
 (0)