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

rds: tcp: Reorder initialization sequence in rds_tcp_init to avoid races

Order of initialization in rds_tcp_init needs to be done so
that resources are set up and destroyed in the correct synchronization
sequence with both the data path, as well as netns create/destroy
path. Specifically,

- we must call register_pernet_subsys and get the rds_tcp_netid
  before calling register_netdevice_notifier, otherwise we risk
  the sequence
    1. register_netdevice_notifier sets up netdev notifier callback
    2. rds_tcp_dev_event -> rds_tcp_kill_sock uses netid 0, and finds
       the wrong rtn, resulting in a panic with string that is of the form:

  BUG: unable to handle kernel NULL pointer dereference at 000000000000000d
  IP: rds_tcp_kill_sock+0x3a/0x1d0 [rds_tcp]
         :

- the rds_tcp_incoming_slab kmem_cache must be initialized before the
  datapath starts up. The latter can happen any time after the
  pernet_subsys registration of rds_tcp_net_ops, whose -> init
  function sets up the listen socket. If the rds_tcp_incoming_slab has
  not been set up at that time, a panic of the form below may be
  encountered

  BUG: unable to handle kernel NULL pointer dereference at 0000000000000014
  IP: kmem_cache_alloc+0x90/0x1c0
     :
  rds_tcp_data_recv+0x1e7/0x370 [rds_tcp]
  tcp_read_sock+0x96/0x1c0
  rds_tcp_recv_path+0x65/0x80 [rds_tcp]
     :
Signed-off-by: default avatarSowmini Varadhan <sowmini.varadhan@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8edc3aff
...@@ -638,19 +638,19 @@ static int rds_tcp_init(void) ...@@ -638,19 +638,19 @@ static int rds_tcp_init(void)
goto out; goto out;
} }
ret = register_netdevice_notifier(&rds_tcp_dev_notifier); ret = rds_tcp_recv_init();
if (ret) { if (ret)
pr_warn("could not register rds_tcp_dev_notifier\n");
goto out_slab; goto out_slab;
}
ret = register_pernet_subsys(&rds_tcp_net_ops); ret = register_pernet_subsys(&rds_tcp_net_ops);
if (ret) if (ret)
goto out_notifier; goto out_recv;
ret = rds_tcp_recv_init(); ret = register_netdevice_notifier(&rds_tcp_dev_notifier);
if (ret) if (ret) {
pr_warn("could not register rds_tcp_dev_notifier\n");
goto out_pernet; goto out_pernet;
}
rds_trans_register(&rds_tcp_transport); rds_trans_register(&rds_tcp_transport);
...@@ -660,9 +660,8 @@ static int rds_tcp_init(void) ...@@ -660,9 +660,8 @@ static int rds_tcp_init(void)
out_pernet: out_pernet:
unregister_pernet_subsys(&rds_tcp_net_ops); unregister_pernet_subsys(&rds_tcp_net_ops);
out_notifier: out_recv:
if (unregister_netdevice_notifier(&rds_tcp_dev_notifier)) rds_tcp_recv_exit();
pr_warn("could not unregister rds_tcp_dev_notifier\n");
out_slab: out_slab:
kmem_cache_destroy(rds_tcp_conn_slab); kmem_cache_destroy(rds_tcp_conn_slab);
out: out:
......
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