From: Bang Nguyen Date: Sat, 16 Apr 2016 18:47:05 +0000 (-0700) Subject: RDS: Fix the rds_conn_destroy panic due to pending messages X-Git-Tag: v4.1.12-92~108^2~6 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=b0de7f2c41386679896ecd411c4adf82baecbc8d;p=users%2Fjedix%2Flinux-maple.git RDS: Fix the rds_conn_destroy panic due to pending messages 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 Signed-off-by: Santosh Shilimkar --- diff --git a/net/rds/connection.c b/net/rds/connection.c index c4b885c87b63..f2b02bacba0a 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -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); diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 4b3c9deb7266..a1e25d70825c 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -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); } diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index 090877d97208..dac3a35620c0 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -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, diff --git a/net/rds/loop.c b/net/rds/loop.c index e0eac736d8b3..be0ff94071f9 100644 --- a/net/rds/loop.c +++ b/net/rds/loop.c @@ -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); } } diff --git a/net/rds/rds.h b/net/rds/rds.h index 6737208fddf5..9d13cf9f89b9 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -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); diff --git a/net/rds/send.c b/net/rds/send.c index edc3083e7a0e..245a3d7ea17e 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -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; diff --git a/net/rds/tcp.c b/net/rds/tcp.c index 65eb17fcba69..fe0aaa71a482 100644 --- a/net/rds/tcp.c +++ b/net/rds/tcp.c @@ -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); } }