aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZach Brown <zach.brown@oracle.com>2010-07-23 13:32:31 -0400
committerAndy Grover <andy.grover@oracle.com>2010-09-08 21:16:47 -0400
commit5adb5bc65f93e52341c3fc9d03d4030dd375e256 (patch)
tree55b19c7757ccd64f58169a05cd63e91bee409bad
parent77510481c0c3980c8979ed236d63e59221fb8ce5 (diff)
RDS: have sockets get transport module references
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>
-rw-r--r--net/rds/af_rds.c2
-rw-r--r--net/rds/connection.c5
-rw-r--r--net/rds/rds.h1
-rw-r--r--net/rds/transport.c19
4 files changed, 21 insertions, 6 deletions
diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c
index 57ef0ec4f03d..8e3886d353b5 100644
--- a/net/rds/af_rds.c
+++ b/net/rds/af_rds.c
@@ -90,6 +90,8 @@ static int rds_release(struct socket *sock)
90 rds_sock_count--; 90 rds_sock_count--;
91 spin_unlock_irqrestore(&rds_sock_lock, flags); 91 spin_unlock_irqrestore(&rds_sock_lock, flags);
92 92
93 rds_trans_put(rs->rs_transport);
94
93 sock->sk = NULL; 95 sock->sk = NULL;
94 sock_put(sk); 96 sock_put(sk);
95out: 97out:
diff --git a/net/rds/connection.c b/net/rds/connection.c
index 75a1a37d64d3..968b7a798398 100644
--- a/net/rds/connection.c
+++ b/net/rds/connection.c
@@ -117,6 +117,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
117{ 117{
118 struct rds_connection *conn, *parent = NULL; 118 struct rds_connection *conn, *parent = NULL;
119 struct hlist_head *head = rds_conn_bucket(laddr, faddr); 119 struct hlist_head *head = rds_conn_bucket(laddr, faddr);
120 struct rds_transport *loop_trans;
120 unsigned long flags; 121 unsigned long flags;
121 int ret; 122 int ret;
122 123
@@ -163,7 +164,9 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
163 * can bind to the destination address then we'd rather the messages 164 * can bind to the destination address then we'd rather the messages
164 * flow through loopback rather than either transport. 165 * flow through loopback rather than either transport.
165 */ 166 */
166 if (rds_trans_get_preferred(faddr)) { 167 loop_trans = rds_trans_get_preferred(faddr);
168 if (loop_trans) {
169 rds_trans_put(loop_trans);
167 conn->c_loopback = 1; 170 conn->c_loopback = 1;
168 if (is_outgoing && trans->t_prefer_loopback) { 171 if (is_outgoing && trans->t_prefer_loopback) {
169 /* "outgoing" connection - and the transport 172 /* "outgoing" connection - and the transport
diff --git a/net/rds/rds.h b/net/rds/rds.h
index 2ff7fc9f0539..aab5e949fa93 100644
--- a/net/rds/rds.h
+++ b/net/rds/rds.h
@@ -798,6 +798,7 @@ void rds_connect_complete(struct rds_connection *conn);
798int rds_trans_register(struct rds_transport *trans); 798int rds_trans_register(struct rds_transport *trans);
799void rds_trans_unregister(struct rds_transport *trans); 799void rds_trans_unregister(struct rds_transport *trans);
800struct rds_transport *rds_trans_get_preferred(__be32 addr); 800struct rds_transport *rds_trans_get_preferred(__be32 addr);
801void rds_trans_put(struct rds_transport *trans);
801unsigned int rds_trans_stats_info_copy(struct rds_info_iterator *iter, 802unsigned int rds_trans_stats_info_copy(struct rds_info_iterator *iter,
802 unsigned int avail); 803 unsigned int avail);
803int rds_trans_init(void); 804int rds_trans_init(void);
diff --git a/net/rds/transport.c b/net/rds/transport.c
index 7e1067901353..7f2ac4fec367 100644
--- a/net/rds/transport.c
+++ b/net/rds/transport.c
@@ -71,19 +71,28 @@ void rds_trans_unregister(struct rds_transport *trans)
71} 71}
72EXPORT_SYMBOL_GPL(rds_trans_unregister); 72EXPORT_SYMBOL_GPL(rds_trans_unregister);
73 73
74void rds_trans_put(struct rds_transport *trans)
75{
76 if (trans && trans->t_owner)
77 module_put(trans->t_owner);
78}
79
74struct rds_transport *rds_trans_get_preferred(__be32 addr) 80struct rds_transport *rds_trans_get_preferred(__be32 addr)
75{ 81{
76 struct rds_transport *ret = NULL; 82 struct rds_transport *ret = NULL;
77 int i; 83 struct rds_transport *trans;
84 unsigned int i;
78 85
79 if (IN_LOOPBACK(ntohl(addr))) 86 if (IN_LOOPBACK(ntohl(addr)))
80 return &rds_loop_transport; 87 return &rds_loop_transport;
81 88
82 down_read(&rds_trans_sem); 89 down_read(&rds_trans_sem);
83 for (i = 0; i < RDS_TRANS_COUNT; i++) 90 for (i = 0; i < RDS_TRANS_COUNT; i++) {
84 { 91 trans = transports[i];
85 if (transports[i] && (transports[i]->laddr_check(addr) == 0)) { 92
86 ret = transports[i]; 93 if (trans && (trans->laddr_check(addr) == 0) &&
94 (!trans->t_owner || try_module_get(trans->t_owner))) {
95 ret = trans;
87 break; 96 break;
88 } 97 }
89 } 98 }