OSDN Git Service

net/smc: delete an asymmetric link as SMC server
authorKarsten Graul <kgraul@linux.ibm.com>
Sun, 3 May 2020 12:38:46 +0000 (14:38 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 3 May 2020 23:07:09 +0000 (16:07 -0700)
When a link group moved from asymmetric to symmetric state then the
dangling asymmetric link can be deleted. Add smc_llc_find_asym_link() to
find the respective link and add smc_llc_delete_asym_link() to delete
it.

Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Reviewed-by: Ursula Braun <ubraun@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/smc/smc_llc.c
net/smc/smc_wr.c
net/smc/smc_wr.h

index 1fefee5..9d102c9 100644 (file)
@@ -863,6 +863,85 @@ static void smc_llc_process_cli_add_link(struct smc_link_group *lgr)
        mutex_unlock(&lgr->llc_conf_mutex);
 }
 
+/* find the asymmetric link when 3 links are established  */
+static struct smc_link *smc_llc_find_asym_link(struct smc_link_group *lgr)
+{
+       int asym_idx = -ENOENT;
+       int i, j, k;
+       bool found;
+
+       /* determine asymmetric link */
+       found = false;
+       for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
+               for (j = i + 1; j < SMC_LINKS_PER_LGR_MAX; j++) {
+                       if (!smc_link_usable(&lgr->lnk[i]) ||
+                           !smc_link_usable(&lgr->lnk[j]))
+                               continue;
+                       if (!memcmp(lgr->lnk[i].gid, lgr->lnk[j].gid,
+                                   SMC_GID_SIZE)) {
+                               found = true;   /* asym_lnk is i or j */
+                               break;
+                       }
+               }
+               if (found)
+                       break;
+       }
+       if (!found)
+               goto out; /* no asymmetric link */
+       for (k = 0; k < SMC_LINKS_PER_LGR_MAX; k++) {
+               if (!smc_link_usable(&lgr->lnk[k]))
+                       continue;
+               if (k != i &&
+                   !memcmp(lgr->lnk[i].peer_gid, lgr->lnk[k].peer_gid,
+                           SMC_GID_SIZE)) {
+                       asym_idx = i;
+                       break;
+               }
+               if (k != j &&
+                   !memcmp(lgr->lnk[j].peer_gid, lgr->lnk[k].peer_gid,
+                           SMC_GID_SIZE)) {
+                       asym_idx = j;
+                       break;
+               }
+       }
+out:
+       return (asym_idx < 0) ? NULL : &lgr->lnk[asym_idx];
+}
+
+static void smc_llc_delete_asym_link(struct smc_link_group *lgr)
+{
+       struct smc_link *lnk_new = NULL, *lnk_asym;
+       struct smc_llc_qentry *qentry;
+       int rc;
+
+       lnk_asym = smc_llc_find_asym_link(lgr);
+       if (!lnk_asym)
+               return; /* no asymmetric link */
+       if (!smc_link_downing(&lnk_asym->state))
+               return;
+       /* tbd: lnk_new = smc_switch_conns(lgr, lnk_asym, false); */
+       smc_wr_tx_wait_no_pending_sends(lnk_asym);
+       if (!lnk_new)
+               goto out_free;
+       /* change flow type from ADD_LINK into DEL_LINK */
+       lgr->llc_flow_lcl.type = SMC_LLC_FLOW_DEL_LINK;
+       rc = smc_llc_send_delete_link(lnk_new, lnk_asym->link_id, SMC_LLC_REQ,
+                                     true, SMC_LLC_DEL_NO_ASYM_NEEDED);
+       if (rc) {
+               smcr_link_down_cond(lnk_new);
+               goto out_free;
+       }
+       qentry = smc_llc_wait(lgr, lnk_new, SMC_LLC_WAIT_TIME,
+                             SMC_LLC_DELETE_LINK);
+       if (!qentry) {
+               smcr_link_down_cond(lnk_new);
+               goto out_free;
+       }
+       smc_llc_flow_qentry_del(&lgr->llc_flow_lcl);
+out_free:
+       smcr_link_clear(lnk_asym);
+}
+
 static int smc_llc_srv_rkey_exchange(struct smc_link *link,
                                     struct smc_link *link_new)
 {
@@ -1014,7 +1093,7 @@ static void smc_llc_process_srv_add_link(struct smc_link_group *lgr)
        rc = smc_llc_srv_add_link(link);
        if (!rc && lgr->type == SMC_LGR_SYMMETRIC) {
                /* delete any asymmetric link */
-               /* tbd: smc_llc_delete_asym_link(lgr); */
+               smc_llc_delete_asym_link(lgr);
        }
        mutex_unlock(&lgr->llc_conf_mutex);
 }
index 031e6c9..3fd27be 100644 (file)
@@ -61,7 +61,7 @@ static inline bool smc_wr_is_tx_pend(struct smc_link *link)
 }
 
 /* wait till all pending tx work requests on the given link are completed */
-static inline int smc_wr_tx_wait_no_pending_sends(struct smc_link *link)
+int smc_wr_tx_wait_no_pending_sends(struct smc_link *link)
 {
        if (wait_event_timeout(link->wr_tx_wait, !smc_wr_is_tx_pend(link),
                               SMC_WR_TX_WAIT_PENDING_TIME))
index 3ac99c8..f7eaeb3 100644 (file)
@@ -106,6 +106,7 @@ void smc_wr_tx_dismiss_slots(struct smc_link *lnk, u8 wr_rx_hdr_type,
                             smc_wr_tx_filter filter,
                             smc_wr_tx_dismisser dismisser,
                             unsigned long data);
+int smc_wr_tx_wait_no_pending_sends(struct smc_link *link);
 
 int smc_wr_rx_register_handler(struct smc_wr_rx_handler *handler);
 int smc_wr_rx_post_init(struct smc_link *link);