diff options
author | Karsten Graul <kgraul@linux.ibm.com> | 2018-07-25 10:35:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-07-26 01:25:53 -0400 |
commit | 0d18a0cb4b1585d9e5a3b300d5df9ed866561ffb (patch) | |
tree | 1c854a0d55d1e3636aa7f75674712c233eabb36c /net/smc | |
parent | 603cc1498455cf57f5ca4483b600efb37ea2c56c (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.c | 47 | ||||
-rw-r--r-- | net/smc/smc_core.h | 4 | ||||
-rw-r--r-- | net/smc/smc_llc.c | 30 | ||||
-rw-r--r-- | net/smc/smc_llc.h | 3 | ||||
-rw-r--r-- | net/smc/smc_wr.c | 7 |
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 | ||
34 | static struct smc_lgr_list smc_lgr_list = { /* established link groups */ | 35 | static 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 | ||
55 | void 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 | */ | ||
146 | static 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 | |||
136 | static void smc_lgr_free_work(struct work_struct *work) | 156 | static 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 */ |
154 | free: | 174 | free: |
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 */ | |||
34 | enum smc_link_state { /* possible states of a link */ | 34 | enum 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); |
267 | void smcd_conn_free(struct smc_connection *conn); | 268 | void smcd_conn_free(struct smc_connection *conn); |
269 | void smc_lgr_schedule_free_work_fast(struct smc_link_group *lgr); | ||
268 | void smc_core_exit(void); | 270 | void smc_core_exit(void); |
269 | 271 | ||
270 | static inline struct smc_link_group *smc_get_lgr(struct smc_link *link) | 272 | static 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 */ |
279 | static void smc_llc_prep_delete_link(struct smc_llc_msg_del_link *delllc, | 279 | static 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 */ |
295 | int smc_llc_send_delete_link(struct smc_link *link, | 296 | int 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 | ||
628 | void 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 */ |
626 | void smc_llc_link_inactive(struct smc_link *link) | 634 | void 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, | |||
41 | int smc_llc_send_add_link(struct smc_link *link, u8 mac[], u8 gid[], | 41 | int 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); |
43 | int smc_llc_send_delete_link(struct smc_link *link, | 43 | int smc_llc_send_delete_link(struct smc_link *link, |
44 | enum smc_llc_reqresp reqresp); | 44 | enum smc_llc_reqresp reqresp, bool orderly); |
45 | int smc_llc_link_init(struct smc_link *link); | 45 | int smc_llc_link_init(struct smc_link *link); |
46 | void smc_llc_link_active(struct smc_link *link, int testlink_time); | 46 | void smc_llc_link_active(struct smc_link *link, int testlink_time); |
47 | void smc_llc_link_deleting(struct smc_link *link); | ||
47 | void smc_llc_link_inactive(struct smc_link *link); | 48 | void smc_llc_link_inactive(struct smc_link *link); |
48 | void smc_llc_link_clear(struct smc_link *link); | 49 | void smc_llc_link_clear(struct smc_link *link); |
49 | int smc_llc_do_confirm_rkey(struct smc_link *link, | 50 | int 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) |