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

net/smc: fix final cleanup sequence for SMCD devices

If peer announces shutdown, use the link group terminate worker for
local cleanup of link groups and connections to terminate link group
in proper context.

Make sure link groups are cleaned up first before destroying the
event queue of the SMCD device, because link group cleanup may
raise events.

Send signal shutdown only if peer has not done it already.

Send socket abort or close only, if peer has not already announced
shutdown.

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
50c6b20e 43da44c8

+22 -10
+3
net/smc/smc_cdc.c
··· 131 131 { 132 132 int rc; 133 133 134 + if (!conn->lgr || (conn->lgr->is_smcd && conn->lgr->peer_shutdown)) 135 + return -EPIPE; 136 + 134 137 if (conn->lgr->is_smcd) { 135 138 spin_lock_bh(&conn->send_lock); 136 139 rc = smcd_cdc_msg_send(conn);
+12 -8
net/smc/smc_core.c
··· 275 275 lgr->smcd = ini->ism_dev; 276 276 lgr_list = &ini->ism_dev->lgr_list; 277 277 lgr_lock = &lgr->smcd->lgr_lock; 278 + lgr->peer_shutdown = 0; 278 279 } else { 279 280 /* SMC-R specific settings */ 280 281 get_device(&ini->ib_dev->ibdev->dev); ··· 515 514 { 516 515 struct smc_sock *smc = container_of(conn, struct smc_sock, conn); 517 516 518 - smc_close_abort(conn); 517 + if (conn->lgr->is_smcd && conn->lgr->peer_shutdown) 518 + conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1; 519 + else 520 + smc_close_abort(conn); 519 521 conn->killed = 1; 520 - smc_sk_wake_ups(smc); 521 - smc_lgr_unregister_conn(conn); 522 522 smc->sk.sk_err = ECONNABORTED; 523 + smc_sk_wake_ups(smc); 524 + if (conn->lgr->is_smcd) 525 + tasklet_kill(&conn->rx_tsklet); 526 + smc_lgr_unregister_conn(conn); 523 527 smc_close_active_abort(smc); 524 528 } 525 529 ··· 610 604 list_for_each_entry_safe(lgr, l, &dev->lgr_list, list) { 611 605 if ((!peer_gid || lgr->peer_gid == peer_gid) && 612 606 (vlan == VLAN_VID_MASK || lgr->vlan_id == vlan)) { 607 + if (peer_gid) /* peer triggered termination */ 608 + lgr->peer_shutdown = 1; 613 609 list_move(&lgr->list, &lgr_free_list); 614 610 } 615 611 } ··· 620 612 /* cancel the regular free workers and actually free lgrs */ 621 613 list_for_each_entry_safe(lgr, l, &lgr_free_list, list) { 622 614 list_del_init(&lgr->list); 623 - __smc_lgr_terminate(lgr); 624 - cancel_delayed_work_sync(&lgr->free_work); 625 - if (!peer_gid && vlan == VLAN_VID_MASK) /* dev terminated? */ 626 - smc_ism_signal_shutdown(lgr); 627 - smc_lgr_free(lgr); 615 + schedule_work(&lgr->terminate_work); 628 616 } 629 617 } 630 618
+2
net/smc/smc_core.h
··· 228 228 /* Peer GID (remote) */ 229 229 struct smcd_dev *smcd; 230 230 /* ISM device for VLAN reg. */ 231 + u8 peer_shutdown : 1; 232 + /* peer triggered shutdownn */ 231 233 }; 232 234 }; 233 235 };
+5 -2
net/smc/smc_ism.c
··· 226 226 int rc; 227 227 union smcd_sw_event_info ev_info; 228 228 229 + if (lgr->peer_shutdown) 230 + return 0; 231 + 229 232 memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE); 230 233 ev_info.vlan_id = lgr->vlan_id; 231 234 ev_info.code = ISM_EVENT_REQUEST; ··· 316 313 void smcd_unregister_dev(struct smcd_dev *smcd) 317 314 { 318 315 spin_lock(&smcd_dev_list.lock); 319 - list_del(&smcd->list); 316 + list_del_init(&smcd->list); 320 317 spin_unlock(&smcd_dev_list.lock); 321 318 smcd->going_away = 1; 319 + smc_smcd_terminate(smcd, 0, VLAN_VID_MASK); 322 320 flush_workqueue(smcd->event_wq); 323 321 destroy_workqueue(smcd->event_wq); 324 - smc_smcd_terminate(smcd, 0, VLAN_VID_MASK); 325 322 326 323 device_del(&smcd->dev); 327 324 }