aboutsummaryrefslogtreecommitdiffstats
path: root/net/rds/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/rds/tcp.c')
-rw-r--r--net/rds/tcp.c78
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 */
137void 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);
187newsock:
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 */
133void rds_tcp_set_callbacks(struct socket *sock, struct rds_connection *conn) 205void rds_tcp_set_callbacks(struct socket *sock, struct rds_connection *conn)
134{ 206{