aboutsummaryrefslogtreecommitdiffstats
path: root/net/rds/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/rds/connection.c')
-rw-r--r--net/rds/connection.c49
1 files changed, 31 insertions, 18 deletions
diff --git a/net/rds/connection.c b/net/rds/connection.c
index d14445c48304..b420a20d84fd 100644
--- a/net/rds/connection.c
+++ b/net/rds/connection.c
@@ -126,7 +126,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
126 struct rds_transport *trans, gfp_t gfp, 126 struct rds_transport *trans, gfp_t gfp,
127 int is_outgoing) 127 int is_outgoing)
128{ 128{
129 struct rds_connection *conn, *tmp, *parent = NULL; 129 struct rds_connection *conn, *parent = NULL;
130 struct hlist_head *head = rds_conn_bucket(laddr, faddr); 130 struct hlist_head *head = rds_conn_bucket(laddr, faddr);
131 unsigned long flags; 131 unsigned long flags;
132 int ret; 132 int ret;
@@ -155,7 +155,6 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
155 } 155 }
156 156
157 INIT_HLIST_NODE(&conn->c_hash_node); 157 INIT_HLIST_NODE(&conn->c_hash_node);
158 conn->c_version = RDS_PROTOCOL_3_0;
159 conn->c_laddr = laddr; 158 conn->c_laddr = laddr;
160 conn->c_faddr = faddr; 159 conn->c_faddr = faddr;
161 spin_lock_init(&conn->c_lock); 160 spin_lock_init(&conn->c_lock);
@@ -211,26 +210,40 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
211 trans->t_name ? trans->t_name : "[unknown]", 210 trans->t_name ? trans->t_name : "[unknown]",
212 is_outgoing ? "(outgoing)" : ""); 211 is_outgoing ? "(outgoing)" : "");
213 212
213 /*
214 * Since we ran without holding the conn lock, someone could
215 * have created the same conn (either normal or passive) in the
216 * interim. We check while holding the lock. If we won, we complete
217 * init and return our conn. If we lost, we rollback and return the
218 * other one.
219 */
214 spin_lock_irqsave(&rds_conn_lock, flags); 220 spin_lock_irqsave(&rds_conn_lock, flags);
215 if (parent == NULL) { 221 if (parent) {
216 tmp = rds_conn_lookup(head, laddr, faddr, trans); 222 /* Creating passive conn */
217 if (tmp == NULL) 223 if (parent->c_passive) {
218 hlist_add_head(&conn->c_hash_node, head); 224 trans->conn_free(conn->c_transport_data);
219 } else { 225 kmem_cache_free(rds_conn_slab, conn);
220 tmp = parent->c_passive; 226 conn = parent->c_passive;
221 if (!tmp) 227 } else {
222 parent->c_passive = conn; 228 parent->c_passive = conn;
223 } 229 rds_cong_add_conn(conn);
224 230 rds_conn_count++;
225 if (tmp) { 231 }
226 trans->conn_free(conn->c_transport_data);
227 kmem_cache_free(rds_conn_slab, conn);
228 conn = tmp;
229 } else { 232 } else {
230 rds_cong_add_conn(conn); 233 /* Creating normal conn */
231 rds_conn_count++; 234 struct rds_connection *found;
235
236 found = rds_conn_lookup(head, laddr, faddr, trans);
237 if (found) {
238 trans->conn_free(conn->c_transport_data);
239 kmem_cache_free(rds_conn_slab, conn);
240 conn = found;
241 } else {
242 hlist_add_head(&conn->c_hash_node, head);
243 rds_cong_add_conn(conn);
244 rds_conn_count++;
245 }
232 } 246 }
233
234 spin_unlock_irqrestore(&rds_conn_lock, flags); 247 spin_unlock_irqrestore(&rds_conn_lock, flags);
235 248
236out: 249out: