diff options
author | Andreas Gruenbacher <agruen@linbit.com> | 2012-08-10 11:00:30 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-09 08:05:50 -0500 |
commit | 715306f69d85f7ea21eaef4efe75b8364cfea1d5 (patch) | |
tree | f6abd1f0a94aab0d2e097b72743f7dbe9ef9deaa | |
parent | eb12010e9af119c84e6b2214064a98681027e0e3 (diff) |
drbd: Don't unregister socket state_change callback from within the callback
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 31 |
1 files changed, 18 insertions, 13 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 99121076bf12..14df37ccd524 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -679,21 +679,15 @@ struct accept_wait_data { | |||
679 | 679 | ||
680 | }; | 680 | }; |
681 | 681 | ||
682 | static void incomming_connection(struct sock *sk) | 682 | static void drbd_incoming_connection(struct sock *sk) |
683 | { | 683 | { |
684 | struct accept_wait_data *ad = sk->sk_user_data; | 684 | struct accept_wait_data *ad = sk->sk_user_data; |
685 | struct drbd_tconn *tconn = ad->tconn; | 685 | void (*state_change)(struct sock *sk); |
686 | 686 | ||
687 | if (sk->sk_state != TCP_ESTABLISHED) | 687 | state_change = ad->original_sk_state_change; |
688 | conn_warn(tconn, "unexpected tcp state change. sk_state = %d\n", sk->sk_state); | 688 | if (sk->sk_state == TCP_ESTABLISHED) |
689 | 689 | complete(&ad->door_bell); | |
690 | write_lock_bh(&sk->sk_callback_lock); | 690 | state_change(sk); |
691 | sk->sk_state_change = ad->original_sk_state_change; | ||
692 | sk->sk_user_data = NULL; | ||
693 | write_unlock_bh(&sk->sk_callback_lock); | ||
694 | |||
695 | sk->sk_state_change(sk); | ||
696 | complete(&ad->door_bell); | ||
697 | } | 691 | } |
698 | 692 | ||
699 | static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_data *ad) | 693 | static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_data *ad) |
@@ -736,7 +730,7 @@ static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_da | |||
736 | ad->s_listen = s_listen; | 730 | ad->s_listen = s_listen; |
737 | write_lock_bh(&s_listen->sk->sk_callback_lock); | 731 | write_lock_bh(&s_listen->sk->sk_callback_lock); |
738 | ad->original_sk_state_change = s_listen->sk->sk_state_change; | 732 | ad->original_sk_state_change = s_listen->sk->sk_state_change; |
739 | s_listen->sk->sk_state_change = incomming_connection; | 733 | s_listen->sk->sk_state_change = drbd_incoming_connection; |
740 | s_listen->sk->sk_user_data = ad; | 734 | s_listen->sk->sk_user_data = ad; |
741 | write_unlock_bh(&s_listen->sk->sk_callback_lock); | 735 | write_unlock_bh(&s_listen->sk->sk_callback_lock); |
742 | 736 | ||
@@ -759,6 +753,14 @@ out: | |||
759 | return -EIO; | 753 | return -EIO; |
760 | } | 754 | } |
761 | 755 | ||
756 | static void unregister_state_change(struct sock *sk, struct accept_wait_data *ad) | ||
757 | { | ||
758 | write_lock_bh(&sk->sk_callback_lock); | ||
759 | sk->sk_state_change = ad->original_sk_state_change; | ||
760 | sk->sk_user_data = NULL; | ||
761 | write_unlock_bh(&sk->sk_callback_lock); | ||
762 | } | ||
763 | |||
762 | static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct accept_wait_data *ad) | 764 | static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct accept_wait_data *ad) |
763 | { | 765 | { |
764 | int timeo, connect_int, err = 0; | 766 | int timeo, connect_int, err = 0; |
@@ -789,6 +791,9 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct acc | |||
789 | } | 791 | } |
790 | } | 792 | } |
791 | 793 | ||
794 | if (s_estab) | ||
795 | unregister_state_change(s_estab->sk, ad); | ||
796 | |||
792 | return s_estab; | 797 | return s_estab; |
793 | } | 798 | } |
794 | 799 | ||