]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
rds: tcp: cancel all worker threads before shutting down socket
authorSowmini Varadhan <sowmini.varadhan@oracle.com>
Tue, 18 Jul 2017 14:36:12 +0000 (17:36 +0300)
committerBrian Maly <brian.maly@oracle.com>
Tue, 17 Jul 2018 23:52:59 +0000 (19:52 -0400)
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 <sowmini.varadhan@oracle.com>
Signed-off-by: Yuval Shaia <yuval.shaia@oracle.com>
Reviewed-by: Wei Lin Guay <wei.lin.guay@oracle.com>
Signed-off-by: Dhaval Giani <dhaval.giani@oracle.com>
(cherry picked from commit UEK4 bf1f0c8c007c58eae14622c6f9a3fe36f6b19d5a)

Orabug: 28298156

Signed-off-by: Yuval Shaia <yuval.shaia@oracle.com>
Reviewed-by: Yuval Shaia <yuval.shaia@oracle.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Signed-off-by: Brian Maly <brian.maly@oracle.com>
net/rds/connection.c

index 89f2539c9be4334933e4950dce7789af452a4ff4..5dc20884a9e338350207e4b75930c052ac7cf503 100644 (file)
@@ -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);