Commit c492d4c74dd3f87559883ffa0f94a8f1ae3fe5f5

Authored by Xin Long
Committed by David S. Miller
1 parent 8ac8a01092

tipc: change to use register_pernet_device

This patch is to fix a dst defcnt leak, which can be reproduced by doing:

  # ip net a c; ip net a s; modprobe tipc
  # ip net e s ip l a n eth1 type veth peer n eth1 netns c
  # ip net e c ip l s lo up; ip net e c ip l s eth1 up
  # ip net e s ip l s lo up; ip net e s ip l s eth1 up
  # ip net e c ip a a 1.1.1.2/8 dev eth1
  # ip net e s ip a a 1.1.1.1/8 dev eth1
  # ip net e c tipc b e m udp n u1 localip 1.1.1.2
  # ip net e s tipc b e m udp n u1 localip 1.1.1.1
  # ip net d c; ip net d s; rmmod tipc

and it will get stuck and keep logging the error:

  unregister_netdevice: waiting for lo to become free. Usage count = 1

The cause is that a dst is held by the udp sock's sk_rx_dst set on udp rx
path with udp_early_demux == 1, and this dst (eventually holding lo dev)
can't be released as bearer's removal in tipc pernet .exit happens after
lo dev's removal, default_device pernet .exit.

 "There are two distinct types of pernet_operations recognized: subsys and
  device.  At creation all subsys init functions are called before device
  init functions, and at destruction all device exit functions are called
  before subsys exit function."

So by calling register_pernet_device instead to register tipc_net_ops, the
pernet .exit() will be invoked earlier than loopback dev's removal when a
netns is being destroyed, as fou/gue does.

Note that vxlan and geneve udp tunnels don't have this issue, as the udp
sock is released in their device ndo_stop().

This fix is also necessary for tipc dst_cache, which will hold dsts on tx
path and I will introduce in my next patch.

Reported-by: Li Shuang <shuali@redhat.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 6 additions and 6 deletions Side-by-side Diff

... ... @@ -134,7 +134,7 @@
134 134 if (err)
135 135 goto out_sysctl;
136 136  
137   - err = register_pernet_subsys(&tipc_net_ops);
  137 + err = register_pernet_device(&tipc_net_ops);
138 138 if (err)
139 139 goto out_pernet;
140 140  
... ... @@ -142,7 +142,7 @@
142 142 if (err)
143 143 goto out_socket;
144 144  
145   - err = register_pernet_subsys(&tipc_topsrv_net_ops);
  145 + err = register_pernet_device(&tipc_topsrv_net_ops);
146 146 if (err)
147 147 goto out_pernet_topsrv;
148 148  
149 149  
... ... @@ -153,11 +153,11 @@
153 153 pr_info("Started in single node mode\n");
154 154 return 0;
155 155 out_bearer:
156   - unregister_pernet_subsys(&tipc_topsrv_net_ops);
  156 + unregister_pernet_device(&tipc_topsrv_net_ops);
157 157 out_pernet_topsrv:
158 158 tipc_socket_stop();
159 159 out_socket:
160   - unregister_pernet_subsys(&tipc_net_ops);
  160 + unregister_pernet_device(&tipc_net_ops);
161 161 out_pernet:
162 162 tipc_unregister_sysctl();
163 163 out_sysctl:
164 164  
... ... @@ -172,9 +172,9 @@
172 172 static void __exit tipc_exit(void)
173 173 {
174 174 tipc_bearer_cleanup();
175   - unregister_pernet_subsys(&tipc_topsrv_net_ops);
  175 + unregister_pernet_device(&tipc_topsrv_net_ops);
176 176 tipc_socket_stop();
177   - unregister_pernet_subsys(&tipc_net_ops);
  177 + unregister_pernet_device(&tipc_net_ops);
178 178 tipc_netlink_stop();
179 179 tipc_netlink_compat_stop();
180 180 tipc_unregister_sysctl();