diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-06-20 11:25:44 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-06-20 11:25:44 -0400 |
commit | af52739b922f656eb1f39016fabaabe4baeda2e2 (patch) | |
tree | 79a7aa810d0493cd0cf4adebac26d37f12e8b545 /net/rds/tcp.c | |
parent | 25ed6a5e97809129a1bc852b6b5c7d03baa112c4 (diff) | |
parent | 33688abb2802ff3a230bd2441f765477b94cc89e (diff) |
Merge 4.7-rc4 into staging-next
We want the fixes in here, and we can resolve a merge issue in
drivers/iio/industrialio-trigger.c
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/rds/tcp.c')
-rw-r--r-- | net/rds/tcp.c | 78 |
1 files changed, 75 insertions, 3 deletions
diff --git a/net/rds/tcp.c b/net/rds/tcp.c index 86187dad1440..74ee126a6fe6 100644 --- a/net/rds/tcp.c +++ b/net/rds/tcp.c | |||
@@ -126,9 +126,81 @@ void rds_tcp_restore_callbacks(struct socket *sock, | |||
126 | } | 126 | } |
127 | 127 | ||
128 | /* | 128 | /* |
129 | * This is the only path that sets tc->t_sock. Send and receive trust that | 129 | * rds_tcp_reset_callbacks() switches the to the new sock and |
130 | * it is set. The RDS_CONN_UP bit protects those paths from being | 130 | * returns the existing tc->t_sock. |
131 | * called while it isn't set. | 131 | * |
132 | * The only functions that set tc->t_sock are rds_tcp_set_callbacks | ||
133 | * and rds_tcp_reset_callbacks. Send and receive trust that | ||
134 | * it is set. The absence of RDS_CONN_UP bit protects those paths | ||
135 | * from being called while it isn't set. | ||
136 | */ | ||
137 | void rds_tcp_reset_callbacks(struct socket *sock, | ||
138 | struct rds_connection *conn) | ||
139 | { | ||
140 | struct rds_tcp_connection *tc = conn->c_transport_data; | ||
141 | struct socket *osock = tc->t_sock; | ||
142 | |||
143 | if (!osock) | ||
144 | goto newsock; | ||
145 | |||
146 | /* Need to resolve a duelling SYN between peers. | ||
147 | * We have an outstanding SYN to this peer, which may | ||
148 | * potentially have transitioned to the RDS_CONN_UP state, | ||
149 | * so we must quiesce any send threads before resetting | ||
150 | * c_transport_data. We quiesce these threads by setting | ||
151 | * c_state to something other than RDS_CONN_UP, and then | ||
152 | * waiting for any existing threads in rds_send_xmit to | ||
153 | * complete release_in_xmit(). (Subsequent threads entering | ||
154 | * rds_send_xmit() will bail on !rds_conn_up(). | ||
155 | * | ||
156 | * However an incoming syn-ack at this point would end up | ||
157 | * marking the conn as RDS_CONN_UP, and would again permit | ||
158 | * rds_send_xmi() threads through, so ideally we would | ||
159 | * synchronize on RDS_CONN_UP after lock_sock(), but cannot | ||
160 | * do that: waiting on !RDS_IN_XMIT after lock_sock() may | ||
161 | * end up deadlocking with tcp_sendmsg(), and the RDS_IN_XMIT | ||
162 | * would not get set. As a result, we set c_state to | ||
163 | * RDS_CONN_RESETTTING, to ensure that rds_tcp_state_change | ||
164 | * cannot mark rds_conn_path_up() in the window before lock_sock() | ||
165 | */ | ||
166 | atomic_set(&conn->c_state, RDS_CONN_RESETTING); | ||
167 | wait_event(conn->c_waitq, !test_bit(RDS_IN_XMIT, &conn->c_flags)); | ||
168 | lock_sock(osock->sk); | ||
169 | /* reset receive side state for rds_tcp_data_recv() for osock */ | ||
170 | if (tc->t_tinc) { | ||
171 | rds_inc_put(&tc->t_tinc->ti_inc); | ||
172 | tc->t_tinc = NULL; | ||
173 | } | ||
174 | tc->t_tinc_hdr_rem = sizeof(struct rds_header); | ||
175 | tc->t_tinc_data_rem = 0; | ||
176 | tc->t_sock = NULL; | ||
177 | |||
178 | write_lock_bh(&osock->sk->sk_callback_lock); | ||
179 | |||
180 | osock->sk->sk_user_data = NULL; | ||
181 | osock->sk->sk_data_ready = tc->t_orig_data_ready; | ||
182 | osock->sk->sk_write_space = tc->t_orig_write_space; | ||
183 | osock->sk->sk_state_change = tc->t_orig_state_change; | ||
184 | write_unlock_bh(&osock->sk->sk_callback_lock); | ||
185 | release_sock(osock->sk); | ||
186 | sock_release(osock); | ||
187 | newsock: | ||
188 | rds_send_reset(conn); | ||
189 | lock_sock(sock->sk); | ||
190 | write_lock_bh(&sock->sk->sk_callback_lock); | ||
191 | tc->t_sock = sock; | ||
192 | sock->sk->sk_user_data = conn; | ||
193 | sock->sk->sk_data_ready = rds_tcp_data_ready; | ||
194 | sock->sk->sk_write_space = rds_tcp_write_space; | ||
195 | sock->sk->sk_state_change = rds_tcp_state_change; | ||
196 | |||
197 | write_unlock_bh(&sock->sk->sk_callback_lock); | ||
198 | release_sock(sock->sk); | ||
199 | } | ||
200 | |||
201 | /* Add tc to rds_tcp_tc_list and set tc->t_sock. See comments | ||
202 | * above rds_tcp_reset_callbacks for notes about synchronization | ||
203 | * with data path | ||
132 | */ | 204 | */ |
133 | void rds_tcp_set_callbacks(struct socket *sock, struct rds_connection *conn) | 205 | void rds_tcp_set_callbacks(struct socket *sock, struct rds_connection *conn) |
134 | { | 206 | { |