diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 96ab2ffc2a41..46c55793dd8d 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -666,12 +666,11 @@ out: return sock; } -static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn) +static struct socket *prepare_listen_socket(struct drbd_tconn *tconn) { - int timeo, err, my_addr_len; - int sndbuf_size, rcvbuf_size, connect_int; - struct socket *s_estab = NULL, *s_listen; + int err, sndbuf_size, rcvbuf_size, my_addr_len; struct sockaddr_in6 my_addr; + struct socket *s_listen; struct net_conf *nc; const char *what; @@ -683,7 +682,6 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn) } sndbuf_size = nc->sndbuf_size; rcvbuf_size = nc->rcvbuf_size; - connect_int = nc->connect_int; rcu_read_unlock(); my_addr_len = min_t(int, tconn->my_addr_len, sizeof(struct sockaddr_in6)); @@ -691,18 +689,13 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn) what = "sock_create_kern"; err = sock_create_kern(((struct sockaddr *)&my_addr)->sa_family, - SOCK_STREAM, IPPROTO_TCP, &s_listen); + SOCK_STREAM, IPPROTO_TCP, &s_listen); if (err) { s_listen = NULL; goto out; } - timeo = connect_int * HZ; - timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */ - - s_listen->sk->sk_reuse = 1; /* SO_REUSEADDR */ - s_listen->sk->sk_rcvtimeo = timeo; - s_listen->sk->sk_sndtimeo = timeo; + s_listen->sk->sk_reuse = 1; /* SO_REUSEADDR */ drbd_setbufsize(s_listen, sndbuf_size, rcvbuf_size); what = "bind before listen"; @@ -715,7 +708,46 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn) if (err < 0) goto out; - what = "accept"; + return s_listen; +out: + if (s_listen) + sock_release(s_listen); + if (err < 0) { + if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) { + conn_err(tconn, "%s failed, err = %d\n", what, err); + conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); + } + } + + return NULL; +} + +static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn) +{ + int timeo, connect_int, err = 0; + struct socket *s_estab = NULL; + struct socket *s_listen; + struct net_conf *nc; + + rcu_read_lock(); + nc = rcu_dereference(tconn->net_conf); + if (!nc) { + rcu_read_unlock(); + return NULL; + } + connect_int = nc->connect_int; + rcu_read_unlock(); + + timeo = connect_int * HZ; + timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */ + + s_listen = prepare_listen_socket(tconn); + if (!s_listen) + goto out; + + s_listen->sk->sk_rcvtimeo = timeo; + s_listen->sk->sk_sndtimeo = timeo; + err = kernel_accept(s_listen, &s_estab, 0); out: @@ -723,7 +755,7 @@ out: sock_release(s_listen); if (err < 0) { if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) { - conn_err(tconn, "%s failed, err = %d\n", what, err); + conn_err(tconn, "accept failed, err = %d\n", err); conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); } }