Skip to content

Commit

Permalink
rds: tcp: Take explicit refcounts on struct net
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Sowmini Varadhan <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
sowminiv authored and davem330 committed Mar 7, 2017
1 parent fa4c7fb commit 8edc3af
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 5 deletions.
1 change: 1 addition & 0 deletions net/rds/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions net/rds/rds.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions net/rds/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 8edc3af

Please sign in to comment.