aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/rds/connection.c48
1 files changed, 31 insertions, 17 deletions
diff --git a/net/rds/connection.c b/net/rds/connection.c
index 605fe3f60de3..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;
@@ -210,26 +210,40 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
210 trans->t_name ? trans->t_name : "[unknown]", 210 trans->t_name ? trans->t_name : "[unknown]",
211 is_outgoing ? "(outgoing)" : ""); 211 is_outgoing ? "(outgoing)" : "");
212 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 */
213 spin_lock_irqsave(&rds_conn_lock, flags); 220 spin_lock_irqsave(&rds_conn_lock, flags);
214 if (parent == NULL) { 221 if (parent) {
215 tmp = rds_conn_lookup(head, laddr, faddr, trans); 222 /* Creating passive conn */
216 if (tmp == NULL) 223 if (parent->c_passive) {
217 hlist_add_head(&conn->c_hash_node, head); 224 trans->conn_free(conn->c_transport_data);
218 } else { 225 kmem_cache_free(rds_conn_slab, conn);
219 tmp = parent->c_passive; 226 conn = parent->c_passive;
220 if (!tmp) 227 } else {
221 parent->c_passive = conn; 228 parent->c_passive = conn;
222 } 229 rds_cong_add_conn(conn);
223 230 rds_conn_count++;
224 if (tmp) { 231 }
225 trans->conn_free(conn->c_transport_data);
226 kmem_cache_free(rds_conn_slab, conn);
227 conn = tmp;
228 } else { 232 } else {
229 rds_cong_add_conn(conn); 233 /* Creating normal conn */
230 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 }
231 } 246 }
232
233 spin_unlock_irqrestore(&rds_conn_lock, flags); 247 spin_unlock_irqrestore(&rds_conn_lock, flags);
234 248
235out: 249out: