diff options
-rw-r--r-- | net/rds/connection.c | 44 |
1 files changed, 22 insertions, 22 deletions
diff --git a/net/rds/connection.c b/net/rds/connection.c index 87df15b9f8e4..180b83ab2607 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c | |||
@@ -62,6 +62,7 @@ static struct hlist_head *rds_conn_bucket(__be32 laddr, __be32 faddr) | |||
62 | var |= RDS_INFO_CONNECTION_FLAG_##suffix; \ | 62 | var |= RDS_INFO_CONNECTION_FLAG_##suffix; \ |
63 | } while (0) | 63 | } while (0) |
64 | 64 | ||
65 | /* rcu read lock must be held or the connection spinlock */ | ||
65 | static struct rds_connection *rds_conn_lookup(struct hlist_head *head, | 66 | static struct rds_connection *rds_conn_lookup(struct hlist_head *head, |
66 | __be32 laddr, __be32 faddr, | 67 | __be32 laddr, __be32 faddr, |
67 | struct rds_transport *trans) | 68 | struct rds_transport *trans) |
@@ -69,7 +70,7 @@ static struct rds_connection *rds_conn_lookup(struct hlist_head *head, | |||
69 | struct rds_connection *conn, *ret = NULL; | 70 | struct rds_connection *conn, *ret = NULL; |
70 | struct hlist_node *pos; | 71 | struct hlist_node *pos; |
71 | 72 | ||
72 | hlist_for_each_entry(conn, pos, head, c_hash_node) { | 73 | hlist_for_each_entry_rcu(conn, pos, head, c_hash_node) { |
73 | if (conn->c_faddr == faddr && conn->c_laddr == laddr && | 74 | if (conn->c_faddr == faddr && conn->c_laddr == laddr && |
74 | conn->c_trans == trans) { | 75 | conn->c_trans == trans) { |
75 | ret = conn; | 76 | ret = conn; |
@@ -119,7 +120,8 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, | |||
119 | unsigned long flags; | 120 | unsigned long flags; |
120 | int ret; | 121 | int ret; |
121 | 122 | ||
122 | spin_lock_irqsave(&rds_conn_lock, flags); | 123 | |
124 | rcu_read_lock(); | ||
123 | conn = rds_conn_lookup(head, laddr, faddr, trans); | 125 | conn = rds_conn_lookup(head, laddr, faddr, trans); |
124 | if (conn && conn->c_loopback && conn->c_trans != &rds_loop_transport && | 126 | if (conn && conn->c_loopback && conn->c_trans != &rds_loop_transport && |
125 | !is_outgoing) { | 127 | !is_outgoing) { |
@@ -130,7 +132,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, | |||
130 | parent = conn; | 132 | parent = conn; |
131 | conn = parent->c_passive; | 133 | conn = parent->c_passive; |
132 | } | 134 | } |
133 | spin_unlock_irqrestore(&rds_conn_lock, flags); | 135 | rcu_read_unlock(); |
134 | if (conn) | 136 | if (conn) |
135 | goto out; | 137 | goto out; |
136 | 138 | ||
@@ -227,7 +229,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, | |||
227 | kmem_cache_free(rds_conn_slab, conn); | 229 | kmem_cache_free(rds_conn_slab, conn); |
228 | conn = found; | 230 | conn = found; |
229 | } else { | 231 | } else { |
230 | hlist_add_head(&conn->c_hash_node, head); | 232 | hlist_add_head_rcu(&conn->c_hash_node, head); |
231 | rds_cong_add_conn(conn); | 233 | rds_cong_add_conn(conn); |
232 | rds_conn_count++; | 234 | rds_conn_count++; |
233 | } | 235 | } |
@@ -306,8 +308,13 @@ void rds_conn_shutdown(struct rds_connection *conn) | |||
306 | * to the conn hash, so we never trigger a reconnect on this | 308 | * to the conn hash, so we never trigger a reconnect on this |
307 | * conn - the reconnect is always triggered by the active peer. */ | 309 | * conn - the reconnect is always triggered by the active peer. */ |
308 | cancel_delayed_work_sync(&conn->c_conn_w); | 310 | cancel_delayed_work_sync(&conn->c_conn_w); |
309 | if (!hlist_unhashed(&conn->c_hash_node)) | 311 | rcu_read_lock(); |
312 | if (!hlist_unhashed(&conn->c_hash_node)) { | ||
313 | rcu_read_unlock(); | ||
310 | rds_queue_reconnect(conn); | 314 | rds_queue_reconnect(conn); |
315 | } else { | ||
316 | rcu_read_unlock(); | ||
317 | } | ||
311 | } | 318 | } |
312 | 319 | ||
313 | /* | 320 | /* |
@@ -323,14 +330,12 @@ void rds_conn_destroy(struct rds_connection *conn) | |||
323 | 330 | ||
324 | /* Ensure conn will not be scheduled for reconnect */ | 331 | /* Ensure conn will not be scheduled for reconnect */ |
325 | spin_lock_irq(&rds_conn_lock); | 332 | spin_lock_irq(&rds_conn_lock); |
326 | hlist_del_init(&conn->c_hash_node); | 333 | hlist_del_init_rcu(&conn->c_hash_node); |
327 | spin_unlock_irq(&rds_conn_lock); | 334 | spin_unlock_irq(&rds_conn_lock); |
328 | 335 | ||
329 | /* wait for the rds thread to shut it down */ | 336 | synchronize_rcu(); |
330 | atomic_set(&conn->c_state, RDS_CONN_ERROR); | 337 | |
331 | cancel_delayed_work(&conn->c_conn_w); | 338 | rds_conn_shutdown(conn); |
332 | queue_work(rds_wq, &conn->c_down_w); | ||
333 | flush_workqueue(rds_wq); | ||
334 | 339 | ||
335 | /* tear down queued messages */ | 340 | /* tear down queued messages */ |
336 | list_for_each_entry_safe(rm, rtmp, | 341 | list_for_each_entry_safe(rm, rtmp, |
@@ -369,17 +374,16 @@ static void rds_conn_message_info(struct socket *sock, unsigned int len, | |||
369 | struct list_head *list; | 374 | struct list_head *list; |
370 | struct rds_connection *conn; | 375 | struct rds_connection *conn; |
371 | struct rds_message *rm; | 376 | struct rds_message *rm; |
372 | unsigned long flags; | ||
373 | unsigned int total = 0; | 377 | unsigned int total = 0; |
374 | size_t i; | 378 | size_t i; |
375 | 379 | ||
376 | len /= sizeof(struct rds_info_message); | 380 | len /= sizeof(struct rds_info_message); |
377 | 381 | ||
378 | spin_lock_irqsave(&rds_conn_lock, flags); | 382 | rcu_read_lock(); |
379 | 383 | ||
380 | for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash); | 384 | for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash); |
381 | i++, head++) { | 385 | i++, head++) { |
382 | hlist_for_each_entry(conn, pos, head, c_hash_node) { | 386 | hlist_for_each_entry_rcu(conn, pos, head, c_hash_node) { |
383 | if (want_send) | 387 | if (want_send) |
384 | list = &conn->c_send_queue; | 388 | list = &conn->c_send_queue; |
385 | else | 389 | else |
@@ -399,8 +403,7 @@ static void rds_conn_message_info(struct socket *sock, unsigned int len, | |||
399 | spin_unlock(&conn->c_lock); | 403 | spin_unlock(&conn->c_lock); |
400 | } | 404 | } |
401 | } | 405 | } |
402 | 406 | rcu_read_unlock(); | |
403 | spin_unlock_irqrestore(&rds_conn_lock, flags); | ||
404 | 407 | ||
405 | lens->nr = total; | 408 | lens->nr = total; |
406 | lens->each = sizeof(struct rds_info_message); | 409 | lens->each = sizeof(struct rds_info_message); |
@@ -430,19 +433,17 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, | |||
430 | uint64_t buffer[(item_len + 7) / 8]; | 433 | uint64_t buffer[(item_len + 7) / 8]; |
431 | struct hlist_head *head; | 434 | struct hlist_head *head; |
432 | struct hlist_node *pos; | 435 | struct hlist_node *pos; |
433 | struct hlist_node *tmp; | ||
434 | struct rds_connection *conn; | 436 | struct rds_connection *conn; |
435 | unsigned long flags; | ||
436 | size_t i; | 437 | size_t i; |
437 | 438 | ||
438 | spin_lock_irqsave(&rds_conn_lock, flags); | 439 | rcu_read_lock(); |
439 | 440 | ||
440 | lens->nr = 0; | 441 | lens->nr = 0; |
441 | lens->each = item_len; | 442 | lens->each = item_len; |
442 | 443 | ||
443 | for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash); | 444 | for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash); |
444 | i++, head++) { | 445 | i++, head++) { |
445 | hlist_for_each_entry_safe(conn, pos, tmp, head, c_hash_node) { | 446 | hlist_for_each_entry_rcu(conn, pos, head, c_hash_node) { |
446 | 447 | ||
447 | /* XXX no c_lock usage.. */ | 448 | /* XXX no c_lock usage.. */ |
448 | if (!visitor(conn, buffer)) | 449 | if (!visitor(conn, buffer)) |
@@ -458,8 +459,7 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, | |||
458 | lens->nr++; | 459 | lens->nr++; |
459 | } | 460 | } |
460 | } | 461 | } |
461 | 462 | rcu_read_unlock(); | |
462 | spin_unlock_irqrestore(&rds_conn_lock, flags); | ||
463 | } | 463 | } |
464 | EXPORT_SYMBOL_GPL(rds_for_each_conn_info); | 464 | EXPORT_SYMBOL_GPL(rds_for_each_conn_info); |
465 | 465 | ||