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: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
fa4c7fb2ad
commit
8edc3affc0
@ -429,6 +429,7 @@ void rds_conn_destroy(struct rds_connection *conn)
|
||||
*/
|
||||
rds_cong_remove_conn(conn);
|
||||
|
||||
put_net(conn->c_net);
|
||||
kmem_cache_free(rds_conn_slab, conn);
|
||||
|
||||
spin_lock_irqsave(&rds_conn_lock, flags);
|
||||
|
@ -147,7 +147,7 @@ struct rds_connection {
|
||||
|
||||
/* Protocol version */
|
||||
unsigned int c_version;
|
||||
possible_net_t c_net;
|
||||
struct net *c_net;
|
||||
|
||||
struct list_head c_map_item;
|
||||
unsigned long c_map_queued;
|
||||
@ -162,13 +162,13 @@ struct rds_connection {
|
||||
static inline
|
||||
struct net *rds_conn_net(struct rds_connection *conn)
|
||||
{
|
||||
return read_pnet(&conn->c_net);
|
||||
return conn->c_net;
|
||||
}
|
||||
|
||||
static inline
|
||||
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
|
||||
|
@ -529,7 +529,7 @@ static void rds_tcp_kill_sock(struct net *net)
|
||||
flush_work(&rtn->rds_tcp_accept_w);
|
||||
spin_lock_irq(&rds_tcp_conn_lock);
|
||||
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)
|
||||
continue;
|
||||
@ -584,7 +584,7 @@ static void rds_tcp_sysctl_reset(struct net *net)
|
||||
|
||||
spin_lock_irq(&rds_tcp_conn_lock);
|
||||
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)
|
||||
continue;
|
||||
|
Loading…
Reference in New Issue
Block a user