aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2012-07-12 08:22:37 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 10:58:31 -0500
commit7a426fd8d5af1d5e71cfcdf5ecbefbbad47a81fd (patch)
tree06174b9f6f35fce19e9b74a69ca30fc89065f434 /drivers/block/drbd
parent1f3e509b761d6d8f91acbf7da39624d086e1f2eb (diff)
drbd: Keep the listening socket open while trying to connect to the peer
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd')
-rw-r--r--drivers/block/drbd/drbd_receiver.c72
1 files changed, 54 insertions, 18 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 46c55793dd8d..9aac1c4033c7 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -666,7 +666,32 @@ out:
666 return sock; 666 return sock;
667} 667}
668 668
669static struct socket *prepare_listen_socket(struct drbd_tconn *tconn) 669struct accept_wait_data {
670 struct drbd_tconn *tconn;
671 struct socket *s_listen;
672 struct completion door_bell;
673 void (*original_sk_state_change)(struct sock *sk);
674
675};
676
677static void incomming_connection(struct sock *sk)
678{
679 struct accept_wait_data *ad = sk->sk_user_data;
680 struct drbd_tconn *tconn = ad->tconn;
681
682 if (sk->sk_state != TCP_ESTABLISHED)
683 conn_warn(tconn, "unexpected tcp state change. sk_state = %d\n", sk->sk_state);
684
685 write_lock_bh(&sk->sk_callback_lock);
686 sk->sk_state_change = ad->original_sk_state_change;
687 sk->sk_user_data = NULL;
688 write_unlock_bh(&sk->sk_callback_lock);
689
690 sk->sk_state_change(sk);
691 complete(&ad->door_bell);
692}
693
694static int prepare_listen_socket(struct drbd_tconn *tconn, struct accept_wait_data *ad)
670{ 695{
671 int err, sndbuf_size, rcvbuf_size, my_addr_len; 696 int err, sndbuf_size, rcvbuf_size, my_addr_len;
672 struct sockaddr_in6 my_addr; 697 struct sockaddr_in6 my_addr;
@@ -678,7 +703,7 @@ static struct socket *prepare_listen_socket(struct drbd_tconn *tconn)
678 nc = rcu_dereference(tconn->net_conf); 703 nc = rcu_dereference(tconn->net_conf);
679 if (!nc) { 704 if (!nc) {
680 rcu_read_unlock(); 705 rcu_read_unlock();
681 return NULL; 706 return -EIO;
682 } 707 }
683 sndbuf_size = nc->sndbuf_size; 708 sndbuf_size = nc->sndbuf_size;
684 rcvbuf_size = nc->rcvbuf_size; 709 rcvbuf_size = nc->rcvbuf_size;
@@ -703,12 +728,19 @@ static struct socket *prepare_listen_socket(struct drbd_tconn *tconn)
703 if (err < 0) 728 if (err < 0)
704 goto out; 729 goto out;
705 730
731 ad->s_listen = s_listen;
732 write_lock_bh(&s_listen->sk->sk_callback_lock);
733 ad->original_sk_state_change = s_listen->sk->sk_state_change;
734 s_listen->sk->sk_state_change = incomming_connection;
735 s_listen->sk->sk_user_data = ad;
736 write_unlock_bh(&s_listen->sk->sk_callback_lock);
737
706 what = "listen"; 738 what = "listen";
707 err = s_listen->ops->listen(s_listen, 5); 739 err = s_listen->ops->listen(s_listen, 5);
708 if (err < 0) 740 if (err < 0)
709 goto out; 741 goto out;
710 742
711 return s_listen; 743 return 0;
712out: 744out:
713 if (s_listen) 745 if (s_listen)
714 sock_release(s_listen); 746 sock_release(s_listen);
@@ -719,14 +751,13 @@ out:
719 } 751 }
720 } 752 }
721 753
722 return NULL; 754 return -EIO;
723} 755}
724 756
725static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn) 757static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct accept_wait_data *ad)
726{ 758{
727 int timeo, connect_int, err = 0; 759 int timeo, connect_int, err = 0;
728 struct socket *s_estab = NULL; 760 struct socket *s_estab = NULL;
729 struct socket *s_listen;
730 struct net_conf *nc; 761 struct net_conf *nc;
731 762
732 rcu_read_lock(); 763 rcu_read_lock();
@@ -741,18 +772,11 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn)
741 timeo = connect_int * HZ; 772 timeo = connect_int * HZ;
742 timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */ 773 timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */
743 774
744 s_listen = prepare_listen_socket(tconn); 775 err = wait_for_completion_interruptible_timeout(&ad->door_bell, timeo);
745 if (!s_listen) 776 if (err <= 0)
746 goto out; 777 return NULL;
747
748 s_listen->sk->sk_rcvtimeo = timeo;
749 s_listen->sk->sk_sndtimeo = timeo;
750
751 err = kernel_accept(s_listen, &s_estab, 0);
752 778
753out: 779 err = kernel_accept(ad->s_listen, &s_estab, 0);
754 if (s_listen)
755 sock_release(s_listen);
756 if (err < 0) { 780 if (err < 0) {
757 if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) { 781 if (err != -EAGAIN && err != -EINTR && err != -ERESTARTSYS) {
758 conn_err(tconn, "accept failed, err = %d\n", err); 782 conn_err(tconn, "accept failed, err = %d\n", err);
@@ -855,6 +879,10 @@ static int conn_connect(struct drbd_tconn *tconn)
855 int vnr, timeout, try, h, ok; 879 int vnr, timeout, try, h, ok;
856 bool discard_my_data; 880 bool discard_my_data;
857 enum drbd_state_rv rv; 881 enum drbd_state_rv rv;
882 struct accept_wait_data ad = {
883 .tconn = tconn,
884 .door_bell = COMPLETION_INITIALIZER_ONSTACK(ad.door_bell),
885 };
858 886
859 if (conn_request_state(tconn, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS) 887 if (conn_request_state(tconn, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS)
860 return -2; 888 return -2;
@@ -873,6 +901,9 @@ static int conn_connect(struct drbd_tconn *tconn)
873 /* Assume that the peer only understands protocol 80 until we know better. */ 901 /* Assume that the peer only understands protocol 80 until we know better. */
874 tconn->agreed_pro_version = 80; 902 tconn->agreed_pro_version = 80;
875 903
904 if (prepare_listen_socket(tconn, &ad))
905 return 0;
906
876 do { 907 do {
877 struct socket *s; 908 struct socket *s;
878 909
@@ -911,7 +942,7 @@ static int conn_connect(struct drbd_tconn *tconn)
911 } 942 }
912 943
913retry: 944retry:
914 s = drbd_wait_for_connect(tconn); 945 s = drbd_wait_for_connect(tconn, &ad);
915 if (s) { 946 if (s) {
916 try = receive_first_packet(tconn, s); 947 try = receive_first_packet(tconn, s);
917 drbd_socket_okay(&sock.socket); 948 drbd_socket_okay(&sock.socket);
@@ -957,6 +988,9 @@ retry:
957 } 988 }
958 } while (1); 989 } while (1);
959 990
991 if (ad.s_listen)
992 sock_release(ad.s_listen);
993
960 sock.socket->sk->sk_reuse = 1; /* SO_REUSEADDR */ 994 sock.socket->sk->sk_reuse = 1; /* SO_REUSEADDR */
961 msock.socket->sk->sk_reuse = 1; /* SO_REUSEADDR */ 995 msock.socket->sk->sk_reuse = 1; /* SO_REUSEADDR */
962 996
@@ -1052,6 +1086,8 @@ retry:
1052 return h; 1086 return h;
1053 1087
1054out_release_sockets: 1088out_release_sockets:
1089 if (ad.s_listen)
1090 sock_release(ad.s_listen);
1055 if (sock.socket) 1091 if (sock.socket)
1056 sock_release(sock.socket); 1092 sock_release(sock.socket);
1057 if (msock.socket) 1093 if (msock.socket)