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>
This commit is contained in:
Andreas Gruenbacher 2012-08-10 17:00:30 +02:00 committed by Philipp Reisner
parent eb12010e9a
commit 715306f69d

View File

@ -679,21 +679,15 @@ struct accept_wait_data {
}; };
static void incomming_connection(struct sock *sk) static void drbd_incoming_connection(struct sock *sk)
{ {
struct accept_wait_data *ad = sk->sk_user_data; struct accept_wait_data *ad = sk->sk_user_data;
struct drbd_tconn *tconn = ad->tconn; void (*state_change)(struct sock *sk);
if (sk->sk_state != TCP_ESTABLISHED) state_change = ad->original_sk_state_change;
conn_warn(tconn, "unexpected tcp state change. sk_state = %d\n", sk->sk_state); if (sk->sk_state == TCP_ESTABLISHED)
complete(&ad->door_bell);
write_lock_bh(&sk->sk_callback_lock); state_change(sk);
sk->sk_state_change = ad->original_sk_state_change;
sk->sk_user_data = NULL;
write_unlock_bh(&sk->sk_callback_lock);
sk->sk_state_change(sk);
complete(&ad->door_bell);
} }
static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_data *ad) 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
ad->s_listen = s_listen; ad->s_listen = s_listen;
write_lock_bh(&s_listen->sk->sk_callback_lock); write_lock_bh(&s_listen->sk->sk_callback_lock);
ad->original_sk_state_change = s_listen->sk->sk_state_change; ad->original_sk_state_change = s_listen->sk->sk_state_change;
s_listen->sk->sk_state_change = incomming_connection; s_listen->sk->sk_state_change = drbd_incoming_connection;
s_listen->sk->sk_user_data = ad; s_listen->sk->sk_user_data = ad;
write_unlock_bh(&s_listen->sk->sk_callback_lock); write_unlock_bh(&s_listen->sk->sk_callback_lock);
@ -759,6 +753,14 @@ out:
return -EIO; return -EIO;
} }
static void unregister_state_change(struct sock *sk, struct accept_wait_data *ad)
{
write_lock_bh(&sk->sk_callback_lock);
sk->sk_state_change = ad->original_sk_state_change;
sk->sk_user_data = NULL;
write_unlock_bh(&sk->sk_callback_lock);
}
static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct accept_wait_data *ad) static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct accept_wait_data *ad)
{ {
int timeo, connect_int, err = 0; int timeo, connect_int, err = 0;
@ -789,6 +791,9 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct acc
} }
} }
if (s_estab)
unregister_state_change(s_estab->sk, ad);
return s_estab; return s_estab;
} }