From: Sowmini Varadhan Date: Tue, 18 Jul 2017 14:36:12 +0000 (+0300) Subject: rds: tcp: cancel all worker threads before shutting down socket X-Git-Tag: v4.1.12-124.31.3~690 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=ababc94bcce0410868da03719b4e9ef79c5da603;p=users%2Fjedix%2Flinux-maple.git rds: tcp: cancel all worker threads before shutting down socket We could end up executing rds_conn_shutdown before the rds_recv_worker thread, then rds_conn_shutdown -> rds_tcp_conn_shutdown can do a sock_release and set sock->sk to null, which may interleave in bad ways with rds_recv_worker, e.g., it could result in: "BUG: unable to handle kernel NULL pointer dereference at 0000000000000078" [ffff881769f6fd70] release_sock at ffffffff815f337b [ffff881769f6fd90] rds_tcp_recv at ffffffffa043c888 [rds_tcp] [ffff881769f6fdb0] rds_recv_worker at ffffffffa04a4810 [rds] [ffff881769f6fde0] process_one_work at ffffffff810a14c1 [ffff881769f6fe40] worker_thread at ffffffff810a1940 [ffff881769f6fec0] kthread at ffffffff810a6b1e cancel send/recv worker threads before shutting down connection. Also, do not enqueue any new shutdown workq items when the connection is shutting down (this may happen for rds-tcp in softirq mode, if a FIN or CLOSE is received while the modules is in the middle of an unload) Signed-off-by: Sowmini Varadhan Signed-off-by: Yuval Shaia Reviewed-by: Wei Lin Guay Signed-off-by: Dhaval Giani (cherry picked from commit UEK4 bf1f0c8c007c58eae14622c6f9a3fe36f6b19d5a) Orabug: 28298156 Signed-off-by: Yuval Shaia Reviewed-by: Yuval Shaia Reviewed-by: Darren Kenny Signed-off-by: Brian Maly --- diff --git a/net/rds/connection.c b/net/rds/connection.c index 89f2539c9be43..5dc20884a9e33 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -469,6 +469,10 @@ static void rds_conn_path_destroy(struct rds_conn_path *cp, int shutdown) if (!cp->cp_transport_data) return; + /* make sure lingering queued work won't try to ref the conn */ + cancel_delayed_work_sync(&cp->cp_send_w); + cancel_delayed_work_sync(&cp->cp_recv_w); + rds_conn_path_drop(cp, DR_CONN_DESTROY); flush_work(&cp->cp_down_w); @@ -479,10 +483,6 @@ static void rds_conn_path_destroy(struct rds_conn_path *cp, int shutdown) */ cancel_delayed_work_sync(&cp->cp_reconn_w); - /* make sure lingering queued work won't try to ref the conn */ - cancel_delayed_work_sync(&cp->cp_send_w); - cancel_delayed_work_sync(&cp->cp_recv_w); - /* tear down queued messages */ list_for_each_entry_safe(rm, rtmp, &cp->cp_send_queue, @@ -991,6 +991,10 @@ void rds_conn_path_drop(struct rds_conn_path *cp, int reason) conn, &conn->c_laddr, &conn->c_faddr, conn->c_tos); + if (reason != DR_CONN_DESTROY && test_bit(RDS_DESTROY_PENDING, + &cp->cp_flags)) + return; + queue_work(cp->cp_wq, &cp->cp_down_w); } EXPORT_SYMBOL_GPL(rds_conn_path_drop);