diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2011-12-19 16:42:56 -0500 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 10:58:13 -0500 |
commit | 7da358625c056b631b0abf2fcf50dad5bcbc22d9 (patch) | |
tree | bddb07eb9171846ddc48119c9549b078b0d395ac /drivers/block/drbd/drbd_receiver.c | |
parent | a01842ebeea315cbe4382703c065f671d8cd7622 (diff) |
drbd: Restore late assigning of tconn->data.sock and meta.sock
With commit from Mon Mar 28 16:33:12 2011 +0200
"drbd: drbd_connect(): Initialize struct drbd_socket before sending anything"
tconn->data.sock and tconn->meta.sock get assigned early, in
conn_connect.
The early assigning can trigger an OOPS, because it may released the socket
without acquiring the mutex protecting the socket. An other thread (worker)
might use setsockopt() on the socket while it gets free()ed.
Restored the (proven) 8.3 behavior of assigning these sockets after the two
connections are established.
Credits for reporting the issue are going to Arne Redlich.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_receiver.c')
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 106 |
1 files changed, 57 insertions, 49 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 1b6845a6ba8d..c8d3f38d539f 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -842,7 +842,7 @@ int drbd_connected(struct drbd_conf *mdev) | |||
842 | */ | 842 | */ |
843 | static int conn_connect(struct drbd_tconn *tconn) | 843 | static int conn_connect(struct drbd_tconn *tconn) |
844 | { | 844 | { |
845 | struct socket *sock, *msock; | 845 | struct drbd_socket sock, msock; |
846 | struct drbd_conf *mdev; | 846 | struct drbd_conf *mdev; |
847 | struct net_conf *nc; | 847 | struct net_conf *nc; |
848 | int vnr, timeout, try, h, ok; | 848 | int vnr, timeout, try, h, ok; |
@@ -851,6 +851,15 @@ static int conn_connect(struct drbd_tconn *tconn) | |||
851 | if (conn_request_state(tconn, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS) | 851 | if (conn_request_state(tconn, NS(conn, C_WF_CONNECTION), CS_VERBOSE) < SS_SUCCESS) |
852 | return -2; | 852 | return -2; |
853 | 853 | ||
854 | mutex_init(&sock.mutex); | ||
855 | sock.sbuf = tconn->data.sbuf; | ||
856 | sock.rbuf = tconn->data.rbuf; | ||
857 | sock.socket = NULL; | ||
858 | mutex_init(&msock.mutex); | ||
859 | msock.sbuf = tconn->meta.sbuf; | ||
860 | msock.rbuf = tconn->meta.rbuf; | ||
861 | msock.socket = NULL; | ||
862 | |||
854 | clear_bit(DISCARD_CONCURRENT, &tconn->flags); | 863 | clear_bit(DISCARD_CONCURRENT, &tconn->flags); |
855 | 864 | ||
856 | /* Assume that the peer only understands protocol 80 until we know better. */ | 865 | /* Assume that the peer only understands protocol 80 until we know better. */ |
@@ -869,22 +878,26 @@ static int conn_connect(struct drbd_tconn *tconn) | |||
869 | } | 878 | } |
870 | 879 | ||
871 | if (s) { | 880 | if (s) { |
872 | if (!tconn->data.socket) { | 881 | if (!sock.socket) { |
873 | tconn->data.socket = s; | 882 | sock.socket = s; |
874 | send_first_packet(tconn, &tconn->data, P_INITIAL_DATA); | 883 | send_first_packet(tconn, &sock, P_INITIAL_DATA); |
875 | } else if (!tconn->meta.socket) { | 884 | } else if (!msock.socket) { |
876 | tconn->meta.socket = s; | 885 | msock.socket = s; |
877 | send_first_packet(tconn, &tconn->meta, P_INITIAL_META); | 886 | send_first_packet(tconn, &msock, P_INITIAL_META); |
878 | } else { | 887 | } else { |
879 | conn_err(tconn, "Logic error in conn_connect()\n"); | 888 | conn_err(tconn, "Logic error in conn_connect()\n"); |
880 | goto out_release_sockets; | 889 | goto out_release_sockets; |
881 | } | 890 | } |
882 | } | 891 | } |
883 | 892 | ||
884 | if (tconn->data.socket && tconn->meta.socket) { | 893 | if (sock.socket && msock.socket) { |
885 | schedule_timeout_interruptible(tconn->net_conf->ping_timeo*HZ/10); | 894 | rcu_read_lock(); |
886 | ok = drbd_socket_okay(&tconn->data.socket); | 895 | nc = rcu_dereference(tconn->net_conf); |
887 | ok = drbd_socket_okay(&tconn->meta.socket) && ok; | 896 | timeout = nc->ping_timeo * HZ / 10; |
897 | rcu_read_unlock(); | ||
898 | schedule_timeout_interruptible(timeout); | ||
899 | ok = drbd_socket_okay(&sock.socket); | ||
900 | ok = drbd_socket_okay(&msock.socket) && ok; | ||
888 | if (ok) | 901 | if (ok) |
889 | break; | 902 | break; |
890 | } | 903 | } |
@@ -893,22 +906,22 @@ retry: | |||
893 | s = drbd_wait_for_connect(tconn); | 906 | s = drbd_wait_for_connect(tconn); |
894 | if (s) { | 907 | if (s) { |
895 | try = receive_first_packet(tconn, s); | 908 | try = receive_first_packet(tconn, s); |
896 | drbd_socket_okay(&tconn->data.socket); | 909 | drbd_socket_okay(&sock.socket); |
897 | drbd_socket_okay(&tconn->meta.socket); | 910 | drbd_socket_okay(&msock.socket); |
898 | switch (try) { | 911 | switch (try) { |
899 | case P_INITIAL_DATA: | 912 | case P_INITIAL_DATA: |
900 | if (tconn->data.socket) { | 913 | if (sock.socket) { |
901 | conn_warn(tconn, "initial packet S crossed\n"); | 914 | conn_warn(tconn, "initial packet S crossed\n"); |
902 | sock_release(tconn->data.socket); | 915 | sock_release(sock.socket); |
903 | } | 916 | } |
904 | tconn->data.socket = s; | 917 | sock.socket = s; |
905 | break; | 918 | break; |
906 | case P_INITIAL_META: | 919 | case P_INITIAL_META: |
907 | if (tconn->meta.socket) { | 920 | if (msock.socket) { |
908 | conn_warn(tconn, "initial packet M crossed\n"); | 921 | conn_warn(tconn, "initial packet M crossed\n"); |
909 | sock_release(tconn->meta.socket); | 922 | sock_release(msock.socket); |
910 | } | 923 | } |
911 | tconn->meta.socket = s; | 924 | msock.socket = s; |
912 | set_bit(DISCARD_CONCURRENT, &tconn->flags); | 925 | set_bit(DISCARD_CONCURRENT, &tconn->flags); |
913 | break; | 926 | break; |
914 | default: | 927 | default: |
@@ -928,49 +941,48 @@ retry: | |||
928 | goto out_release_sockets; | 941 | goto out_release_sockets; |
929 | } | 942 | } |
930 | 943 | ||
931 | if (tconn->data.socket && &tconn->meta.socket) { | 944 | if (sock.socket && &msock.socket) { |
932 | ok = drbd_socket_okay(&tconn->data.socket); | 945 | ok = drbd_socket_okay(&sock.socket); |
933 | ok = drbd_socket_okay(&tconn->meta.socket) && ok; | 946 | ok = drbd_socket_okay(&msock.socket) && ok; |
934 | if (ok) | 947 | if (ok) |
935 | break; | 948 | break; |
936 | } | 949 | } |
937 | } while (1); | 950 | } while (1); |
938 | 951 | ||
939 | sock = tconn->data.socket; | 952 | sock.socket->sk->sk_reuse = 1; /* SO_REUSEADDR */ |
940 | msock = tconn->meta.socket; | 953 | msock.socket->sk->sk_reuse = 1; /* SO_REUSEADDR */ |
941 | 954 | ||
942 | msock->sk->sk_reuse = 1; /* SO_REUSEADDR */ | 955 | sock.socket->sk->sk_allocation = GFP_NOIO; |
943 | sock->sk->sk_reuse = 1; /* SO_REUSEADDR */ | 956 | msock.socket->sk->sk_allocation = GFP_NOIO; |
944 | 957 | ||
945 | sock->sk->sk_allocation = GFP_NOIO; | 958 | sock.socket->sk->sk_priority = TC_PRIO_INTERACTIVE_BULK; |
946 | msock->sk->sk_allocation = GFP_NOIO; | 959 | msock.socket->sk->sk_priority = TC_PRIO_INTERACTIVE; |
947 | |||
948 | sock->sk->sk_priority = TC_PRIO_INTERACTIVE_BULK; | ||
949 | msock->sk->sk_priority = TC_PRIO_INTERACTIVE; | ||
950 | 960 | ||
951 | /* NOT YET ... | 961 | /* NOT YET ... |
952 | * sock->sk->sk_sndtimeo = tconn->net_conf->timeout*HZ/10; | 962 | * sock.socket->sk->sk_sndtimeo = tconn->net_conf->timeout*HZ/10; |
953 | * sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; | 963 | * sock.socket->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; |
954 | * first set it to the P_CONNECTION_FEATURES timeout, | 964 | * first set it to the P_CONNECTION_FEATURES timeout, |
955 | * which we set to 4x the configured ping_timeout. */ | 965 | * which we set to 4x the configured ping_timeout. */ |
956 | rcu_read_lock(); | 966 | rcu_read_lock(); |
957 | nc = rcu_dereference(tconn->net_conf); | 967 | nc = rcu_dereference(tconn->net_conf); |
958 | 968 | ||
959 | sock->sk->sk_sndtimeo = | 969 | sock.socket->sk->sk_sndtimeo = |
960 | sock->sk->sk_rcvtimeo = nc->ping_timeo*4*HZ/10; | 970 | sock.socket->sk->sk_rcvtimeo = nc->ping_timeo*4*HZ/10; |
961 | 971 | ||
962 | msock->sk->sk_rcvtimeo = nc->ping_int*HZ; | 972 | msock.socket->sk->sk_rcvtimeo = nc->ping_int*HZ; |
963 | timeout = nc->timeout * HZ / 10; | 973 | timeout = nc->timeout * HZ / 10; |
964 | discard_my_data = nc->discard_my_data; | 974 | discard_my_data = nc->discard_my_data; |
965 | rcu_read_unlock(); | 975 | rcu_read_unlock(); |
966 | 976 | ||
967 | msock->sk->sk_sndtimeo = timeout; | 977 | msock.socket->sk->sk_sndtimeo = timeout; |
968 | 978 | ||
969 | /* we don't want delays. | 979 | /* we don't want delays. |
970 | * we use TCP_CORK where appropriate, though */ | 980 | * we use TCP_CORK where appropriate, though */ |
971 | drbd_tcp_nodelay(sock); | 981 | drbd_tcp_nodelay(sock.socket); |
972 | drbd_tcp_nodelay(msock); | 982 | drbd_tcp_nodelay(msock.socket); |
973 | 983 | ||
984 | tconn->data.socket = sock.socket; | ||
985 | tconn->meta.socket = msock.socket; | ||
974 | tconn->last_received = jiffies; | 986 | tconn->last_received = jiffies; |
975 | 987 | ||
976 | h = drbd_do_features(tconn); | 988 | h = drbd_do_features(tconn); |
@@ -989,8 +1001,8 @@ retry: | |||
989 | } | 1001 | } |
990 | } | 1002 | } |
991 | 1003 | ||
992 | sock->sk->sk_sndtimeo = timeout; | 1004 | tconn->data.socket->sk->sk_sndtimeo = timeout; |
993 | sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; | 1005 | tconn->data.socket->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; |
994 | 1006 | ||
995 | if (drbd_send_protocol(tconn) == -EOPNOTSUPP) | 1007 | if (drbd_send_protocol(tconn) == -EOPNOTSUPP) |
996 | return -1; | 1008 | return -1; |
@@ -1027,14 +1039,10 @@ retry: | |||
1027 | return h; | 1039 | return h; |
1028 | 1040 | ||
1029 | out_release_sockets: | 1041 | out_release_sockets: |
1030 | if (tconn->data.socket) { | 1042 | if (sock.socket) |
1031 | sock_release(tconn->data.socket); | 1043 | sock_release(sock.socket); |
1032 | tconn->data.socket = NULL; | 1044 | if (msock.socket) |
1033 | } | 1045 | sock_release(msock.socket); |
1034 | if (tconn->meta.socket) { | ||
1035 | sock_release(tconn->meta.socket); | ||
1036 | tconn->meta.socket = NULL; | ||
1037 | } | ||
1038 | return -1; | 1046 | return -1; |
1039 | } | 1047 | } |
1040 | 1048 | ||