diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/rds/connection.c | 48 |
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 | ||
235 | out: | 249 | out: |