Skip to content

Commit 541afa1

Browse files
karstengrdavem330
authored andcommitted
net/smc: add smcr_port_err() and smcr_link_down() processing
Call smcr_port_err() when an IB event reports an inactive IB device. smcr_port_err() calls smcr_link_down() for all affected links. smcr_link_down() either triggers the local DELETE_LINK processing, or sends an DELETE_LINK LLC message to the SMC server to initiate the processing. The old handler function smc_port_terminate() is removed. Add helper smcr_link_down_cond() to take a link down conditionally, and smcr_link_down_cond_sched() to schedule the link_down processing to a work. 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>
1 parent 1f90a05 commit 541afa1

File tree

4 files changed

+98
-32
lines changed

4 files changed

+98
-32
lines changed

net/smc/smc_core.c

+89-30
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ static void smc_buf_free(struct smc_link_group *lgr, bool is_rmb,
5656
static void __smc_lgr_terminate(struct smc_link_group *lgr, bool soft);
5757

5858
static void smc_link_up_work(struct work_struct *work);
59+
static void smc_link_down_work(struct work_struct *work);
5960

6061
/* return head of link group list and its lock for a given link group */
6162
static inline struct list_head *smc_lgr_list_head(struct smc_link_group *lgr,
@@ -320,6 +321,7 @@ static int smcr_link_init(struct smc_link_group *lgr, struct smc_link *lnk,
320321
lnk->smcibdev = ini->ib_dev;
321322
lnk->ibport = ini->ib_port;
322323
lnk->path_mtu = ini->ib_dev->pattr[ini->ib_port - 1].active_mtu;
324+
INIT_WORK(&lnk->link_down_wrk, smc_link_down_work);
323325
if (!ini->ib_dev->initialized) {
324326
rc = (int)smc_ib_setup_per_ibdev(ini->ib_dev);
325327
if (rc)
@@ -818,36 +820,6 @@ void smc_lgr_terminate_sched(struct smc_link_group *lgr)
818820
schedule_work(&lgr->terminate_work);
819821
}
820822

821-
/* Called when IB port is terminated */
822-
void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport)
823-
{
824-
struct smc_link_group *lgr, *l;
825-
LIST_HEAD(lgr_free_list);
826-
int i;
827-
828-
spin_lock_bh(&smc_lgr_list.lock);
829-
list_for_each_entry_safe(lgr, l, &smc_lgr_list.list, list) {
830-
if (lgr->is_smcd)
831-
continue;
832-
/* tbd - terminate only when no more links are active */
833-
for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
834-
if (!smc_link_usable(&lgr->lnk[i]))
835-
continue;
836-
if (lgr->lnk[i].smcibdev == smcibdev &&
837-
lgr->lnk[i].ibport == ibport) {
838-
list_move(&lgr->list, &lgr_free_list);
839-
lgr->freeing = 1;
840-
}
841-
}
842-
}
843-
spin_unlock_bh(&smc_lgr_list.lock);
844-
845-
list_for_each_entry_safe(lgr, l, &lgr_free_list, list) {
846-
list_del_init(&lgr->list);
847-
__smc_lgr_terminate(lgr, false);
848-
}
849-
}
850-
851823
/* Called when peer lgr shutdown (regularly or abnormally) is received */
852824
void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
853825
{
@@ -1000,6 +972,79 @@ void smcr_port_add(struct smc_ib_device *smcibdev, u8 ibport)
1000972
}
1001973
}
1002974

975+
/* link is down - switch connections to alternate link,
976+
* must be called under lgr->llc_conf_mutex lock
977+
*/
978+
static void smcr_link_down(struct smc_link *lnk)
979+
{
980+
struct smc_link_group *lgr = lnk->lgr;
981+
struct smc_link *to_lnk;
982+
int del_link_id;
983+
984+
if (!lgr || lnk->state == SMC_LNK_UNUSED || list_empty(&lgr->list))
985+
return;
986+
987+
smc_ib_modify_qp_reset(lnk);
988+
to_lnk = NULL;
989+
/* tbd: call to_lnk = smc_switch_conns(lgr, lnk, true); */
990+
if (!to_lnk) { /* no backup link available */
991+
smcr_link_clear(lnk);
992+
return;
993+
}
994+
lgr->type = SMC_LGR_SINGLE;
995+
del_link_id = lnk->link_id;
996+
997+
if (lgr->role == SMC_SERV) {
998+
/* trigger local delete link processing */
999+
} else {
1000+
if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
1001+
/* another llc task is ongoing */
1002+
mutex_unlock(&lgr->llc_conf_mutex);
1003+
wait_event_interruptible_timeout(lgr->llc_waiter,
1004+
(lgr->llc_flow_lcl.type == SMC_LLC_FLOW_NONE),
1005+
SMC_LLC_WAIT_TIME);
1006+
mutex_lock(&lgr->llc_conf_mutex);
1007+
}
1008+
smc_llc_send_delete_link(to_lnk, del_link_id, SMC_LLC_REQ, true,
1009+
SMC_LLC_DEL_LOST_PATH);
1010+
}
1011+
}
1012+
1013+
/* must be called under lgr->llc_conf_mutex lock */
1014+
void smcr_link_down_cond(struct smc_link *lnk)
1015+
{
1016+
if (smc_link_downing(&lnk->state))
1017+
smcr_link_down(lnk);
1018+
}
1019+
1020+
/* will get the lgr->llc_conf_mutex lock */
1021+
void smcr_link_down_cond_sched(struct smc_link *lnk)
1022+
{
1023+
if (smc_link_downing(&lnk->state))
1024+
schedule_work(&lnk->link_down_wrk);
1025+
}
1026+
1027+
void smcr_port_err(struct smc_ib_device *smcibdev, u8 ibport)
1028+
{
1029+
struct smc_link_group *lgr, *n;
1030+
int i;
1031+
1032+
list_for_each_entry_safe(lgr, n, &smc_lgr_list.list, list) {
1033+
if (strncmp(smcibdev->pnetid[ibport - 1], lgr->pnet_id,
1034+
SMC_MAX_PNETID_LEN))
1035+
continue; /* lgr is not affected */
1036+
if (list_empty(&lgr->list))
1037+
continue;
1038+
for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
1039+
struct smc_link *lnk = &lgr->lnk[i];
1040+
1041+
if (smc_link_usable(lnk) &&
1042+
lnk->smcibdev == smcibdev && lnk->ibport == ibport)
1043+
smcr_link_down_cond_sched(lnk);
1044+
}
1045+
}
1046+
}
1047+
10031048
static void smc_link_up_work(struct work_struct *work)
10041049
{
10051050
struct smc_ib_up_work *ib_work = container_of(work,
@@ -1014,6 +1059,20 @@ static void smc_link_up_work(struct work_struct *work)
10141059
kfree(ib_work);
10151060
}
10161061

1062+
static void smc_link_down_work(struct work_struct *work)
1063+
{
1064+
struct smc_link *link = container_of(work, struct smc_link,
1065+
link_down_wrk);
1066+
struct smc_link_group *lgr = link->lgr;
1067+
1068+
if (list_empty(&lgr->list))
1069+
return;
1070+
wake_up_interruptible_all(&lgr->llc_waiter);
1071+
mutex_lock(&lgr->llc_conf_mutex);
1072+
smcr_link_down(link);
1073+
mutex_unlock(&lgr->llc_conf_mutex);
1074+
}
1075+
10171076
/* Determine vlan of internal TCP socket.
10181077
* @vlan_id: address to store the determined vlan id into
10191078
*/

net/smc/smc_core.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ struct smc_link {
117117
u8 link_id; /* unique # within link group */
118118
u8 link_idx; /* index in lgr link array */
119119
struct smc_link_group *lgr; /* parent link group */
120+
struct work_struct link_down_wrk; /* wrk to bring link down */
120121

121122
enum smc_link_state state; /* state of link */
122123
struct delayed_work llc_testlink_wrk; /* testlink worker */
@@ -344,8 +345,8 @@ struct smc_clc_msg_local;
344345
void smc_lgr_forget(struct smc_link_group *lgr);
345346
void smc_lgr_cleanup_early(struct smc_connection *conn);
346347
void smc_lgr_terminate_sched(struct smc_link_group *lgr);
347-
void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport);
348348
void smcr_port_add(struct smc_ib_device *smcibdev, u8 ibport);
349+
void smcr_port_err(struct smc_ib_device *smcibdev, u8 ibport);
349350
void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid,
350351
unsigned short vlan);
351352
void smc_smcd_terminate_all(struct smcd_dev *dev);
@@ -376,6 +377,9 @@ void smcr_link_clear(struct smc_link *lnk);
376377
int smcr_buf_map_lgr(struct smc_link *lnk);
377378
int smcr_buf_reg_lgr(struct smc_link *lnk);
378379
int smcr_link_reg_rmb(struct smc_link *link, struct smc_buf_desc *rmb_desc);
380+
void smcr_link_down_cond(struct smc_link *lnk);
381+
void smcr_link_down_cond_sched(struct smc_link *lnk);
382+
379383
static inline struct smc_link_group *smc_get_lgr(struct smc_link *link)
380384
{
381385
return link->lgr;

net/smc/smc_ib.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ static void smc_ib_port_event_work(struct work_struct *work)
249249
clear_bit(port_idx, &smcibdev->port_event_mask);
250250
if (!smc_ib_port_active(smcibdev, port_idx + 1)) {
251251
set_bit(port_idx, smcibdev->ports_going_away);
252-
smc_port_terminate(smcibdev, port_idx + 1);
252+
smcr_port_err(smcibdev, port_idx + 1);
253253
} else {
254254
clear_bit(port_idx, smcibdev->ports_going_away);
255255
smcr_port_add(smcibdev, port_idx + 1);

net/smc/smc_llc.h

+3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ enum smc_llc_msg_type {
3535
SMC_LLC_DELETE_RKEY = 0x09,
3636
};
3737

38+
#define smc_link_downing(state) \
39+
(cmpxchg(state, SMC_LNK_ACTIVE, SMC_LNK_INACTIVE) == SMC_LNK_ACTIVE)
40+
3841
/* LLC DELETE LINK Request Reason Codes */
3942
#define SMC_LLC_DEL_LOST_PATH 0x00010000
4043
#define SMC_LLC_DEL_OP_INIT_TERM 0x00020000

0 commit comments

Comments
 (0)