Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/smc: abnormal termination of SMCD link groups

A final cleanup due to SMCD device removal means immediate freeing
of all link groups belonging to this device in interrupt context.

This patch introduces a separate SMCD link group termination routine,
which terminates all link groups of an SMCD device.

This new routine smcd_terminate_all ()is reused if the smc module is
unloaded.

Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ursula Braun and committed by
David S. Miller
5421ec28 42bfba9e

+57 -21
+1 -1
net/smc/smc_clc.c
··· 349 349 smc->peer_diagnosis = ntohl(dclc->peer_diagnosis); 350 350 if (((struct smc_clc_msg_decline *)buf)->hdr.flag) { 351 351 smc->conn.lgr->sync_err = 1; 352 - smc_lgr_terminate(smc->conn.lgr); 352 + smc_lgr_terminate(smc->conn.lgr, true); 353 353 } 354 354 } 355 355
+51 -16
net/smc/smc_core.c
··· 224 224 struct smc_link_group *lgr = container_of(work, struct smc_link_group, 225 225 terminate_work); 226 226 227 - smc_lgr_terminate(lgr); 227 + smc_lgr_terminate(lgr, true); 228 228 } 229 229 230 230 /* create a new SMC link group */ ··· 528 528 } 529 529 530 530 /* kill a connection */ 531 - static void smc_conn_kill(struct smc_connection *conn) 531 + static void smc_conn_kill(struct smc_connection *conn, bool soft) 532 532 { 533 533 struct smc_sock *smc = container_of(conn, struct smc_sock, conn); 534 534 ··· 541 541 smc_sk_wake_ups(smc); 542 542 if (conn->lgr->is_smcd) { 543 543 smc_ism_unset_conn(conn); 544 - tasklet_kill(&conn->rx_tsklet); 544 + if (soft) 545 + tasklet_kill(&conn->rx_tsklet); 546 + else 547 + tasklet_unlock_wait(&conn->rx_tsklet); 545 548 } 546 549 smc_lgr_unregister_conn(conn); 547 550 smc_close_active_abort(smc); ··· 565 562 } 566 563 567 564 /* terminate link group */ 568 - static void __smc_lgr_terminate(struct smc_link_group *lgr) 565 + static void __smc_lgr_terminate(struct smc_link_group *lgr, bool soft) 569 566 { 570 567 struct smc_connection *conn; 571 568 struct smc_sock *smc; ··· 573 570 574 571 if (lgr->terminating) 575 572 return; /* lgr already terminating */ 573 + if (!soft) 574 + cancel_delayed_work_sync(&lgr->free_work); 576 575 lgr->terminating = 1; 577 576 if (!lgr->is_smcd) 578 577 smc_llc_link_inactive(&lgr->lnk[SMC_SINGLE_LINK]); ··· 588 583 smc = container_of(conn, struct smc_sock, conn); 589 584 sock_hold(&smc->sk); /* sock_put below */ 590 585 lock_sock(&smc->sk); 591 - smc_conn_kill(conn); 586 + smc_conn_kill(conn, soft); 592 587 release_sock(&smc->sk); 593 588 sock_put(&smc->sk); /* sock_hold above */ 594 589 read_lock_bh(&lgr->conns_lock); ··· 596 591 } 597 592 read_unlock_bh(&lgr->conns_lock); 598 593 smc_lgr_cleanup(lgr); 599 - smc_lgr_schedule_free_work_fast(lgr); 594 + if (soft) 595 + smc_lgr_schedule_free_work_fast(lgr); 596 + else 597 + smc_lgr_free(lgr); 600 598 } 601 599 602 - /* unlink and terminate link group */ 603 - void smc_lgr_terminate(struct smc_link_group *lgr) 600 + /* unlink and terminate link group 601 + * @soft: true if link group shutdown can take its time 602 + * false if immediate link group shutdown is required 603 + */ 604 + void smc_lgr_terminate(struct smc_link_group *lgr, bool soft) 604 605 { 605 606 spinlock_t *lgr_lock; 606 607 ··· 616 605 spin_unlock_bh(lgr_lock); 617 606 return; /* lgr already terminating */ 618 607 } 608 + if (!soft) 609 + lgr->freeing = 1; 619 610 list_del_init(&lgr->list); 620 611 spin_unlock_bh(lgr_lock); 621 - __smc_lgr_terminate(lgr); 612 + __smc_lgr_terminate(lgr, soft); 622 613 } 623 614 624 615 /* Called when IB port is terminated */ ··· 640 627 641 628 list_for_each_entry_safe(lgr, l, &lgr_free_list, list) { 642 629 list_del_init(&lgr->list); 643 - __smc_lgr_terminate(lgr); 630 + __smc_lgr_terminate(lgr, true); 644 631 } 645 632 } 646 633 647 - /* Called when SMC-D device is terminated or peer is lost */ 634 + /* Called when peer lgr shutdown (regularly or abnormally) is received */ 648 635 void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan) 649 636 { 650 637 struct smc_link_group *lgr, *l; ··· 666 653 list_for_each_entry_safe(lgr, l, &lgr_free_list, list) { 667 654 list_del_init(&lgr->list); 668 655 schedule_work(&lgr->terminate_work); 656 + } 657 + } 658 + 659 + /* Called when an SMCD device is removed or the smc module is unloaded */ 660 + void smc_smcd_terminate_all(struct smcd_dev *smcd) 661 + { 662 + struct smc_link_group *lgr, *lg; 663 + LIST_HEAD(lgr_free_list); 664 + 665 + spin_lock_bh(&smcd->lgr_lock); 666 + list_splice_init(&smcd->lgr_list, &lgr_free_list); 667 + list_for_each_entry(lgr, &lgr_free_list, list) 668 + lgr->freeing = 1; 669 + spin_unlock_bh(&smcd->lgr_lock); 670 + 671 + list_for_each_entry_safe(lgr, lg, &lgr_free_list, list) { 672 + list_del_init(&lgr->list); 673 + __smc_lgr_terminate(lgr, false); 669 674 } 670 675 } 671 676 ··· 1204 1173 spin_unlock(&smcd_dev_list.lock); 1205 1174 } 1206 1175 1207 - /* Called (from smc_exit) when module is removed */ 1208 - void smc_core_exit(void) 1176 + /* Clean up all SMC link groups */ 1177 + static void smc_lgrs_shutdown(void) 1209 1178 { 1210 1179 struct smc_link_group *lgr, *lg; 1211 1180 LIST_HEAD(lgr_freeing_list); ··· 1219 1188 1220 1189 spin_lock(&smcd_dev_list.lock); 1221 1190 list_for_each_entry(smcd, &smcd_dev_list.list, list) 1222 - list_splice_init(&smcd->lgr_list, &lgr_freeing_list); 1191 + smc_smcd_terminate_all(smcd); 1223 1192 spin_unlock(&smcd_dev_list.lock); 1224 1193 1225 1194 list_for_each_entry_safe(lgr, lg, &lgr_freeing_list, list) { ··· 1233 1202 smc_llc_link_inactive(lnk); 1234 1203 } 1235 1204 cancel_delayed_work_sync(&lgr->free_work); 1236 - if (lgr->is_smcd) 1237 - smc_ism_signal_shutdown(lgr); 1238 1205 smc_lgr_free(lgr); /* free link group */ 1239 1206 } 1207 + } 1208 + 1209 + /* Called (from smc_exit) when module is removed */ 1210 + void smc_core_exit(void) 1211 + { 1212 + smc_lgrs_shutdown(); 1240 1213 }
+2 -1
net/smc/smc_core.h
··· 296 296 struct smc_clc_msg_local; 297 297 298 298 void smc_lgr_forget(struct smc_link_group *lgr); 299 - void smc_lgr_terminate(struct smc_link_group *lgr); 299 + void smc_lgr_terminate(struct smc_link_group *lgr, bool soft); 300 300 void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport); 301 301 void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, 302 302 unsigned short vlan); 303 + void smc_smcd_terminate_all(struct smcd_dev *dev); 303 304 int smc_buf_create(struct smc_sock *smc, bool is_smcd); 304 305 int smc_uncompress_bufsize(u8 compressed); 305 306 int smc_rmb_rtoken_handling(struct smc_connection *conn,
+1 -1
net/smc/smc_ism.c
··· 329 329 list_del_init(&smcd->list); 330 330 spin_unlock(&smcd_dev_list.lock); 331 331 smcd->going_away = 1; 332 - smc_smcd_terminate(smcd, 0, VLAN_VID_MASK); 332 + smc_smcd_terminate_all(smcd); 333 333 flush_workqueue(smcd->event_wq); 334 334 destroy_workqueue(smcd->event_wq); 335 335
+1 -1
net/smc/smc_llc.c
··· 614 614 rc = wait_for_completion_interruptible_timeout(&link->llc_testlink_resp, 615 615 SMC_LLC_WAIT_TIME); 616 616 if (rc <= 0) { 617 - smc_lgr_terminate(smc_get_lgr(link)); 617 + smc_lgr_terminate(smc_get_lgr(link), true); 618 618 return; 619 619 } 620 620 next_interval = link->llc_testlink_time;
+1 -1
net/smc/smc_tx.c
··· 284 284 rdma_wr->rkey = lgr->rtokens[conn->rtoken_idx][SMC_SINGLE_LINK].rkey; 285 285 rc = ib_post_send(link->roce_qp, &rdma_wr->wr, NULL); 286 286 if (rc) 287 - smc_lgr_terminate(lgr); 287 + smc_lgr_terminate(lgr, true); 288 288 return rc; 289 289 } 290 290