Commit 7a426fd8 authored by Philipp Reisner's avatar Philipp Reisner

drbd: Keep the listening socket open while trying to connect to the peer

Signed-off-by: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
parent 1f3e509b
...@@ -666,7 +666,32 @@ static struct socket *drbd_try_connect(struct drbd_tconn *tconn) ...@@ -666,7 +666,32 @@ static struct socket *drbd_try_connect(struct drbd_tconn *tconn)
return sock; return sock;
} }
static struct socket *prepare_listen_socket(struct drbd_tconn *tconn) struct accept_wait_data {
struct drbd_tconn *tconn;
struct socket *s_listen;
struct completion door_bell;
void (*original_sk_state_change)(struct sock *sk);
};
static void incomming_connection(struct sock *sk)
{
struct accept_wait_data *ad = sk->sk_user_data;
struct drbd_tconn *tconn = ad->tconn;
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);
complete(&ad->door_bell);
}
static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_data *ad)
{ {
int err, sndbuf_size, rcvbuf_size, my_addr_len; int err, sndbuf_size, rcvbuf_size, my_addr_len;
struct sockaddr_in6 my_addr; struct sockaddr_in6 my_addr;
...@@ -678,7 +703,7 @@ static struct socket *prepare_listen_socket(struct drbd_tconn *tconn) ...@@ -678,7 +703,7 @@ static struct socket *prepare_listen_socket(struct drbd_tconn *tconn)
nc = rcu_dereference(tconn->net_conf); nc = rcu_dereference(tconn->net_conf);
if (!nc) { if (!nc) {
rcu_read_unlock(); rcu_read_unlock();
return NULL; return -EIO;
} }
sndbuf_size = nc->sndbuf_size; sndbuf_size = nc->sndbuf_size;
rcvbuf_size = nc->rcvbuf_size; rcvbuf_size = nc->rcvbuf_size;
...@@ -703,12 +728,19 @@ static struct socket *prepare_listen_socket(struct drbd_tconn *tconn) ...@@ -703,12 +728,19 @@ static struct socket *prepare_listen_socket(struct drbd_tconn *tconn)
if (err < 0) if (err < 0)
goto out; goto out;
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_user_data = ad;
write_unlock_bh(&s_listen->sk->sk_callback_lock);
what = "listen"; what = "listen";
err = s_listen->ops->listen(s_listen, 5); err = s_listen->ops->listen(s_listen, 5);
if (err < 0) if (err < 0)
goto out; goto out;
return s_listen; return 0;
out: out:
if (s_listen) if (s_listen)
sock_release(s_listen); sock_release(s_listen);
...@@ -719,14 +751,13 @@ static struct socket *prepare_listen_socket(struct drbd_tconn *tconn) ...@@ -719,14 +751,13 @@ static struct socket *prepare_listen_socket(struct drbd_tconn *tconn)
} }
} }
return NULL; return -EIO;
} }
static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn) 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;
struct socket *s_estab = NULL; struct socket *s_estab = NULL;
struct socket *s_listen;
struct net_conf *nc; struct net_conf *nc;
rcu_read_lock(); rcu_read_lock();
...@@ -741,18 +772,11 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn) ...@@ -741,18 +772,11 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn)
timeo = connect_int * HZ; timeo = connect_int * HZ;
timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */ timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */
s_listen = prepare_listen_socket(tconn); err = wait_for_completion_interruptible_timeout(&ad->door_bell, timeo);
if (!s_listen) if (err <= 0)
goto out; return NULL;
s_listen->sk->sk_rcvtimeo = timeo;
s_listen->sk->sk_sndtimeo = timeo;
err = kernel_accept(s_listen, &s_estab, 0);
out: err = kernel_accept(ad->s_listen, &s_estab, 0);
if (s_listen)
sock_release(s_listen);
if (err < 0) { if (err < 0) {
if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) { if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) {
conn_err(tconn, "accept failed, err = %d\n", err); conn_err(tconn, "accept failed, err = %d\n", err);
...@@ -855,6 +879,10 @@ static int conn_connect(struct drbd_tconn *tconn) ...@@ -855,6 +879,10 @@ static int conn_connect(struct drbd_tconn *tconn)
int vnr, timeout, try, h, ok; int vnr, timeout, try, h, ok;
bool discard_my_data; bool discard_my_data;
enum drbd_state_rv rv; enum drbd_state_rv rv;
struct accept_wait_data ad = {
.tconn = tconn,
.door_bell = COMPLETION_INITIALIZER_ONSTACK(ad.door_bell),
};
if (conn_request_state(tconn, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS) if (conn_request_state(tconn, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS)
return -2; return -2;
...@@ -873,6 +901,9 @@ static int conn_connect(struct drbd_tconn *tconn) ...@@ -873,6 +901,9 @@ static int conn_connect(struct drbd_tconn *tconn)
/* Assume that the peer only understands protocol 80 until we know better. */ /* Assume that the peer only understands protocol 80 until we know better. */
tconn->agreed_pro_version = 80; tconn->agreed_pro_version = 80;
if (prepare_listen_socket(tconn, &ad))
return 0;
do { do {
struct socket *s; struct socket *s;
...@@ -911,7 +942,7 @@ static int conn_connect(struct drbd_tconn *tconn) ...@@ -911,7 +942,7 @@ static int conn_connect(struct drbd_tconn *tconn)
} }
retry: retry:
s = drbd_wait_for_connect(tconn); s = drbd_wait_for_connect(tconn, &ad);
if (s) { if (s) {
try = receive_first_packet(tconn, s); try = receive_first_packet(tconn, s);
drbd_socket_okay(&sock.socket); drbd_socket_okay(&sock.socket);
...@@ -957,6 +988,9 @@ static int conn_connect(struct drbd_tconn *tconn) ...@@ -957,6 +988,9 @@ static int conn_connect(struct drbd_tconn *tconn)
} }
} while (1); } while (1);
if (ad.s_listen)
sock_release(ad.s_listen);
sock.socket->sk->sk_reuse = 1; /* SO_REUSEADDR */ sock.socket->sk->sk_reuse = 1; /* SO_REUSEADDR */
msock.socket->sk->sk_reuse = 1; /* SO_REUSEADDR */ msock.socket->sk->sk_reuse = 1; /* SO_REUSEADDR */
...@@ -1052,6 +1086,8 @@ static int conn_connect(struct drbd_tconn *tconn) ...@@ -1052,6 +1086,8 @@ static int conn_connect(struct drbd_tconn *tconn)
return h; return h;
out_release_sockets: out_release_sockets:
if (ad.s_listen)
sock_release(ad.s_listen);
if (sock.socket) if (sock.socket)
sock_release(sock.socket); sock_release(sock.socket);
if (msock.socket) if (msock.socket)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment