Commit 50c6b20e authored by Ursula Braun's avatar Ursula Braun Committed by David S. Miller

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: default avatarUrsula Braun <ubraun@linux.ibm.com>
Signed-off-by: default avatarKarsten Graul <kgraul@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 43da44c8
...@@ -131,6 +131,9 @@ int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn) ...@@ -131,6 +131,9 @@ int smc_cdc_get_slot_and_msg_send(struct smc_connection *conn)
{ {
int rc; int rc;
if (!conn->lgr || (conn->lgr->is_smcd && conn->lgr->peer_shutdown))
return -EPIPE;
if (conn->lgr->is_smcd) { if (conn->lgr->is_smcd) {
spin_lock_bh(&conn->send_lock); spin_lock_bh(&conn->send_lock);
rc = smcd_cdc_msg_send(conn); rc = smcd_cdc_msg_send(conn);
......
...@@ -275,6 +275,7 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -275,6 +275,7 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
lgr->smcd = ini->ism_dev; lgr->smcd = ini->ism_dev;
lgr_list = &ini->ism_dev->lgr_list; lgr_list = &ini->ism_dev->lgr_list;
lgr_lock = &lgr->smcd->lgr_lock; lgr_lock = &lgr->smcd->lgr_lock;
lgr->peer_shutdown = 0;
} else { } else {
/* SMC-R specific settings */ /* SMC-R specific settings */
get_device(&ini->ib_dev->ibdev->dev); get_device(&ini->ib_dev->ibdev->dev);
...@@ -514,11 +515,16 @@ static void smc_conn_kill(struct smc_connection *conn) ...@@ -514,11 +515,16 @@ static void smc_conn_kill(struct smc_connection *conn)
{ {
struct smc_sock *smc = container_of(conn, struct smc_sock, conn); struct smc_sock *smc = container_of(conn, struct smc_sock, conn);
smc_close_abort(conn); if (conn->lgr->is_smcd && conn->lgr->peer_shutdown)
conn->local_tx_ctrl.conn_state_flags.peer_conn_abort = 1;
else
smc_close_abort(conn);
conn->killed = 1; conn->killed = 1;
smc->sk.sk_err = ECONNABORTED;
smc_sk_wake_ups(smc); smc_sk_wake_ups(smc);
if (conn->lgr->is_smcd)
tasklet_kill(&conn->rx_tsklet);
smc_lgr_unregister_conn(conn); smc_lgr_unregister_conn(conn);
smc->sk.sk_err = ECONNABORTED;
smc_close_active_abort(smc); smc_close_active_abort(smc);
} }
...@@ -604,6 +610,8 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan) ...@@ -604,6 +610,8 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
list_for_each_entry_safe(lgr, l, &dev->lgr_list, list) { list_for_each_entry_safe(lgr, l, &dev->lgr_list, list) {
if ((!peer_gid || lgr->peer_gid == peer_gid) && if ((!peer_gid || lgr->peer_gid == peer_gid) &&
(vlan == VLAN_VID_MASK || lgr->vlan_id == vlan)) { (vlan == VLAN_VID_MASK || lgr->vlan_id == vlan)) {
if (peer_gid) /* peer triggered termination */
lgr->peer_shutdown = 1;
list_move(&lgr->list, &lgr_free_list); list_move(&lgr->list, &lgr_free_list);
} }
} }
...@@ -612,11 +620,7 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan) ...@@ -612,11 +620,7 @@ void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid, unsigned short vlan)
/* cancel the regular free workers and actually free lgrs */ /* cancel the regular free workers and actually free lgrs */
list_for_each_entry_safe(lgr, l, &lgr_free_list, list) { list_for_each_entry_safe(lgr, l, &lgr_free_list, list) {
list_del_init(&lgr->list); list_del_init(&lgr->list);
__smc_lgr_terminate(lgr); schedule_work(&lgr->terminate_work);
cancel_delayed_work_sync(&lgr->free_work);
if (!peer_gid && vlan == VLAN_VID_MASK) /* dev terminated? */
smc_ism_signal_shutdown(lgr);
smc_lgr_free(lgr);
} }
} }
......
...@@ -228,6 +228,8 @@ struct smc_link_group { ...@@ -228,6 +228,8 @@ struct smc_link_group {
/* Peer GID (remote) */ /* Peer GID (remote) */
struct smcd_dev *smcd; struct smcd_dev *smcd;
/* ISM device for VLAN reg. */ /* ISM device for VLAN reg. */
u8 peer_shutdown : 1;
/* peer triggered shutdownn */
}; };
}; };
}; };
......
...@@ -226,6 +226,9 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr) ...@@ -226,6 +226,9 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr)
int rc; int rc;
union smcd_sw_event_info ev_info; union smcd_sw_event_info ev_info;
if (lgr->peer_shutdown)
return 0;
memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE); memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE);
ev_info.vlan_id = lgr->vlan_id; ev_info.vlan_id = lgr->vlan_id;
ev_info.code = ISM_EVENT_REQUEST; ev_info.code = ISM_EVENT_REQUEST;
...@@ -313,12 +316,12 @@ EXPORT_SYMBOL_GPL(smcd_register_dev); ...@@ -313,12 +316,12 @@ EXPORT_SYMBOL_GPL(smcd_register_dev);
void smcd_unregister_dev(struct smcd_dev *smcd) void smcd_unregister_dev(struct smcd_dev *smcd)
{ {
spin_lock(&smcd_dev_list.lock); spin_lock(&smcd_dev_list.lock);
list_del(&smcd->list); list_del_init(&smcd->list);
spin_unlock(&smcd_dev_list.lock); spin_unlock(&smcd_dev_list.lock);
smcd->going_away = 1; smcd->going_away = 1;
smc_smcd_terminate(smcd, 0, VLAN_VID_MASK);
flush_workqueue(smcd->event_wq); flush_workqueue(smcd->event_wq);
destroy_workqueue(smcd->event_wq); destroy_workqueue(smcd->event_wq);
smc_smcd_terminate(smcd, 0, VLAN_VID_MASK);
device_del(&smcd->dev); device_del(&smcd->dev);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment