@@ -863,6 +863,18 @@ static void smc_llc_process_cli_add_link(struct smc_link_group *lgr)
863863 mutex_unlock (& lgr -> llc_conf_mutex );
864864}
865865
866+ static int smc_llc_active_link_count (struct smc_link_group * lgr )
867+ {
868+ int i , link_count = 0 ;
869+
870+ for (i = 0 ; i < SMC_LINKS_PER_LGR_MAX ; i ++ ) {
871+ if (!smc_link_usable (& lgr -> lnk [i ]))
872+ continue ;
873+ link_count ++ ;
874+ }
875+ return link_count ;
876+ }
877+
866878/* find the asymmetric link when 3 links are established */
867879static struct smc_link * smc_llc_find_asym_link (struct smc_link_group * lgr )
868880{
@@ -1118,6 +1130,63 @@ static void smc_llc_add_link_work(struct work_struct *work)
11181130 smc_llc_flow_stop (lgr , & lgr -> llc_flow_lcl );
11191131}
11201132
1133+ static void smc_llc_process_cli_delete_link (struct smc_link_group * lgr )
1134+ {
1135+ struct smc_link * lnk_del = NULL , * lnk_asym , * lnk ;
1136+ struct smc_llc_msg_del_link * del_llc ;
1137+ struct smc_llc_qentry * qentry ;
1138+ int active_links ;
1139+ int lnk_idx ;
1140+
1141+ qentry = smc_llc_flow_qentry_clr (& lgr -> llc_flow_lcl );
1142+ lnk = qentry -> link ;
1143+ del_llc = & qentry -> msg .delete_link ;
1144+
1145+ if (del_llc -> hd .flags & SMC_LLC_FLAG_DEL_LINK_ALL ) {
1146+ smc_lgr_terminate_sched (lgr );
1147+ goto out ;
1148+ }
1149+ mutex_lock (& lgr -> llc_conf_mutex );
1150+ /* delete single link */
1151+ for (lnk_idx = 0 ; lnk_idx < SMC_LINKS_PER_LGR_MAX ; lnk_idx ++ ) {
1152+ if (lgr -> lnk [lnk_idx ].link_id != del_llc -> link_num )
1153+ continue ;
1154+ lnk_del = & lgr -> lnk [lnk_idx ];
1155+ break ;
1156+ }
1157+ del_llc -> hd .flags |= SMC_LLC_FLAG_RESP ;
1158+ if (!lnk_del ) {
1159+ /* link was not found */
1160+ del_llc -> reason = htonl (SMC_LLC_DEL_NOLNK );
1161+ smc_llc_send_message (lnk , & qentry -> msg );
1162+ goto out_unlock ;
1163+ }
1164+ lnk_asym = smc_llc_find_asym_link (lgr );
1165+
1166+ del_llc -> reason = 0 ;
1167+ smc_llc_send_message (lnk , & qentry -> msg ); /* response */
1168+
1169+ if (smc_link_downing (& lnk_del -> state )) {
1170+ /* tbd: call smc_switch_conns(lgr, lnk_del, false); */
1171+ smc_wr_tx_wait_no_pending_sends (lnk_del );
1172+ }
1173+ smcr_link_clear (lnk_del );
1174+
1175+ active_links = smc_llc_active_link_count (lgr );
1176+ if (lnk_del == lnk_asym ) {
1177+ /* expected deletion of asym link, don't change lgr state */
1178+ } else if (active_links == 1 ) {
1179+ lgr -> type = SMC_LGR_SINGLE ;
1180+ } else if (!active_links ) {
1181+ lgr -> type = SMC_LGR_NONE ;
1182+ smc_lgr_terminate_sched (lgr );
1183+ }
1184+ out_unlock :
1185+ mutex_unlock (& lgr -> llc_conf_mutex );
1186+ out :
1187+ kfree (qentry );
1188+ }
1189+
11211190static void smc_llc_delete_link_work (struct work_struct * work )
11221191{
11231192 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)
11281197 smc_llc_flow_qentry_del (& lgr -> llc_flow_lcl );
11291198 goto out ;
11301199 }
1200+
1201+ if (lgr -> role == SMC_CLNT )
1202+ smc_llc_process_cli_delete_link (lgr );
11311203out :
11321204 smc_llc_flow_stop (lgr , & lgr -> llc_flow_lcl );
11331205}
0 commit comments