RDS_CONN_RESET SO gets enhanced to support reseting all
connections associated with a local address.
$rds-stress -r <SRC_IP> -s 0 --reset
Orabug:
23222944
Reported-by: Bang Ngyen <bang.nguyen@oracle.com>
Acked-by: Bang Ngyen <bang.nguyen@oracle.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@oracle.com>
{
struct rds_reset reset;
struct rds_connection *conn;
+ LIST_HEAD(s_addr_conns);
if (optlen != sizeof(struct rds_reset))
return -EINVAL;
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);
conn->c_drop_source = DR_USER_RESET;
rds_conn_drop(conn);
}
-
+done:
return 0;
}
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
unsigned int c_route_resolved;
enum rds_conn_drop_src c_drop_source;
+ struct list_head c_laddr_node;
};
static inline
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,