]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
RDS: have sockets get transport module references
authorZach Brown <zach.brown@oracle.com>
Fri, 23 Jul 2010 17:32:31 +0000 (10:32 -0700)
committerMukesh Kacker <mukesh.kacker@oracle.com>
Tue, 7 Jul 2015 23:41:26 +0000 (16:41 -0700)
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 <zach.brown@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Signed-off-by: Bang Nguyen <bang.nguyen@oracle.com>
net/rds/af_rds.c
net/rds/rds.h
net/rds/transport.c

index 5fcd495ff4377e3c12bf85f4c2f3e3cd20ae203c..1b249e75b5d9511e31720e6852a2b3e3ae78b375 100644 (file)
@@ -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:
index 3cac06afc4ab40a91048aac5a38493636ee655f3..240d856c8e022e8e26d69fc3e335b8c40dc093fd 100644 (file)
@@ -797,6 +797,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);
index 7e106790135353c036d6fa0dcba3345cf072f3dd..7f2ac4fec3678b28715b95094c6346bcc49333e1 100644 (file)
@@ -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;
                }
        }