diff options
-rw-r--r-- | include/net/smc.h | 2 | ||||
-rw-r--r-- | net/smc/smc_core.c | 6 | ||||
-rw-r--r-- | net/smc/smc_ism.c | 1 |
3 files changed, 9 insertions, 0 deletions
diff --git a/include/net/smc.h b/include/net/smc.h index 7c2082341bb3..646feb4bc75f 100644 --- a/include/net/smc.h +++ b/include/net/smc.h @@ -79,6 +79,8 @@ struct smcd_dev { bool pnetid_by_user; struct list_head lgr_list; spinlock_t lgr_lock; + atomic_t lgr_cnt; + wait_queue_head_t lgrs_deleted; u8 going_away : 1; }; diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index d79dd78c1cd8..30854acb846c 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -276,6 +276,7 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini) lgr_list = &ini->ism_dev->lgr_list; lgr_lock = &lgr->smcd->lgr_lock; lgr->peer_shutdown = 0; + atomic_inc(&ini->ism_dev->lgr_cnt); } else { /* SMC-R specific settings */ get_device(&ini->ib_dev->ibdev->dev); @@ -486,6 +487,8 @@ static void smc_lgr_free(struct smc_link_group *lgr) smc_ism_put_vlan(lgr->smcd, lgr->vlan_id); put_device(&lgr->smcd->dev); } + if (!atomic_dec_return(&lgr->smcd->lgr_cnt)) + wake_up(&lgr->smcd->lgrs_deleted); } else { smc_link_clear(&lgr->lnk[SMC_SINGLE_LINK]); put_device(&lgr->lnk[SMC_SINGLE_LINK].smcibdev->ibdev->dev); @@ -685,6 +688,9 @@ void smc_smcd_terminate_all(struct smcd_dev *smcd) list_del_init(&lgr->list); __smc_lgr_terminate(lgr, false); } + + if (atomic_read(&smcd->lgr_cnt)) + wait_event(smcd->lgrs_deleted, !atomic_read(&smcd->lgr_cnt)); } /* Determine vlan of internal TCP socket. diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c index 56cdab8be1fa..5c4727d5066e 100644 --- a/net/smc/smc_ism.c +++ b/net/smc/smc_ism.c @@ -302,6 +302,7 @@ struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name, spin_lock_init(&smcd->lgr_lock); INIT_LIST_HEAD(&smcd->vlan); INIT_LIST_HEAD(&smcd->lgr_list); + init_waitqueue_head(&smcd->lgrs_deleted); smcd->event_wq = alloc_ordered_workqueue("ism_evt_wq-%s)", WQ_MEM_RECLAIM, name); if (!smcd->event_wq) { |