aboutsummaryrefslogtreecommitdiffstats
path: root/net/smc
diff options
context:
space:
mode:
authorKarsten Graul <kgraul@linux.ibm.com>2018-07-25 10:35:33 -0400
committerDavid S. Miller <davem@davemloft.net>2018-07-26 01:25:53 -0400
commit0d18a0cb4b1585d9e5a3b300d5df9ed866561ffb (patch)
tree1c854a0d55d1e3636aa7f75674712c233eabb36c /net/smc
parent603cc1498455cf57f5ca4483b600efb37ea2c56c (diff)
net/smc: improve delete link processing
Send an orderly DELETE LINK request before termination of a link group, add support for client triggered DELETE LINK processing. And send a disorderly DELETE LINK before module is unloaded. Signed-off-by: Karsten Graul <kgraul@linux.ibm.com> Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/smc')
-rw-r--r--net/smc/smc_core.c47
-rw-r--r--net/smc/smc_core.h4
-rw-r--r--net/smc/smc_llc.c30
-rw-r--r--net/smc/smc_llc.h3
-rw-r--r--net/smc/smc_wr.c7
5 files changed, 68 insertions, 23 deletions
diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
index 90c10ae9ae09..a46418f45ecd 100644
--- a/net/smc/smc_core.c
+++ b/net/smc/smc_core.c
@@ -30,6 +30,7 @@
30#define SMC_LGR_NUM_INCR 256 30#define SMC_LGR_NUM_INCR 256
31#define SMC_LGR_FREE_DELAY_SERV (600 * HZ) 31#define SMC_LGR_FREE_DELAY_SERV (600 * HZ)
32#define SMC_LGR_FREE_DELAY_CLNT (SMC_LGR_FREE_DELAY_SERV + 10 * HZ) 32#define SMC_LGR_FREE_DELAY_CLNT (SMC_LGR_FREE_DELAY_SERV + 10 * HZ)
33#define SMC_LGR_FREE_DELAY_FAST (8 * HZ)
33 34
34static struct smc_lgr_list smc_lgr_list = { /* established link groups */ 35static struct smc_lgr_list smc_lgr_list = { /* established link groups */
35 .lock = __SPIN_LOCK_UNLOCKED(smc_lgr_list.lock), 36 .lock = __SPIN_LOCK_UNLOCKED(smc_lgr_list.lock),
@@ -51,6 +52,11 @@ static void smc_lgr_schedule_free_work(struct smc_link_group *lgr)
51 SMC_LGR_FREE_DELAY_CLNT : SMC_LGR_FREE_DELAY_SERV); 52 SMC_LGR_FREE_DELAY_CLNT : SMC_LGR_FREE_DELAY_SERV);
52} 53}
53 54
55void smc_lgr_schedule_free_work_fast(struct smc_link_group *lgr)
56{
57 mod_delayed_work(system_wq, &lgr->free_work, SMC_LGR_FREE_DELAY_FAST);
58}
59
54/* Register connection's alert token in our lookup structure. 60/* Register connection's alert token in our lookup structure.
55 * To use rbtrees we have to implement our own insert core. 61 * To use rbtrees we have to implement our own insert core.
56 * Requires @conns_lock 62 * Requires @conns_lock
@@ -133,6 +139,20 @@ static void smc_lgr_unregister_conn(struct smc_connection *conn)
133 smc_lgr_schedule_free_work(lgr); 139 smc_lgr_schedule_free_work(lgr);
134} 140}
135 141
142/* Send delete link, either as client to request the initiation
143 * of the DELETE LINK sequence from server; or as server to
144 * initiate the delete processing. See smc_llc_rx_delete_link().
145 */
146static int smc_link_send_delete(struct smc_link *lnk)
147{
148 if (lnk->state == SMC_LNK_ACTIVE &&
149 !smc_llc_send_delete_link(lnk, SMC_LLC_REQ, true)) {
150 smc_llc_link_deleting(lnk);
151 return 0;
152 }
153 return -ENOTCONN;
154}
155
136static void smc_lgr_free_work(struct work_struct *work) 156static void smc_lgr_free_work(struct work_struct *work)
137{ 157{
138 struct smc_link_group *lgr = container_of(to_delayed_work(work), 158 struct smc_link_group *lgr = container_of(to_delayed_work(work),
@@ -153,10 +173,21 @@ static void smc_lgr_free_work(struct work_struct *work)
153 list_del_init(&lgr->list); /* remove from smc_lgr_list */ 173 list_del_init(&lgr->list); /* remove from smc_lgr_list */
154free: 174free:
155 spin_unlock_bh(&smc_lgr_list.lock); 175 spin_unlock_bh(&smc_lgr_list.lock);
176
177 if (!lgr->is_smcd && !lgr->terminating) {
178 /* try to send del link msg, on error free lgr immediately */
179 if (!smc_link_send_delete(&lgr->lnk[SMC_SINGLE_LINK])) {
180 /* reschedule in case we never receive a response */
181 smc_lgr_schedule_free_work(lgr);
182 return;
183 }
184 }
185
156 if (!delayed_work_pending(&lgr->free_work)) { 186 if (!delayed_work_pending(&lgr->free_work)) {
157 if (!lgr->is_smcd && 187 struct smc_link *lnk = &lgr->lnk[SMC_SINGLE_LINK];
158 lgr->lnk[SMC_SINGLE_LINK].state != SMC_LNK_INACTIVE) 188
159 smc_llc_link_inactive(&lgr->lnk[SMC_SINGLE_LINK]); 189 if (!lgr->is_smcd && lnk->state != SMC_LNK_INACTIVE)
190 smc_llc_link_inactive(lnk);
160 smc_lgr_free(lgr); 191 smc_lgr_free(lgr);
161 } 192 }
162} 193}
@@ -984,8 +1015,14 @@ void smc_core_exit(void)
984 spin_unlock_bh(&smc_lgr_list.lock); 1015 spin_unlock_bh(&smc_lgr_list.lock);
985 list_for_each_entry_safe(lgr, lg, &lgr_freeing_list, list) { 1016 list_for_each_entry_safe(lgr, lg, &lgr_freeing_list, list) {
986 list_del_init(&lgr->list); 1017 list_del_init(&lgr->list);
987 if (!lgr->is_smcd) 1018 if (!lgr->is_smcd) {
988 smc_llc_link_inactive(&lgr->lnk[SMC_SINGLE_LINK]); 1019 struct smc_link *lnk = &lgr->lnk[SMC_SINGLE_LINK];
1020
1021 if (lnk->state == SMC_LNK_ACTIVE)
1022 smc_llc_send_delete_link(lnk, SMC_LLC_REQ,
1023 false);
1024 smc_llc_link_inactive(lnk);
1025 }
989 cancel_delayed_work_sync(&lgr->free_work); 1026 cancel_delayed_work_sync(&lgr->free_work);
990 smc_lgr_free(lgr); /* free link group */ 1027 smc_lgr_free(lgr); /* free link group */
991 } 1028 }
diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h
index a4f0cc4e0270..c156674733c9 100644
--- a/net/smc/smc_core.h
+++ b/net/smc/smc_core.h
@@ -34,7 +34,8 @@ enum smc_lgr_role { /* possible roles of a link group */
34enum smc_link_state { /* possible states of a link */ 34enum smc_link_state { /* possible states of a link */
35 SMC_LNK_INACTIVE, /* link is inactive */ 35 SMC_LNK_INACTIVE, /* link is inactive */
36 SMC_LNK_ACTIVATING, /* link is being activated */ 36 SMC_LNK_ACTIVATING, /* link is being activated */
37 SMC_LNK_ACTIVE /* link is active */ 37 SMC_LNK_ACTIVE, /* link is active */
38 SMC_LNK_DELETING, /* link is being deleted */
38}; 39};
39 40
40#define SMC_WR_BUF_SIZE 48 /* size of work request buffer */ 41#define SMC_WR_BUF_SIZE 48 /* size of work request buffer */
@@ -265,6 +266,7 @@ int smc_conn_create(struct smc_sock *smc, bool is_smcd, int srv_first_contact,
265 struct smc_clc_msg_local *lcl, struct smcd_dev *smcd, 266 struct smc_clc_msg_local *lcl, struct smcd_dev *smcd,
266 u64 peer_gid); 267 u64 peer_gid);
267void smcd_conn_free(struct smc_connection *conn); 268void smcd_conn_free(struct smc_connection *conn);
269void smc_lgr_schedule_free_work_fast(struct smc_link_group *lgr);
268void smc_core_exit(void); 270void smc_core_exit(void);
269 271
270static inline struct smc_link_group *smc_get_lgr(struct smc_link *link) 272static inline struct smc_link_group *smc_get_lgr(struct smc_link *link)
diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c
index a88c01029fa6..9c916c709ca7 100644
--- a/net/smc/smc_llc.c
+++ b/net/smc/smc_llc.c
@@ -278,7 +278,7 @@ int smc_llc_send_add_link(struct smc_link *link, u8 mac[], u8 gid[],
278/* prepare a delete link message */ 278/* prepare a delete link message */
279static void smc_llc_prep_delete_link(struct smc_llc_msg_del_link *delllc, 279static void smc_llc_prep_delete_link(struct smc_llc_msg_del_link *delllc,
280 struct smc_link *link, 280 struct smc_link *link,
281 enum smc_llc_reqresp reqresp) 281 enum smc_llc_reqresp reqresp, bool orderly)
282{ 282{
283 memset(delllc, 0, sizeof(*delllc)); 283 memset(delllc, 0, sizeof(*delllc));
284 delllc->hd.common.type = SMC_LLC_DELETE_LINK; 284 delllc->hd.common.type = SMC_LLC_DELETE_LINK;
@@ -287,13 +287,14 @@ static void smc_llc_prep_delete_link(struct smc_llc_msg_del_link *delllc,
287 delllc->hd.flags |= SMC_LLC_FLAG_RESP; 287 delllc->hd.flags |= SMC_LLC_FLAG_RESP;
288 /* DEL_LINK_ALL because only 1 link supported */ 288 /* DEL_LINK_ALL because only 1 link supported */
289 delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ALL; 289 delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ALL;
290 delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ORDERLY; 290 if (orderly)
291 delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ORDERLY;
291 delllc->link_num = link->link_id; 292 delllc->link_num = link->link_id;
292} 293}
293 294
294/* send DELETE LINK request or response */ 295/* send DELETE LINK request or response */
295int smc_llc_send_delete_link(struct smc_link *link, 296int smc_llc_send_delete_link(struct smc_link *link,
296 enum smc_llc_reqresp reqresp) 297 enum smc_llc_reqresp reqresp, bool orderly)
297{ 298{
298 struct smc_llc_msg_del_link *delllc; 299 struct smc_llc_msg_del_link *delllc;
299 struct smc_wr_tx_pend_priv *pend; 300 struct smc_wr_tx_pend_priv *pend;
@@ -304,7 +305,7 @@ int smc_llc_send_delete_link(struct smc_link *link,
304 if (rc) 305 if (rc)
305 return rc; 306 return rc;
306 delllc = (struct smc_llc_msg_del_link *)wr_buf; 307 delllc = (struct smc_llc_msg_del_link *)wr_buf;
307 smc_llc_prep_delete_link(delllc, link, reqresp); 308 smc_llc_prep_delete_link(delllc, link, reqresp, orderly);
308 /* send llc message */ 309 /* send llc message */
309 rc = smc_wr_tx_send(link, pend); 310 rc = smc_wr_tx_send(link, pend);
310 return rc; 311 return rc;
@@ -438,17 +439,19 @@ static void smc_llc_rx_delete_link(struct smc_link *link,
438 439
439 if (llc->hd.flags & SMC_LLC_FLAG_RESP) { 440 if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
440 if (lgr->role == SMC_SERV) 441 if (lgr->role == SMC_SERV)
441 smc_lgr_terminate(lgr); 442 smc_lgr_schedule_free_work_fast(lgr);
442 } else { 443 } else {
444 smc_lgr_forget(lgr);
445 smc_llc_link_deleting(link);
443 if (lgr->role == SMC_SERV) { 446 if (lgr->role == SMC_SERV) {
444 smc_lgr_forget(lgr); 447 /* client asks to delete this link, send request */
445 smc_llc_prep_delete_link(llc, link, SMC_LLC_REQ); 448 smc_llc_prep_delete_link(llc, link, SMC_LLC_REQ, true);
446 smc_llc_send_message(link, llc, sizeof(*llc));
447 } else { 449 } else {
448 smc_llc_prep_delete_link(llc, link, SMC_LLC_RESP); 450 /* server requests to delete this link, send response */
449 smc_llc_send_message(link, llc, sizeof(*llc)); 451 smc_llc_prep_delete_link(llc, link, SMC_LLC_RESP, true);
450 smc_lgr_terminate(lgr);
451 } 452 }
453 smc_llc_send_message(link, llc, sizeof(*llc));
454 smc_lgr_schedule_free_work_fast(lgr);
452 } 455 }
453} 456}
454 457
@@ -622,6 +625,11 @@ void smc_llc_link_active(struct smc_link *link, int testlink_time)
622 } 625 }
623} 626}
624 627
628void smc_llc_link_deleting(struct smc_link *link)
629{
630 link->state = SMC_LNK_DELETING;
631}
632
625/* called in tasklet context */ 633/* called in tasklet context */
626void smc_llc_link_inactive(struct smc_link *link) 634void smc_llc_link_inactive(struct smc_link *link)
627{ 635{
diff --git a/net/smc/smc_llc.h b/net/smc/smc_llc.h
index 95a7f3662e59..9e2ff088e301 100644
--- a/net/smc/smc_llc.h
+++ b/net/smc/smc_llc.h
@@ -41,9 +41,10 @@ int smc_llc_send_confirm_link(struct smc_link *lnk,
41int smc_llc_send_add_link(struct smc_link *link, u8 mac[], u8 gid[], 41int smc_llc_send_add_link(struct smc_link *link, u8 mac[], u8 gid[],
42 enum smc_llc_reqresp reqresp); 42 enum smc_llc_reqresp reqresp);
43int smc_llc_send_delete_link(struct smc_link *link, 43int smc_llc_send_delete_link(struct smc_link *link,
44 enum smc_llc_reqresp reqresp); 44 enum smc_llc_reqresp reqresp, bool orderly);
45int smc_llc_link_init(struct smc_link *link); 45int smc_llc_link_init(struct smc_link *link);
46void smc_llc_link_active(struct smc_link *link, int testlink_time); 46void smc_llc_link_active(struct smc_link *link, int testlink_time);
47void smc_llc_link_deleting(struct smc_link *link);
47void smc_llc_link_inactive(struct smc_link *link); 48void smc_llc_link_inactive(struct smc_link *link);
48void smc_llc_link_clear(struct smc_link *link); 49void smc_llc_link_clear(struct smc_link *link);
49int smc_llc_do_confirm_rkey(struct smc_link *link, 50int smc_llc_do_confirm_rkey(struct smc_link *link,
diff --git a/net/smc/smc_wr.c b/net/smc/smc_wr.c
index b6df69756bef..f856b8402b3f 100644
--- a/net/smc/smc_wr.c
+++ b/net/smc/smc_wr.c
@@ -182,17 +182,14 @@ int smc_wr_tx_get_free_slot(struct smc_link *link,
182 if (rc) 182 if (rc)
183 return rc; 183 return rc;
184 } else { 184 } else {
185 struct smc_link_group *lgr;
186
187 lgr = smc_get_lgr(link);
188 rc = wait_event_timeout( 185 rc = wait_event_timeout(
189 link->wr_tx_wait, 186 link->wr_tx_wait,
190 list_empty(&lgr->list) || /* lgr terminated */ 187 link->state == SMC_LNK_INACTIVE ||
191 (smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY), 188 (smc_wr_tx_get_free_slot_index(link, &idx) != -EBUSY),
192 SMC_WR_TX_WAIT_FREE_SLOT_TIME); 189 SMC_WR_TX_WAIT_FREE_SLOT_TIME);
193 if (!rc) { 190 if (!rc) {
194 /* timeout - terminate connections */ 191 /* timeout - terminate connections */
195 smc_lgr_terminate(lgr); 192 smc_lgr_terminate(smc_get_lgr(link));
196 return -EPIPE; 193 return -EPIPE;
197 } 194 }
198 if (idx == link->wr_tx_cnt) 195 if (idx == link->wr_tx_cnt)