Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 715306f6 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Philipp Reisner
Browse files

drbd: Don't unregister socket state_change callback from within the callback

parent eb12010e
Loading
Loading
Loading
Loading
+18 −13
Original line number Diff line number Diff line
@@ -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 drbd_tconn *tconn = ad->tconn;
	void (*state_change)(struct sock *sk);

	if (sk->sk_state != TCP_ESTABLISHED)
		conn_warn(tconn, "unexpected tcp state change. sk_state = %d\n", sk->sk_state);

	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);

	sk->sk_state_change(sk);
	state_change = ad->original_sk_state_change;
	if (sk->sk_state == TCP_ESTABLISHED)
		complete(&ad->door_bell);
	state_change(sk);
}

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;
	write_lock_bh(&s_listen->sk->sk_callback_lock);
	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;
	write_unlock_bh(&s_listen->sk->sk_callback_lock);

@@ -759,6 +753,14 @@ static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_da
	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)
{
	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;
}