From: Santosh Shilimkar Date: Wed, 23 Mar 2016 04:51:49 +0000 (-0700) Subject: RDS: Add reset all conns for a source address to CONN_RESET X-Git-Tag: v4.1.12-92~148^2~7 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=1df6544650af7fc2d941a56f3ed5dcab448d3e4e;p=users%2Fjedix%2Flinux-maple.git RDS: Add reset all conns for a source address to CONN_RESET RDS_CONN_RESET SO gets enhanced to support reseting all connections associated with a local address. $rds-stress -r -s 0 --reset Orabug: 23222944 Reported-by: Bang Ngyen Acked-by: Bang Ngyen Signed-off-by: Santosh Shilimkar --- diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index f3948435c1b91..4b3e728a4c3cc 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -327,6 +327,7 @@ static int rds_user_reset(struct rds_sock *rs, char __user *optval, int optlen) { struct rds_reset reset; struct rds_connection *conn; + LIST_HEAD(s_addr_conns); if (optlen != sizeof(struct rds_reset)) return -EINVAL; @@ -335,6 +336,23 @@ static int rds_user_reset(struct rds_sock *rs, char __user *optval, int optlen) sizeof(struct rds_reset))) return -EFAULT; + /* Reset all conns associated with source addr */ + if (reset.dst.s_addr == 0) { + pr_info("RDS: Reset ALL conns for Source %pI4\n", + &reset.src.s_addr); + + rds_conn_laddr_list(reset.src.s_addr, &s_addr_conns); + if (list_empty(&s_addr_conns)) + goto done; + + list_for_each_entry(conn, &s_addr_conns, c_laddr_node) + if (conn) { + conn->c_drop_source = 1; + rds_conn_drop(conn); + } + goto done; + } + conn = rds_conn_find(sock_net(rds_rs_to_sk(rs)), reset.src.s_addr, reset.dst.s_addr, rs->rs_transport, reset.tos); @@ -347,7 +365,7 @@ static int rds_user_reset(struct rds_sock *rs, char __user *optval, int optlen) conn->c_drop_source = DR_USER_RESET; rds_conn_drop(conn); } - +done: return 0; } diff --git a/net/rds/connection.c b/net/rds/connection.c index 0b7d1e2ee5876..c4b885c87b63a 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -91,6 +91,24 @@ static struct rds_connection *rds_conn_lookup(struct net *net, return ret; } +void rds_conn_laddr_list(__be32 laddr, struct list_head *laddr_conns) +{ + struct rds_connection *conn; + struct hlist_head *head; + int i; + + rcu_read_lock(); + + for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash); + i++, head++) { + hlist_for_each_entry_rcu(conn, head, c_hash_node) + if (conn->c_laddr == laddr) + list_add(&conn->c_laddr_node, laddr_conns); + } + + rcu_read_unlock(); +} + /* * This is called by transports as they're bringing down a connection. * It clears partial message state so that the transport can start sending diff --git a/net/rds/rds.h b/net/rds/rds.h index a3d6284edd2a7..7237bc58fb9d7 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -287,6 +287,7 @@ struct rds_connection { unsigned int c_route_resolved; enum rds_conn_drop_src c_drop_source; + struct list_head c_laddr_node; }; static inline @@ -838,6 +839,7 @@ void rds_conn_shutdown(struct rds_connection *conn, int restart); void rds_conn_destroy(struct rds_connection *conn); 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); void rds_conn_connect_if_down(struct rds_connection *conn); void rds_for_each_conn_info(struct socket *sock, unsigned int len, struct rds_info_iterator *iter,