Merge branch 'smc-last-part-of-termination-improvements'

Karsten Graul says:

====================
last part of termination improvements

Patches 1 and 2 finish the set of termination patches, introducing
a reboot handler that terminates all link groups. Patch 3 adds an
rcu_barrier before the module is unloaded, and patch 4 is cleanup.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2019-11-16 12:26:49 -08:00
commit 3af7ff93e4
6 changed files with 61 additions and 8 deletions

View file

@ -25,6 +25,7 @@
#include <linux/in.h>
#include <linux/sched/signal.h>
#include <linux/if_vlan.h>
#include <linux/rcupdate_wait.h>
#include <net/sock.h>
#include <net/tcp.h>
@ -2038,22 +2039,28 @@ static int __init smc_init(void)
if (rc)
goto out_pernet_subsys;
rc = smc_core_init();
if (rc) {
pr_err("%s: smc_core_init fails with %d\n", __func__, rc);
goto out_pnet;
}
rc = smc_llc_init();
if (rc) {
pr_err("%s: smc_llc_init fails with %d\n", __func__, rc);
goto out_pnet;
goto out_core;
}
rc = smc_cdc_init();
if (rc) {
pr_err("%s: smc_cdc_init fails with %d\n", __func__, rc);
goto out_pnet;
goto out_core;
}
rc = proto_register(&smc_proto, 1);
if (rc) {
pr_err("%s: proto_register(v4) fails with %d\n", __func__, rc);
goto out_pnet;
goto out_core;
}
rc = proto_register(&smc_proto6, 1);
@ -2085,6 +2092,8 @@ out_proto6:
proto_unregister(&smc_proto6);
out_proto:
proto_unregister(&smc_proto);
out_core:
smc_core_exit();
out_pnet:
smc_pnet_exit();
out_pernet_subsys:
@ -2095,14 +2104,15 @@ out_pernet_subsys:
static void __exit smc_exit(void)
{
smc_core_exit();
static_branch_disable(&tcp_have_smc);
smc_ib_unregister_client();
sock_unregister(PF_SMC);
smc_core_exit();
smc_ib_unregister_client();
proto_unregister(&smc_proto6);
proto_unregister(&smc_proto);
smc_pnet_exit();
unregister_pernet_subsys(&smc_net_ops);
rcu_barrier();
}
module_init(smc_init);

View file

@ -20,8 +20,6 @@
#include "smc_cdc.h"
#include "smc_close.h"
#define SMC_CLOSE_WAIT_LISTEN_CLCSOCK_TIME (5 * HZ)
/* release the clcsock that is assigned to the smc_sock */
void smc_clcsock_release(struct smc_sock *smc)
{

View file

@ -13,6 +13,8 @@
#include <linux/if_vlan.h>
#include <linux/random.h>
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/reboot.h>
#include <net/tcp.h>
#include <net/sock.h>
#include <rdma/ib_verbs.h>
@ -39,6 +41,9 @@ static struct smc_lgr_list smc_lgr_list = { /* established link groups */
.num = 0,
};
static atomic_t lgr_cnt; /* number of existing link groups */
static DECLARE_WAIT_QUEUE_HEAD(lgrs_deleted);
static void smc_buf_free(struct smc_link_group *lgr, bool is_rmb,
struct smc_buf_desc *buf_desc);
@ -319,6 +324,8 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
rc = smc_wr_create_link(lnk);
if (rc)
goto destroy_qp;
atomic_inc(&lgr_cnt);
atomic_inc(&ini->ib_dev->lnk_cnt);
}
smc->conn.lgr = lgr;
spin_lock_bh(lgr_lock);
@ -406,6 +413,8 @@ static void smc_link_clear(struct smc_link *lnk)
smc_ib_destroy_queue_pair(lnk);
smc_ib_dealloc_protection_domain(lnk);
smc_wr_free_link_mem(lnk);
if (!atomic_dec_return(&lnk->smcibdev->lnk_cnt))
wake_up(&lnk->smcibdev->lnks_deleted);
}
static void smcr_buf_free(struct smc_link_group *lgr, bool is_rmb,
@ -492,6 +501,8 @@ static void smc_lgr_free(struct smc_link_group *lgr)
} else {
smc_link_clear(&lgr->lnk[SMC_SINGLE_LINK]);
put_device(&lgr->lnk[SMC_SINGLE_LINK].smcibdev->ibdev->dev);
if (!atomic_dec_return(&lgr_cnt))
wake_up(&lgrs_deleted);
}
kfree(lgr);
}
@ -729,6 +740,15 @@ void smc_smcr_terminate_all(struct smc_ib_device *smcibdev)
list_del_init(&lgr->list);
__smc_lgr_terminate(lgr, false);
}
if (smcibdev) {
if (atomic_read(&smcibdev->lnk_cnt))
wait_event(smcibdev->lnks_deleted,
!atomic_read(&smcibdev->lnk_cnt));
} else {
if (atomic_read(&lgr_cnt))
wait_event(lgrs_deleted, !atomic_read(&lgr_cnt));
}
}
/* Determine vlan of internal TCP socket.
@ -1263,8 +1283,27 @@ static void smc_lgrs_shutdown(void)
spin_unlock(&smcd_dev_list.lock);
}
static int smc_core_reboot_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
smc_lgrs_shutdown();
return 0;
}
static struct notifier_block smc_reboot_notifier = {
.notifier_call = smc_core_reboot_event,
};
int __init smc_core_init(void)
{
atomic_set(&lgr_cnt, 0);
return register_reboot_notifier(&smc_reboot_notifier);
}
/* Called (from smc_exit) when module is removed */
void smc_core_exit(void)
{
unregister_reboot_notifier(&smc_reboot_notifier);
smc_lgrs_shutdown();
}

View file

@ -318,6 +318,7 @@ void smc_conn_free(struct smc_connection *conn);
int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini);
void smcd_conn_free(struct smc_connection *conn);
void smc_lgr_schedule_free_work_fast(struct smc_link_group *lgr);
int smc_core_init(void);
void smc_core_exit(void);
static inline struct smc_link_group *smc_get_lgr(struct smc_link *link)

View file

@ -15,6 +15,7 @@
#include <linux/random.h>
#include <linux/workqueue.h>
#include <linux/scatterlist.h>
#include <linux/wait.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_cache.h>
@ -543,7 +544,8 @@ static void smc_ib_add_dev(struct ib_device *ibdev)
smcibdev->ibdev = ibdev;
INIT_WORK(&smcibdev->port_event_work, smc_ib_port_event_work);
atomic_set(&smcibdev->lnk_cnt, 0);
init_waitqueue_head(&smcibdev->lnks_deleted);
spin_lock(&smc_ib_devices.lock);
list_add_tail(&smcibdev->list, &smc_ib_devices.list);
spin_unlock(&smc_ib_devices.lock);

View file

@ -14,6 +14,7 @@
#include <linux/interrupt.h>
#include <linux/if_ether.h>
#include <linux/wait.h>
#include <rdma/ib_verbs.h>
#include <net/smc.h>
@ -48,6 +49,8 @@ struct smc_ib_device { /* ib-device infos for smc */
struct work_struct port_event_work;
unsigned long port_event_mask;
DECLARE_BITMAP(ports_going_away, SMC_MAX_PORTS);
atomic_t lnk_cnt; /* number of links on ibdev */
wait_queue_head_t lnks_deleted; /* wait 4 removal of all links*/
};
struct smc_buf_desc;