Commit c3d9494e authored by Ursula Braun's avatar Ursula Braun Committed by Jakub Kicinski

net/smc: no new connections on disappearing devices

Add a "going_away" indication to ISM devices and IB ports and
avoid creation of new connections on such disappearing devices.

And do not handle ISM events if ISM device is disappearing.
Signed-off-by: default avatarUrsula Braun <ubraun@linux.ibm.com>
Signed-off-by: default avatarKarsten Graul <kgraul@linux.ibm.com>
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
parent b3cb53c0
...@@ -77,6 +77,7 @@ struct smcd_dev { ...@@ -77,6 +77,7 @@ struct smcd_dev {
bool pnetid_by_user; bool pnetid_by_user;
struct list_head lgr_list; struct list_head lgr_list;
spinlock_t lgr_lock; spinlock_t lgr_lock;
u8 going_away : 1;
}; };
struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name, struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
......
...@@ -1060,6 +1060,27 @@ int smc_rmb_rtoken_handling(struct smc_connection *conn, ...@@ -1060,6 +1060,27 @@ int smc_rmb_rtoken_handling(struct smc_connection *conn,
return 0; return 0;
} }
static void smc_core_going_away(void)
{
struct smc_ib_device *smcibdev;
struct smcd_dev *smcd;
spin_lock(&smc_ib_devices.lock);
list_for_each_entry(smcibdev, &smc_ib_devices.list, list) {
int i;
for (i = 0; i < SMC_MAX_PORTS; i++)
set_bit(i, smcibdev->ports_going_away);
}
spin_unlock(&smc_ib_devices.lock);
spin_lock(&smcd_dev_list.lock);
list_for_each_entry(smcd, &smcd_dev_list.list, list) {
smcd->going_away = 1;
}
spin_unlock(&smcd_dev_list.lock);
}
/* Called (from smc_exit) when module is removed */ /* Called (from smc_exit) when module is removed */
void smc_core_exit(void) void smc_core_exit(void)
{ {
...@@ -1067,6 +1088,8 @@ void smc_core_exit(void) ...@@ -1067,6 +1088,8 @@ void smc_core_exit(void)
LIST_HEAD(lgr_freeing_list); LIST_HEAD(lgr_freeing_list);
struct smcd_dev *smcd; struct smcd_dev *smcd;
smc_core_going_away();
spin_lock_bh(&smc_lgr_list.lock); spin_lock_bh(&smc_lgr_list.lock);
list_splice_init(&smc_lgr_list.list, &lgr_freeing_list); list_splice_init(&smc_lgr_list.list, &lgr_freeing_list);
spin_unlock_bh(&smc_lgr_list.lock); spin_unlock_bh(&smc_lgr_list.lock);
......
...@@ -242,8 +242,12 @@ static void smc_ib_port_event_work(struct work_struct *work) ...@@ -242,8 +242,12 @@ static void smc_ib_port_event_work(struct work_struct *work)
for_each_set_bit(port_idx, &smcibdev->port_event_mask, SMC_MAX_PORTS) { for_each_set_bit(port_idx, &smcibdev->port_event_mask, SMC_MAX_PORTS) {
smc_ib_remember_port_attr(smcibdev, port_idx + 1); smc_ib_remember_port_attr(smcibdev, port_idx + 1);
clear_bit(port_idx, &smcibdev->port_event_mask); clear_bit(port_idx, &smcibdev->port_event_mask);
if (!smc_ib_port_active(smcibdev, port_idx + 1)) if (!smc_ib_port_active(smcibdev, port_idx + 1)) {
set_bit(port_idx, smcibdev->ports_going_away);
smc_port_terminate(smcibdev, port_idx + 1); smc_port_terminate(smcibdev, port_idx + 1);
} else {
clear_bit(port_idx, smcibdev->ports_going_away);
}
} }
} }
...@@ -259,8 +263,10 @@ static void smc_ib_global_event_handler(struct ib_event_handler *handler, ...@@ -259,8 +263,10 @@ static void smc_ib_global_event_handler(struct ib_event_handler *handler,
switch (ibevent->event) { switch (ibevent->event) {
case IB_EVENT_DEVICE_FATAL: case IB_EVENT_DEVICE_FATAL:
/* terminate all ports on device */ /* terminate all ports on device */
for (port_idx = 0; port_idx < SMC_MAX_PORTS; port_idx++) for (port_idx = 0; port_idx < SMC_MAX_PORTS; port_idx++) {
set_bit(port_idx, &smcibdev->port_event_mask); set_bit(port_idx, &smcibdev->port_event_mask);
set_bit(port_idx, smcibdev->ports_going_away);
}
schedule_work(&smcibdev->port_event_work); schedule_work(&smcibdev->port_event_work);
break; break;
case IB_EVENT_PORT_ERR: case IB_EVENT_PORT_ERR:
...@@ -269,6 +275,10 @@ static void smc_ib_global_event_handler(struct ib_event_handler *handler, ...@@ -269,6 +275,10 @@ static void smc_ib_global_event_handler(struct ib_event_handler *handler,
port_idx = ibevent->element.port_num - 1; port_idx = ibevent->element.port_num - 1;
if (port_idx < SMC_MAX_PORTS) { if (port_idx < SMC_MAX_PORTS) {
set_bit(port_idx, &smcibdev->port_event_mask); set_bit(port_idx, &smcibdev->port_event_mask);
if (ibevent->event == IB_EVENT_PORT_ERR)
set_bit(port_idx, smcibdev->ports_going_away);
else if (ibevent->event == IB_EVENT_PORT_ACTIVE)
clear_bit(port_idx, smcibdev->ports_going_away);
schedule_work(&smcibdev->port_event_work); schedule_work(&smcibdev->port_event_work);
} }
break; break;
...@@ -307,6 +317,7 @@ static void smc_ib_qp_event_handler(struct ib_event *ibevent, void *priv) ...@@ -307,6 +317,7 @@ static void smc_ib_qp_event_handler(struct ib_event *ibevent, void *priv)
port_idx = ibevent->element.qp->port - 1; port_idx = ibevent->element.qp->port - 1;
if (port_idx < SMC_MAX_PORTS) { if (port_idx < SMC_MAX_PORTS) {
set_bit(port_idx, &smcibdev->port_event_mask); set_bit(port_idx, &smcibdev->port_event_mask);
set_bit(port_idx, smcibdev->ports_going_away);
schedule_work(&smcibdev->port_event_work); schedule_work(&smcibdev->port_event_work);
} }
break; break;
......
...@@ -47,6 +47,7 @@ struct smc_ib_device { /* ib-device infos for smc */ ...@@ -47,6 +47,7 @@ struct smc_ib_device { /* ib-device infos for smc */
u8 initialized : 1; /* ib dev CQ, evthdl done */ u8 initialized : 1; /* ib dev CQ, evthdl done */
struct work_struct port_event_work; struct work_struct port_event_work;
unsigned long port_event_mask; unsigned long port_event_mask;
DECLARE_BITMAP(ports_going_away, SMC_MAX_PORTS);
}; };
struct smc_buf_desc; struct smc_buf_desc;
......
...@@ -315,6 +315,7 @@ void smcd_unregister_dev(struct smcd_dev *smcd) ...@@ -315,6 +315,7 @@ 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(&smcd->list);
spin_unlock(&smcd_dev_list.lock); spin_unlock(&smcd_dev_list.lock);
smcd->going_away = 1;
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); smc_smcd_terminate(smcd, 0, VLAN_VID_MASK);
...@@ -344,6 +345,8 @@ void smcd_handle_event(struct smcd_dev *smcd, struct smcd_event *event) ...@@ -344,6 +345,8 @@ void smcd_handle_event(struct smcd_dev *smcd, struct smcd_event *event)
{ {
struct smc_ism_event_work *wrk; struct smc_ism_event_work *wrk;
if (smcd->going_away)
return;
/* copy event to event work queue, and let it be handled there */ /* copy event to event work queue, and let it be handled there */
wrk = kmalloc(sizeof(*wrk), GFP_ATOMIC); wrk = kmalloc(sizeof(*wrk), GFP_ATOMIC);
if (!wrk) if (!wrk)
......
...@@ -781,6 +781,7 @@ static void smc_pnet_find_rdma_dev(struct net_device *netdev, ...@@ -781,6 +781,7 @@ static void smc_pnet_find_rdma_dev(struct net_device *netdev,
dev_put(ndev); dev_put(ndev);
if (netdev == ndev && if (netdev == ndev &&
smc_ib_port_active(ibdev, i) && smc_ib_port_active(ibdev, i) &&
!test_bit(i - 1, ibdev->ports_going_away) &&
!smc_ib_determine_gid(ibdev, i, ini->vlan_id, !smc_ib_determine_gid(ibdev, i, ini->vlan_id,
ini->ib_gid, NULL)) { ini->ib_gid, NULL)) {
ini->ib_dev = ibdev; ini->ib_dev = ibdev;
...@@ -820,6 +821,7 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev, ...@@ -820,6 +821,7 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
continue; continue;
if (smc_pnet_match(ibdev->pnetid[i - 1], ndev_pnetid) && if (smc_pnet_match(ibdev->pnetid[i - 1], ndev_pnetid) &&
smc_ib_port_active(ibdev, i) && smc_ib_port_active(ibdev, i) &&
!test_bit(i - 1, ibdev->ports_going_away) &&
!smc_ib_determine_gid(ibdev, i, ini->vlan_id, !smc_ib_determine_gid(ibdev, i, ini->vlan_id,
ini->ib_gid, NULL)) { ini->ib_gid, NULL)) {
ini->ib_dev = ibdev; ini->ib_dev = ibdev;
...@@ -846,7 +848,8 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev, ...@@ -846,7 +848,8 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
spin_lock(&smcd_dev_list.lock); spin_lock(&smcd_dev_list.lock);
list_for_each_entry(ismdev, &smcd_dev_list.list, list) { list_for_each_entry(ismdev, &smcd_dev_list.list, list) {
if (smc_pnet_match(ismdev->pnetid, ndev_pnetid)) { if (smc_pnet_match(ismdev->pnetid, ndev_pnetid) &&
!ismdev->going_away) {
ini->ism_dev = ismdev; ini->ism_dev = ismdev;
break; break;
} }
......
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