diff options
Diffstat (limited to 'net/rds/connection.c')
-rw-r--r-- | net/rds/connection.c | 21 |
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 | } |
694 | EXPORT_SYMBOL_GPL(rds_conn_path_drop); | 701 | EXPORT_SYMBOL_GPL(rds_conn_path_drop); |
695 | 702 | ||
@@ -706,9 +713,15 @@ EXPORT_SYMBOL_GPL(rds_conn_drop); | |||
706 | */ | 713 | */ |
707 | void rds_conn_path_connect_if_down(struct rds_conn_path *cp) | 714 | void 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 | } |
713 | EXPORT_SYMBOL_GPL(rds_conn_path_connect_if_down); | 726 | EXPORT_SYMBOL_GPL(rds_conn_path_connect_if_down); |
714 | 727 | ||