]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
RDS: Fix the rds_conn_destroy panic due to pending messages
authorBang Nguyen <bang.nguyen@oracle.com>
Sat, 16 Apr 2016 18:47:05 +0000 (11:47 -0700)
committerChuck Anderson <chuck.anderson@oracle.com>
Tue, 12 Jul 2016 19:49:46 +0000 (12:49 -0700)
In corner cases, there could be pending messages on connection which
needs to be detsroyed. Make sure those messages are purged before
the connection is torned down.

Orabug: 23222944

Signed-off-by: Bang Nguyen <bang.nguyen@oracle.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@oracle.com>
net/rds/connection.c
net/rds/ib_cm.c
net/rds/ib_rdma.c
net/rds/loop.c
net/rds/rds.h
net/rds/send.c
net/rds/tcp.c

index c4b885c87b63a0cda5b6dd590dfb2cb8db2ecd35..f2b02bacba0af789d79a844f163f4749fb0d76b3 100644 (file)
@@ -402,15 +402,18 @@ void rds_conn_shutdown(struct rds_connection *conn, int restart)
  * the conn has been shutdown that no one else is referencing the connection.
  * We can only ensure this in the rmmod path in the current code.
  */
-void rds_conn_destroy(struct rds_connection *conn)
+void rds_conn_destroy(struct rds_connection *conn, int shutdown)
 {
        struct rds_message *rm, *rtmp;
        unsigned long flags;
+       LIST_HEAD(to_be_dropped);
 
        rds_rtd(RDS_RTD_CM, "freeing conn %p <%u.%u.%u.%u,%u.%u.%u.%u,%d>\n",
                conn, NIPQUAD(conn->c_laddr), NIPQUAD(conn->c_faddr),
                conn->c_tos);
 
+       set_bit(RDS_DESTROY_PENDING, &conn->c_flags);
+
        /* Ensure conn will not be scheduled for reconnect */
        spin_lock_irq(&rds_conn_lock);
        hlist_del_init_rcu(&conn->c_hash_node);
@@ -437,10 +440,18 @@ void rds_conn_destroy(struct rds_connection *conn)
        list_for_each_entry_safe(rm, rtmp,
                                 &conn->c_send_queue,
                                 m_conn_item) {
-               list_del_init(&rm->m_conn_item);
-               BUG_ON(!list_empty(&rm->m_sock_item));
-               rds_message_put(rm);
+               if (shutdown) {
+                       list_del_init(&rm->m_conn_item);
+                       BUG_ON(!list_empty(&rm->m_sock_item));
+                       rds_message_put(rm);
+               } else {
+                       list_move_tail(&rm->m_conn_item, &to_be_dropped);
+               }
        }
+
+       if (!list_empty(&to_be_dropped))
+               rds_send_remove_from_sock(&to_be_dropped, RDS_RDMA_SEND_DROPPED);
+
        if (conn->c_xmit_rm)
                rds_message_put(conn->c_xmit_rm);
 
index 4b3c9deb726618f4bdceeb6991525206ca12bdff..a1e25d70825cd496fee1f5e95065503bed93a4d3 100644 (file)
@@ -1054,7 +1054,7 @@ void rds_ib_conn_destroy_worker(struct work_struct *_work)
                container_of(_work, struct rds_ib_conn_destroy_work, work.work);
        struct rds_connection   *conn = work->conn;
 
-       rds_conn_destroy(conn);
+       rds_conn_destroy(conn, 0);
 
        kfree(work);
 }
index 090877d97208c54200df8898c4fb855568a13ba1..dac3a35620c02cf5d5505446f01c41ece7ee9679 100644 (file)
@@ -225,7 +225,7 @@ void rds_ib_destroy_nodev_conns(void)
        spin_unlock_irq(&ib_nodev_conns_lock);
 
        list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node)
-               rds_conn_destroy(ic->conn);
+               rds_conn_destroy(ic->conn, 1);
 }
 
 static unsigned int get_unmap_fmr_cpu(struct rds_ib_device *rds_ibdev,
index e0eac736d8b36d1024f4ba4ce30da50c8d0d4948..be0ff94071f91048192db43ecbd279fc43273ea1 100644 (file)
@@ -185,7 +185,7 @@ void rds_loop_exit(void)
 
        list_for_each_entry_safe(lc, _lc, &tmp_list, loop_node) {
                WARN_ON(lc->conn->c_passive);
-               rds_conn_destroy(lc->conn);
+               rds_conn_destroy(lc->conn, 1);
        }
 }
 
index 6737208fddf569aebeb015e4fac511c19ef80f6b..9d13cf9f89b9b163bb97e94375e101d7ea7fb647 100644 (file)
@@ -134,6 +134,7 @@ enum {
 #define RDS_RECONNECT_PENDING  1
 #define RDS_IN_XMIT            2
 #define RDS_RECV_REFILL                3
+#define RDS_DESTROY_PENDING    4
 
 #define RDS_RDMA_RESOLVE_TO_MAX_INDEX   5
 #define RDS_ADDR_RES_TM_INDEX_MAX 5
@@ -848,7 +849,7 @@ struct rds_connection *rds_conn_find(struct net *net, __be32 laddr,
                                     __be32 faddr,
                                        struct rds_transport *trans, u8 tos);
 void rds_conn_shutdown(struct rds_connection *conn, int restart);
-void rds_conn_destroy(struct rds_connection *conn);
+void rds_conn_destroy(struct rds_connection *conn, int shutdown);
 void rds_conn_reset(struct rds_connection *conn);
 void rds_conn_drop(struct rds_connection *conn);
 void rds_conn_laddr_list(__be32 laddr, struct list_head *laddr_conns);
index edc3083e7a0ee627f520e96e3832736983f9241c..245a3d7ea17e38eb7e16ea6b78ce359935bad827 100644 (file)
@@ -1320,6 +1320,11 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
                goto out;
        }
 
+       if (test_bit(RDS_DESTROY_PENDING, &conn->c_flags)) {
+               ret = -EAGAIN;
+               goto out;
+       }
+
        /* Not accepting new sends until all the failed ops have been reaped */
        if (rds_async_send_enabled && conn->c_pending_flush) {
                ret = -EAGAIN;
index 65eb17fcba69a92611d4ff301ea72ea451b58a4f..fe0aaa71a48234cfff51dc5e23db5a6b7b4abf0b 100644 (file)
@@ -251,8 +251,8 @@ static void rds_tcp_destroy_conns(void)
 
        list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) {
                if (tc->conn->c_passive)
-                       rds_conn_destroy(tc->conn->c_passive);
-               rds_conn_destroy(tc->conn);
+                       rds_conn_destroy(tc->conn->c_passive, 1);
+               rds_conn_destroy(tc->conn, 1);
        }
 }
 
@@ -434,8 +434,8 @@ static void rds_tcp_kill_sock(struct net *net)
                sk->sk_prot->disconnect(sk, 0);
                tcp_done(sk);
                if (tc->conn->c_passive)
-                       rds_conn_destroy(tc->conn->c_passive);
-               rds_conn_destroy(tc->conn);
+                       rds_conn_destroy(tc->conn->c_passive, 1);
+               rds_conn_destroy(tc->conn, 1);
        }
 }