Before a link can be reused it must have been cleared. Lowest current link state is INACTIVE, which does not mean that the link is already cleared. Add a new state UNUSED that is set when the link is cleared and can be reused. Add helper smc_llc_usable_link() to find an active link in a link group, and smc_link_usable() to determine if a link is usable. Signed-off-by: Karsten Graul <kgraul@xxxxxxxxxxxxx> Reviewed-by: Ursula Braun <ubraun@xxxxxxxxxxxxx> --- net/smc/smc_core.c | 36 +++++++++++++++++++----------------- net/smc/smc_core.h | 9 +++++++++ net/smc/smc_llc.c | 4 ++-- net/smc/smc_llc.h | 11 +++++++++++ net/smc/smc_wr.c | 2 +- 5 files changed, 42 insertions(+), 20 deletions(-) diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index e8897d60b27f..57890cbd4e8a 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -260,7 +260,7 @@ static void smc_lgr_free_work(struct work_struct *work) for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { struct smc_link *lnk = &lgr->lnk[i]; - if (lnk->state != SMC_LNK_INACTIVE) + if (smc_link_usable(lnk)) smc_llc_link_inactive(lnk); } } @@ -286,7 +286,7 @@ static u8 smcr_next_link_id(struct smc_link_group *lgr) if (!link_id) /* skip zero as link_id */ link_id = ++lgr->next_link_id; for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { - if (lgr->lnk[i].state != SMC_LNK_INACTIVE && + if (smc_link_usable(&lgr->lnk[i]) && lgr->lnk[i].link_id == link_id) continue; } @@ -350,6 +350,7 @@ static int smcr_link_init(struct smc_link_group *lgr, struct smc_link *lnk, out: put_device(&ini->ib_dev->ibdev->dev); memset(lnk, 0, sizeof(struct smc_link)); + lnk->state = SMC_LNK_UNUSED; if (!atomic_dec_return(&ini->ib_dev->lnk_cnt)) wake_up(&ini->ib_dev->lnks_deleted); return rc; @@ -500,6 +501,8 @@ void smc_conn_free(struct smc_connection *conn) static void smcr_link_clear(struct smc_link *lnk) { + struct smc_ib_device *smcibdev; + if (lnk->peer_qpn == 0) return; lnk->peer_qpn = 0; @@ -510,8 +513,11 @@ static void smcr_link_clear(struct smc_link *lnk) smc_ib_dealloc_protection_domain(lnk); smc_wr_free_link_mem(lnk); put_device(&lnk->smcibdev->ibdev->dev); - if (!atomic_dec_return(&lnk->smcibdev->lnk_cnt)) - wake_up(&lnk->smcibdev->lnks_deleted); + smcibdev = lnk->smcibdev; + memset(lnk, 0, sizeof(struct smc_link)); + lnk->state = SMC_LNK_UNUSED; + if (!atomic_dec_return(&smcibdev->lnk_cnt)) + wake_up(&smcibdev->lnks_deleted); } static void smcr_buf_free(struct smc_link_group *lgr, bool is_rmb, @@ -604,9 +610,8 @@ static void smc_lgr_free(struct smc_link_group *lgr) wake_up(&lgr->smcd->lgrs_deleted); } else { for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { - if (lgr->lnk[i].state == SMC_LNK_INACTIVE) - continue; - smcr_link_clear(&lgr->lnk[i]); + if (lgr->lnk[i].state != SMC_LNK_UNUSED) + smcr_link_clear(&lgr->lnk[i]); } if (!atomic_dec_return(&lgr_cnt)) wake_up(&lgrs_deleted); @@ -686,7 +691,7 @@ static void smc_lgr_cleanup(struct smc_link_group *lgr) for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { struct smc_link *lnk = &lgr->lnk[i]; - if (lnk->state != SMC_LNK_INACTIVE) + if (smc_link_usable(lnk)) smc_llc_link_inactive(lnk); } } @@ -764,7 +769,7 @@ void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport) continue; /* tbd - terminate only when no more links are active */ for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { - if (lgr->lnk[i].state == SMC_LNK_INACTIVE || + if (!smc_link_usable(&lgr->lnk[i]) || lgr->lnk[i].state == SMC_LNK_DELETING) continue; if (lgr->lnk[i].smcibdev == smcibdev && @@ -1161,8 +1166,7 @@ static int smcr_buf_map_usable_links(struct smc_link_group *lgr, for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { struct smc_link *lnk = &lgr->lnk[i]; - if (lnk->state != SMC_LNK_ACTIVE && - lnk->state != SMC_LNK_ACTIVATING) + if (!smc_link_usable(lnk)) continue; if (smcr_buf_map_link(buf_desc, is_rmb, lnk)) { smcr_buf_unuse(buf_desc, lnk); @@ -1294,14 +1298,14 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb) void smc_sndbuf_sync_sg_for_cpu(struct smc_connection *conn) { - if (!conn->lgr || conn->lgr->is_smcd) + if (!conn->lgr || conn->lgr->is_smcd || !smc_link_usable(conn->lnk)) return; smc_ib_sync_sg_for_cpu(conn->lnk, conn->sndbuf_desc, DMA_TO_DEVICE); } void smc_sndbuf_sync_sg_for_device(struct smc_connection *conn) { - if (!conn->lgr || conn->lgr->is_smcd) + if (!conn->lgr || conn->lgr->is_smcd || !smc_link_usable(conn->lnk)) return; smc_ib_sync_sg_for_device(conn->lnk, conn->sndbuf_desc, DMA_TO_DEVICE); } @@ -1313,8 +1317,7 @@ void smc_rmb_sync_sg_for_cpu(struct smc_connection *conn) if (!conn->lgr || conn->lgr->is_smcd) return; for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { - if (conn->lgr->lnk[i].state != SMC_LNK_ACTIVE && - conn->lgr->lnk[i].state != SMC_LNK_ACTIVATING) + if (!smc_link_usable(&conn->lgr->lnk[i])) continue; smc_ib_sync_sg_for_cpu(&conn->lgr->lnk[i], conn->rmb_desc, DMA_FROM_DEVICE); @@ -1328,8 +1331,7 @@ void smc_rmb_sync_sg_for_device(struct smc_connection *conn) if (!conn->lgr || conn->lgr->is_smcd) return; for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { - if (conn->lgr->lnk[i].state != SMC_LNK_ACTIVE && - conn->lgr->lnk[i].state != SMC_LNK_ACTIVATING) + if (!smc_link_usable(&conn->lgr->lnk[i])) continue; smc_ib_sync_sg_for_device(&conn->lgr->lnk[i], conn->rmb_desc, DMA_FROM_DEVICE); diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h index f68ba187ecf8..2b1960c8c8ce 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -32,6 +32,7 @@ enum smc_lgr_role { /* possible roles of a link group */ }; enum smc_link_state { /* possible states of a link */ + SMC_LNK_UNUSED, /* link is unused */ SMC_LNK_INACTIVE, /* link is inactive */ SMC_LNK_ACTIVATING, /* link is being activated */ SMC_LNK_ACTIVE, /* link is active */ @@ -295,6 +296,14 @@ static inline struct smc_connection *smc_lgr_find_conn( return res; } +/* returns true if the specified link is usable */ +static inline bool smc_link_usable(struct smc_link *lnk) +{ + if (lnk->state == SMC_LNK_UNUSED || lnk->state == SMC_LNK_INACTIVE) + return false; + return true; +} + struct smc_sock; struct smc_clc_msg_accept_confirm; struct smc_clc_msg_local; diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c index 903ae068da3a..c267f5006faa 100644 --- a/net/smc/smc_llc.c +++ b/net/smc/smc_llc.c @@ -372,7 +372,7 @@ static void smc_llc_send_message_work(struct work_struct *work) struct smc_wr_buf *wr_buf; int rc; - if (llcwrk->link->state == SMC_LNK_INACTIVE) + if (!smc_link_usable(llcwrk->link)) goto out; rc = smc_llc_add_pending_send(llcwrk->link, &wr_buf, &pend); if (rc) @@ -562,7 +562,7 @@ static void smc_llc_rx_handler(struct ib_wc *wc, void *buf) return; /* short message */ if (llc->raw.hdr.length != sizeof(*llc)) return; /* invalid message */ - if (link->state == SMC_LNK_INACTIVE) + if (!smc_link_usable(link)) return; /* link not active, drop msg */ switch (llc->raw.hdr.common.type) { diff --git a/net/smc/smc_llc.h b/net/smc/smc_llc.h index 461c0c3ef76e..08171131110c 100644 --- a/net/smc/smc_llc.h +++ b/net/smc/smc_llc.h @@ -35,6 +35,17 @@ enum smc_llc_msg_type { SMC_LLC_DELETE_RKEY = 0x09, }; +/* returns a usable link of the link group, or NULL */ +static inline struct smc_link *smc_llc_usable_link(struct smc_link_group *lgr) +{ + int i; + + for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) + if (smc_link_usable(&lgr->lnk[i])) + return &lgr->lnk[i]; + return NULL; +} + /* transmit */ int smc_llc_send_confirm_link(struct smc_link *lnk, enum smc_llc_reqresp reqresp); diff --git a/net/smc/smc_wr.c b/net/smc/smc_wr.c index 337ee52ad3d3..93223628c002 100644 --- a/net/smc/smc_wr.c +++ b/net/smc/smc_wr.c @@ -207,7 +207,7 @@ int smc_wr_tx_get_free_slot(struct smc_link *link, } else { rc = wait_event_interruptible_timeout( link->wr_tx_wait, - link->state == SMC_LNK_INACTIVE || + !smc_link_usable(link) || lgr->terminating || (smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY), SMC_WR_TX_WAIT_FREE_SLOT_TIME); -- 2.17.1