Commit bdf5bd7f authored by Sowmini Varadhan's avatar Sowmini Varadhan Committed by David S. Miller

rds: tcp: remove register_netdevice_notifier infrastructure.

The netns deletion path does not need to wait for all net_devices
to be unregistered before dismantling rds_tcp state for the netns
(we are able to dismantle this state on module unload even when
all net_devices are active so there is no dependency here).

This patch removes code related to netdevice notifiers and
refactors all the code needed to dismantle rds_tcp state
into a ->exit callback for the pernet_operations used with
register_pernet_device().
Signed-off-by: default avatarSowmini Varadhan <sowmini.varadhan@oracle.com>
Reviewed-by: default avatarKirill Tkhai <ktkhai@virtuozzo.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 692ec06d
...@@ -485,40 +485,6 @@ static __net_init int rds_tcp_init_net(struct net *net) ...@@ -485,40 +485,6 @@ static __net_init int rds_tcp_init_net(struct net *net)
return err; return err;
} }
static void __net_exit rds_tcp_exit_net(struct net *net)
{
struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid);
if (rtn->rds_tcp_sysctl)
unregister_net_sysctl_table(rtn->rds_tcp_sysctl);
if (net != &init_net && rtn->ctl_table)
kfree(rtn->ctl_table);
/* If rds_tcp_exit_net() is called as a result of netns deletion,
* the rds_tcp_kill_sock() device notifier would already have cleaned
* up the listen socket, thus there is no work to do in this function.
*
* If rds_tcp_exit_net() is called as a result of module unload,
* i.e., due to rds_tcp_exit() -> unregister_pernet_subsys(), then
* we do need to clean up the listen socket here.
*/
if (rtn->rds_tcp_listen_sock) {
struct socket *lsock = rtn->rds_tcp_listen_sock;
rtn->rds_tcp_listen_sock = NULL;
rds_tcp_listen_stop(lsock, &rtn->rds_tcp_accept_w);
}
}
static struct pernet_operations rds_tcp_net_ops = {
.init = rds_tcp_init_net,
.exit = rds_tcp_exit_net,
.id = &rds_tcp_netid,
.size = sizeof(struct rds_tcp_net),
.async = true,
};
static void rds_tcp_kill_sock(struct net *net) static void rds_tcp_kill_sock(struct net *net)
{ {
struct rds_tcp_connection *tc, *_tc; struct rds_tcp_connection *tc, *_tc;
...@@ -546,40 +512,38 @@ static void rds_tcp_kill_sock(struct net *net) ...@@ -546,40 +512,38 @@ static void rds_tcp_kill_sock(struct net *net)
rds_conn_destroy(tc->t_cpath->cp_conn); rds_conn_destroy(tc->t_cpath->cp_conn);
} }
void *rds_tcp_listen_sock_def_readable(struct net *net) static void __net_exit rds_tcp_exit_net(struct net *net)
{ {
struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid); struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid);
struct socket *lsock = rtn->rds_tcp_listen_sock;
if (!lsock) rds_tcp_kill_sock(net);
return NULL;
return lsock->sk->sk_user_data; if (rtn->rds_tcp_sysctl)
unregister_net_sysctl_table(rtn->rds_tcp_sysctl);
if (net != &init_net && rtn->ctl_table)
kfree(rtn->ctl_table);
} }
static int rds_tcp_dev_event(struct notifier_block *this, static struct pernet_operations rds_tcp_net_ops = {
unsigned long event, void *ptr) .init = rds_tcp_init_net,
.exit = rds_tcp_exit_net,
.id = &rds_tcp_netid,
.size = sizeof(struct rds_tcp_net),
.async = true,
};
void *rds_tcp_listen_sock_def_readable(struct net *net)
{ {
struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid);
struct socket *lsock = rtn->rds_tcp_listen_sock;
/* rds-tcp registers as a pernet subys, so the ->exit will only if (!lsock)
* get invoked after network acitivity has quiesced. We need to return NULL;
* clean up all sockets to quiesce network activity, and use
* the unregistration of the per-net loopback device as a trigger
* to start that cleanup.
*/
if (event == NETDEV_UNREGISTER_FINAL &&
dev->ifindex == LOOPBACK_IFINDEX)
rds_tcp_kill_sock(dev_net(dev));
return NOTIFY_DONE; return lsock->sk->sk_user_data;
} }
static struct notifier_block rds_tcp_dev_notifier = {
.notifier_call = rds_tcp_dev_event,
.priority = -10, /* must be called after other network notifiers */
};
/* when sysctl is used to modify some kernel socket parameters,this /* when sysctl is used to modify some kernel socket parameters,this
* function resets the RDS connections in that netns so that we can * function resets the RDS connections in that netns so that we can
* restart with new parameters. The assumption is that such reset * restart with new parameters. The assumption is that such reset
...@@ -625,9 +589,7 @@ static void rds_tcp_exit(void) ...@@ -625,9 +589,7 @@ static void rds_tcp_exit(void)
rds_tcp_set_unloading(); rds_tcp_set_unloading();
synchronize_rcu(); synchronize_rcu();
rds_info_deregister_func(RDS_INFO_TCP_SOCKETS, rds_tcp_tc_info); rds_info_deregister_func(RDS_INFO_TCP_SOCKETS, rds_tcp_tc_info);
unregister_pernet_subsys(&rds_tcp_net_ops); unregister_pernet_device(&rds_tcp_net_ops);
if (unregister_netdevice_notifier(&rds_tcp_dev_notifier))
pr_warn("could not unregister rds_tcp_dev_notifier\n");
rds_tcp_destroy_conns(); rds_tcp_destroy_conns();
rds_trans_unregister(&rds_tcp_transport); rds_trans_unregister(&rds_tcp_transport);
rds_tcp_recv_exit(); rds_tcp_recv_exit();
...@@ -651,24 +613,15 @@ static int rds_tcp_init(void) ...@@ -651,24 +613,15 @@ static int rds_tcp_init(void)
if (ret) if (ret)
goto out_slab; goto out_slab;
ret = register_pernet_subsys(&rds_tcp_net_ops); ret = register_pernet_device(&rds_tcp_net_ops);
if (ret) if (ret)
goto out_recv; goto out_recv;
ret = register_netdevice_notifier(&rds_tcp_dev_notifier);
if (ret) {
pr_warn("could not register rds_tcp_dev_notifier\n");
goto out_pernet;
}
rds_trans_register(&rds_tcp_transport); rds_trans_register(&rds_tcp_transport);
rds_info_register_func(RDS_INFO_TCP_SOCKETS, rds_tcp_tc_info); rds_info_register_func(RDS_INFO_TCP_SOCKETS, rds_tcp_tc_info);
goto out; goto out;
out_pernet:
unregister_pernet_subsys(&rds_tcp_net_ops);
out_recv: out_recv:
rds_tcp_recv_exit(); rds_tcp_recv_exit();
out_slab: out_slab:
......
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