Commit 621135a0 authored by David S. Miller's avatar David S. Miller

Merge branch 'mptcp-update-mptcp-ack-sequence-outside-of-recv-path'

Florian Westphal says:

====================
mptcp: update mptcp ack sequence outside of recv path

This series moves mptcp-level ack sequence update outside of the recvmsg path.
Current approach has two problems:

1. There is delay between arrival of new data and the time we can ack
   this data.
2. If userspace doesn't call recv for some time, mptcp ack_seq is not
   updated at all, even if this data is queued in the subflow socket
   receive queue.

Move skbs from the subflow socket receive queue to the mptcp-level
receive queue, updating the mptcp-level ack sequence and have recv
take skbs from the mptcp-level receive queue.

The first place where we will attempt to update the mptcp level acks
is from the subflows' data_ready callback, even before we make userspace
aware of new data.

Because of possible deadlock (we need to take the mptcp socket lock
while already holding the subflow sockets lock), we may still need to
defer the mptcp-level ack update.  In such case, this work will be either
done from work queue or recv path, depending on which runs sooner.

In order to avoid pointless scheduling of the work queue, work
will be queued from the mptcp sockets lock release callback.
This allows to detect when the socket owner did drain the subflow
socket receive queue.

Please see individual patches for more information.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5cd129dd 14c441b5
This diff is collapsed.
......@@ -70,6 +70,7 @@ struct mptcp_sock {
u32 token;
unsigned long flags;
bool can_ack;
struct work_struct work;
struct list_head conn_list;
struct skb_ext *cached_ext; /* for the next sendmsg */
struct socket *subflow; /* outgoing connect/listener/!mp_capable */
......@@ -190,17 +191,11 @@ void mptcp_proto_init(void);
int mptcp_proto_v6_init(void);
#endif
struct mptcp_read_arg {
struct msghdr *msg;
};
int mptcp_read_actor(read_descriptor_t *desc, struct sk_buff *skb,
unsigned int offset, size_t len);
void mptcp_get_options(const struct sk_buff *skb,
struct tcp_options_received *opt_rx);
void mptcp_finish_connect(struct sock *sk);
void mptcp_data_ready(struct sock *sk, struct sock *ssk);
int mptcp_token_new_request(struct request_sock *req);
void mptcp_token_destroy_request(u32 token);
......
......@@ -408,6 +408,18 @@ static enum mapping_status get_mapping_status(struct sock *ssk)
return MAPPING_OK;
}
static int subflow_read_actor(read_descriptor_t *desc,
struct sk_buff *skb,
unsigned int offset, size_t len)
{
size_t copy_len = min(desc->count, len);
desc->count -= copy_len;
pr_debug("flushed %zu bytes, %zu left", copy_len, desc->count);
return copy_len;
}
static bool subflow_check_data_avail(struct sock *ssk)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
......@@ -482,16 +494,12 @@ static bool subflow_check_data_avail(struct sock *ssk)
pr_debug("discarding %zu bytes, current map len=%d", delta,
map_remaining);
if (delta) {
struct mptcp_read_arg arg = {
.msg = NULL,
};
read_descriptor_t desc = {
.count = delta,
.arg.data = &arg,
};
int ret;
ret = tcp_read_sock(ssk, &desc, mptcp_read_actor);
ret = tcp_read_sock(ssk, &desc, subflow_read_actor);
if (ret < 0) {
ssk->sk_err = -ret;
goto fatal;
......@@ -554,11 +562,8 @@ static void subflow_data_ready(struct sock *sk)
return;
}
if (mptcp_subflow_data_available(sk)) {
set_bit(MPTCP_DATA_READY, &mptcp_sk(parent)->flags);
parent->sk_data_ready(parent);
}
if (mptcp_subflow_data_available(sk))
mptcp_data_ready(parent, sk);
}
static void subflow_write_space(struct sock *sk)
......@@ -690,11 +695,8 @@ static void subflow_state_change(struct sock *sk)
* a fin packet carrying a DSS can be unnoticed if we don't trigger
* the data available machinery here.
*/
if (parent && subflow->mp_capable && mptcp_subflow_data_available(sk)) {
set_bit(MPTCP_DATA_READY, &mptcp_sk(parent)->flags);
parent->sk_data_ready(parent);
}
if (parent && subflow->mp_capable && mptcp_subflow_data_available(sk))
mptcp_data_ready(parent, sk);
if (parent && !(parent->sk_shutdown & RCV_SHUTDOWN) &&
!subflow->rx_eof && subflow_is_done(sk)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment