-
Bug
-
Resolution: Unresolved
-
Medium
-
None
-
None
-
None
-
3
-
9223372036854775807
A client crash is seen in __wake_up_common(), called from the NET_RX_SOFTIRQ (napi_gro_receive -> tcp_v4_rcv -> tcp_child_process), right after LNet has been unloaded and reloaded. The waitqueue being woken is lnet_acceptor_waitq, reached from a listening socket whose sk_data_ready still points at lnet_acceptor_ready() in the module that is going away.
Several problems allow this:
- sk_data_ready is installed and restored without holding sk->sk_callback_lock, so a softirq can be using the old value while it is being replaced, and nothing waits for it to complete before sock_release() and the module unload. Install and restore the callback under write_lock_bh(&sk->sk_callback_lock), let lnet_acceptor_ready() take the lock for read and NOOP if it lost the race, and call synchronize_net() before releasing the socket.
- The previous callback is saved in a single global, lnet_acceptor_state.pta_odata, overwritten by every add and never reset, hence stale across an unload/reload and NULL before the first listener is added. Store it per listening socket instead.
- LNetNIFini() calls lnet_acceptor_stop() before lnet_shutdown_lndnets(). The acceptor thread exit path drains socket_list and releases the listeners itself, so when ksocknal_shutdown() later calls lnet_acceptor_remove_sockets() the listener is already gone and "Interface %s not found" is reported. The same inversion exists in the LNetNIInit() error path. Call lnet_acceptor_stop() after lnet_shutdown_lndnets(), as lnet_dyn_del_ni() and lnet_dyn_del_net() already do.
The four open coded refcount drops are folded into lnet_acceptor_put_socket(), socket_lock is taken with the _bh variants now that it is shared with a softirq callback, and the listening socket leaked when lnet_sock_listen() fails is freed.
- is related to
-
LU-19651 conf-sanity test_5h: LNetError: lnet_acceptor_remove_socket() Interface eth0 not found
-
- Open
-