Commit 8edc3aff authored by Sowmini Varadhan's avatar Sowmini Varadhan Committed by David S. Miller

rds: tcp: Take explicit refcounts on struct net

It is incorrect for the rds_connection to piggyback on the
sock_net() refcount for the netns because this gives rise to
a chicken-and-egg problem during rds_conn_destroy. Instead explicitly
take a ref on the net, and hold the netns down till the connection
tear-down is complete.
Reported-by: default avatarDmitry Vyukov <dvyukov@google.com>
Signed-off-by: default avatarSowmini Varadhan <sowmini.varadhan@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fa4c7fb2
...@@ -429,6 +429,7 @@ void rds_conn_destroy(struct rds_connection *conn) ...@@ -429,6 +429,7 @@ void rds_conn_destroy(struct rds_connection *conn)
*/ */
rds_cong_remove_conn(conn); rds_cong_remove_conn(conn);
put_net(conn->c_net);
kmem_cache_free(rds_conn_slab, conn); kmem_cache_free(rds_conn_slab, conn);
spin_lock_irqsave(&rds_conn_lock, flags); spin_lock_irqsave(&rds_conn_lock, flags);
......
...@@ -147,7 +147,7 @@ struct rds_connection { ...@@ -147,7 +147,7 @@ struct rds_connection {
/* Protocol version */ /* Protocol version */
unsigned int c_version; unsigned int c_version;
possible_net_t c_net; struct net *c_net;
struct list_head c_map_item; struct list_head c_map_item;
unsigned long c_map_queued; unsigned long c_map_queued;
...@@ -162,13 +162,13 @@ struct rds_connection { ...@@ -162,13 +162,13 @@ struct rds_connection {
static inline static inline
struct net *rds_conn_net(struct rds_connection *conn) struct net *rds_conn_net(struct rds_connection *conn)
{ {
return read_pnet(&conn->c_net); return conn->c_net;
} }
static inline static inline
void rds_conn_net_set(struct rds_connection *conn, struct net *net) void rds_conn_net_set(struct rds_connection *conn, struct net *net)
{ {
write_pnet(&conn->c_net, net); conn->c_net = get_net(net);
} }
#define RDS_FLAG_CONG_BITMAP 0x01 #define RDS_FLAG_CONG_BITMAP 0x01
......
...@@ -529,7 +529,7 @@ static void rds_tcp_kill_sock(struct net *net) ...@@ -529,7 +529,7 @@ static void rds_tcp_kill_sock(struct net *net)
flush_work(&rtn->rds_tcp_accept_w); flush_work(&rtn->rds_tcp_accept_w);
spin_lock_irq(&rds_tcp_conn_lock); spin_lock_irq(&rds_tcp_conn_lock);
list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) { list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) {
struct net *c_net = read_pnet(&tc->t_cpath->cp_conn->c_net); struct net *c_net = tc->t_cpath->cp_conn->c_net;
if (net != c_net || !tc->t_sock) if (net != c_net || !tc->t_sock)
continue; continue;
...@@ -584,7 +584,7 @@ static void rds_tcp_sysctl_reset(struct net *net) ...@@ -584,7 +584,7 @@ static void rds_tcp_sysctl_reset(struct net *net)
spin_lock_irq(&rds_tcp_conn_lock); spin_lock_irq(&rds_tcp_conn_lock);
list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) { list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) {
struct net *c_net = read_pnet(&tc->t_cpath->cp_conn->c_net); struct net *c_net = tc->t_cpath->cp_conn->c_net;
if (net != c_net || !tc->t_sock) if (net != c_net || !tc->t_sock)
continue; continue;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment