|
|
@@ -1964,18 +1964,30 @@ static void o2net_listen_data_ready(struct sock *sk, int bytes)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- /* ->sk_data_ready is also called for a newly established child socket
|
|
|
- * before it has been accepted and the acceptor has set up their
|
|
|
- * data_ready.. we only want to queue listen work for our listening
|
|
|
- * socket */
|
|
|
+ /* This callback may called twice when a new connection
|
|
|
+ * is being established as a child socket inherits everything
|
|
|
+ * from a parent LISTEN socket, including the data_ready cb of
|
|
|
+ * the parent. This leads to a hazard. In o2net_accept_one()
|
|
|
+ * we are still initializing the child socket but have not
|
|
|
+ * changed the inherited data_ready callback yet when
|
|
|
+ * data starts arriving.
|
|
|
+ * We avoid this hazard by checking the state.
|
|
|
+ * For the listening socket, the state will be TCP_LISTEN; for the new
|
|
|
+ * socket, will be TCP_ESTABLISHED. Also, in this case,
|
|
|
+ * sk->sk_user_data is not a valid function pointer.
|
|
|
+ */
|
|
|
+
|
|
|
if (sk->sk_state == TCP_LISTEN) {
|
|
|
mlog(ML_TCP, "bytes: %d\n", bytes);
|
|
|
queue_work(o2net_wq, &o2net_listen_work);
|
|
|
+ } else {
|
|
|
+ ready = NULL;
|
|
|
}
|
|
|
|
|
|
out:
|
|
|
read_unlock(&sk->sk_callback_lock);
|
|
|
- ready(sk, bytes);
|
|
|
+ if (ready != NULL)
|
|
|
+ ready(sk, bytes);
|
|
|
}
|
|
|
|
|
|
static int o2net_open_listening_sock(__be32 addr, __be16 port)
|