OSDN Git Service

net/smc: delete link processing as SMC client
authorKarsten Graul <kgraul@linux.ibm.com>
Sun, 3 May 2020 12:38:48 +0000 (14:38 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 3 May 2020 23:07:39 +0000 (16:07 -0700)
Add smc_llc_process_cli_delete_link() to process a DELETE_LINK request
as SMC client. When the request is to delete ALL links then terminate
the whole link group. If not, find the link to delete by its link_id,
send the DELETE_LINK response LLC message and then clear the deleted
link. Finally determine and update the link group state.

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

index e4e3910..cd57b4f 100644 (file)
@@ -863,6 +863,18 @@ static void smc_llc_process_cli_add_link(struct smc_link_group *lgr)
        mutex_unlock(&lgr->llc_conf_mutex);
 }
 
+static int smc_llc_active_link_count(struct smc_link_group *lgr)
+{
+       int i, link_count = 0;
+
+       for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
+               if (!smc_link_usable(&lgr->lnk[i]))
+                       continue;
+               link_count++;
+       }
+       return link_count;
+}
+
 /* find the asymmetric link when 3 links are established  */
 static struct smc_link *smc_llc_find_asym_link(struct smc_link_group *lgr)
 {
@@ -1118,6 +1130,63 @@ out:
        smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl);
 }
 
+static void smc_llc_process_cli_delete_link(struct smc_link_group *lgr)
+{
+       struct smc_link *lnk_del = NULL, *lnk_asym, *lnk;
+       struct smc_llc_msg_del_link *del_llc;
+       struct smc_llc_qentry *qentry;
+       int active_links;
+       int lnk_idx;
+
+       qentry = smc_llc_flow_qentry_clr(&lgr->llc_flow_lcl);
+       lnk = qentry->link;
+       del_llc = &qentry->msg.delete_link;
+
+       if (del_llc->hd.flags & SMC_LLC_FLAG_DEL_LINK_ALL) {
+               smc_lgr_terminate_sched(lgr);
+               goto out;
+       }
+       mutex_lock(&lgr->llc_conf_mutex);
+       /* delete single link */
+       for (lnk_idx = 0; lnk_idx < SMC_LINKS_PER_LGR_MAX; lnk_idx++) {
+               if (lgr->lnk[lnk_idx].link_id != del_llc->link_num)
+                       continue;
+               lnk_del = &lgr->lnk[lnk_idx];
+               break;
+       }
+       del_llc->hd.flags |= SMC_LLC_FLAG_RESP;
+       if (!lnk_del) {
+               /* link was not found */
+               del_llc->reason = htonl(SMC_LLC_DEL_NOLNK);
+               smc_llc_send_message(lnk, &qentry->msg);
+               goto out_unlock;
+       }
+       lnk_asym = smc_llc_find_asym_link(lgr);
+
+       del_llc->reason = 0;
+       smc_llc_send_message(lnk, &qentry->msg); /* response */
+
+       if (smc_link_downing(&lnk_del->state)) {
+               /* tbd: call smc_switch_conns(lgr, lnk_del, false); */
+               smc_wr_tx_wait_no_pending_sends(lnk_del);
+       }
+       smcr_link_clear(lnk_del);
+
+       active_links = smc_llc_active_link_count(lgr);
+       if (lnk_del == lnk_asym) {
+               /* expected deletion of asym link, don't change lgr state */
+       } else if (active_links == 1) {
+               lgr->type = SMC_LGR_SINGLE;
+       } else if (!active_links) {
+               lgr->type = SMC_LGR_NONE;
+               smc_lgr_terminate_sched(lgr);
+       }
+out_unlock:
+       mutex_unlock(&lgr->llc_conf_mutex);
+out:
+       kfree(qentry);
+}
+
 static void smc_llc_delete_link_work(struct work_struct *work)
 {
        struct smc_link_group *lgr = container_of(work, struct smc_link_group,
@@ -1128,6 +1197,9 @@ static void smc_llc_delete_link_work(struct work_struct *work)
                smc_llc_flow_qentry_del(&lgr->llc_flow_lcl);
                goto out;
        }
+
+       if (lgr->role == SMC_CLNT)
+               smc_llc_process_cli_delete_link(lgr);
 out:
        smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl);
 }