Skip to content

Commit

Permalink
RDS: have sockets get transport module references
Browse files Browse the repository at this point in the history
Right now there's nothing to stop the various paths that use
rs->rs_transport from racing with rmmod and executing freed transport
code.  The simple fix is to have binding to a transport also hold a
reference to the transport's module, removing this class of races.

We already had an unused t_owner field which was set for the modular
transports and which wasn't set for the built-in loop transport.

Signed-off-by: Zach Brown <[email protected]>
  • Loading branch information
Zach Brown authored and Andy Grover committed Sep 9, 2010
1 parent 7751048 commit 5adb5bc
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 6 deletions.
2 changes: 2 additions & 0 deletions net/rds/af_rds.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ static int rds_release(struct socket *sock)
rds_sock_count--;
spin_unlock_irqrestore(&rds_sock_lock, flags);

rds_trans_put(rs->rs_transport);

sock->sk = NULL;
sock_put(sk);
out:
Expand Down
5 changes: 4 additions & 1 deletion net/rds/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
{
struct rds_connection *conn, *parent = NULL;
struct hlist_head *head = rds_conn_bucket(laddr, faddr);
struct rds_transport *loop_trans;
unsigned long flags;
int ret;

Expand Down Expand Up @@ -163,7 +164,9 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
* can bind to the destination address then we'd rather the messages
* flow through loopback rather than either transport.
*/
if (rds_trans_get_preferred(faddr)) {
loop_trans = rds_trans_get_preferred(faddr);
if (loop_trans) {
rds_trans_put(loop_trans);
conn->c_loopback = 1;
if (is_outgoing && trans->t_prefer_loopback) {
/* "outgoing" connection - and the transport
Expand Down
1 change: 1 addition & 0 deletions net/rds/rds.h
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@ void rds_connect_complete(struct rds_connection *conn);
int rds_trans_register(struct rds_transport *trans);
void rds_trans_unregister(struct rds_transport *trans);
struct rds_transport *rds_trans_get_preferred(__be32 addr);
void rds_trans_put(struct rds_transport *trans);
unsigned int rds_trans_stats_info_copy(struct rds_info_iterator *iter,
unsigned int avail);
int rds_trans_init(void);
Expand Down
19 changes: 14 additions & 5 deletions net/rds/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,28 @@ void rds_trans_unregister(struct rds_transport *trans)
}
EXPORT_SYMBOL_GPL(rds_trans_unregister);

void rds_trans_put(struct rds_transport *trans)
{
if (trans && trans->t_owner)
module_put(trans->t_owner);
}

struct rds_transport *rds_trans_get_preferred(__be32 addr)
{
struct rds_transport *ret = NULL;
int i;
struct rds_transport *trans;
unsigned int i;

if (IN_LOOPBACK(ntohl(addr)))
return &rds_loop_transport;

down_read(&rds_trans_sem);
for (i = 0; i < RDS_TRANS_COUNT; i++)
{
if (transports[i] && (transports[i]->laddr_check(addr) == 0)) {
ret = transports[i];
for (i = 0; i < RDS_TRANS_COUNT; i++) {
trans = transports[i];

if (trans && (trans->laddr_check(addr) == 0) &&
(!trans->t_owner || try_module_get(trans->t_owner))) {
ret = trans;
break;
}
}
Expand Down

0 comments on commit 5adb5bc

Please sign in to comment.