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