summaryrefslogtreecommitdiffstats
path: root/net/rds/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/rds/connection.c')
-rw-r--r--net/rds/connection.c21
1 files changed, 17 insertions, 4 deletions
diff --git a/net/rds/connection.c b/net/rds/connection.c
index 1eed197e694f..b10c0ef36d8d 100644
--- a/net/rds/connection.c
+++ b/net/rds/connection.c
@@ -366,8 +366,6 @@ void rds_conn_shutdown(struct rds_conn_path *cp)
366 * to the conn hash, so we never trigger a reconnect on this 366 * to the conn hash, so we never trigger a reconnect on this
367 * conn - the reconnect is always triggered by the active peer. */ 367 * conn - the reconnect is always triggered by the active peer. */
368 cancel_delayed_work_sync(&cp->cp_conn_w); 368 cancel_delayed_work_sync(&cp->cp_conn_w);
369 if (test_bit(RDS_DESTROY_PENDING, &cp->cp_flags))
370 return;
371 rcu_read_lock(); 369 rcu_read_lock();
372 if (!hlist_unhashed(&conn->c_hash_node)) { 370 if (!hlist_unhashed(&conn->c_hash_node)) {
373 rcu_read_unlock(); 371 rcu_read_unlock();
@@ -390,6 +388,7 @@ static void rds_conn_path_destroy(struct rds_conn_path *cp)
390 return; 388 return;
391 389
392 /* make sure lingering queued work won't try to ref the conn */ 390 /* make sure lingering queued work won't try to ref the conn */
391 synchronize_rcu();
393 cancel_delayed_work_sync(&cp->cp_send_w); 392 cancel_delayed_work_sync(&cp->cp_send_w);
394 cancel_delayed_work_sync(&cp->cp_recv_w); 393 cancel_delayed_work_sync(&cp->cp_recv_w);
395 394
@@ -407,6 +406,11 @@ static void rds_conn_path_destroy(struct rds_conn_path *cp)
407 if (cp->cp_xmit_rm) 406 if (cp->cp_xmit_rm)
408 rds_message_put(cp->cp_xmit_rm); 407 rds_message_put(cp->cp_xmit_rm);
409 408
409 WARN_ON(delayed_work_pending(&cp->cp_send_w));
410 WARN_ON(delayed_work_pending(&cp->cp_recv_w));
411 WARN_ON(delayed_work_pending(&cp->cp_conn_w));
412 WARN_ON(work_pending(&cp->cp_down_w));
413
410 cp->cp_conn->c_trans->conn_free(cp->cp_transport_data); 414 cp->cp_conn->c_trans->conn_free(cp->cp_transport_data);
411} 415}
412 416
@@ -686,10 +690,13 @@ void rds_conn_path_drop(struct rds_conn_path *cp, bool destroy)
686{ 690{
687 atomic_set(&cp->cp_state, RDS_CONN_ERROR); 691 atomic_set(&cp->cp_state, RDS_CONN_ERROR);
688 692
689 if (!destroy && test_bit(RDS_DESTROY_PENDING, &cp->cp_flags)) 693 rcu_read_lock();
694 if (!destroy && test_bit(RDS_DESTROY_PENDING, &cp->cp_flags)) {
695 rcu_read_unlock();
690 return; 696 return;
691 697 }
692 queue_work(rds_wq, &cp->cp_down_w); 698 queue_work(rds_wq, &cp->cp_down_w);
699 rcu_read_unlock();
693} 700}
694EXPORT_SYMBOL_GPL(rds_conn_path_drop); 701EXPORT_SYMBOL_GPL(rds_conn_path_drop);
695 702
@@ -706,9 +713,15 @@ EXPORT_SYMBOL_GPL(rds_conn_drop);
706 */ 713 */
707void rds_conn_path_connect_if_down(struct rds_conn_path *cp) 714void rds_conn_path_connect_if_down(struct rds_conn_path *cp)
708{ 715{
716 rcu_read_lock();
717 if (test_bit(RDS_DESTROY_PENDING, &cp->cp_flags)) {
718 rcu_read_unlock();
719 return;
720 }
709 if (rds_conn_path_state(cp) == RDS_CONN_DOWN && 721 if (rds_conn_path_state(cp) == RDS_CONN_DOWN &&
710 !test_and_set_bit(RDS_RECONNECT_PENDING, &cp->cp_flags)) 722 !test_and_set_bit(RDS_RECONNECT_PENDING, &cp->cp_flags))
711 queue_delayed_work(rds_wq, &cp->cp_conn_w, 0); 723 queue_delayed_work(rds_wq, &cp->cp_conn_w, 0);
724 rcu_read_unlock();
712} 725}
713EXPORT_SYMBOL_GPL(rds_conn_path_connect_if_down); 726EXPORT_SYMBOL_GPL(rds_conn_path_connect_if_down);
714 727