Currently, when if mpext allocation fails, the data stream is corrupted, as we can add the required DSS nor roll-back the TCP status. Allocate a skb_ext before the actuall skb_buff creation/TCP status update: in case of memory allocation failure we can bail early, avoiding the above condition. Additionally, if the ext is unused to to skb collapsing, cache the ext in the msk for the next send. Squash-to: "mptcp: Write MPTCP DSS headers to outgoing data packets" Signed-off-by: Paolo Abeni --- net/mptcp/protocol.c | 39 +++++++++++++++++++++++++-------------- net/mptcp/protocol.h | 1 + 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 3180202e56b4..ae158ab08101 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -55,6 +55,14 @@ static struct sock *mptcp_subflow_get(const struct mptcp_sock *msk) return NULL; } +static bool mptcp_ext_cache_refill(struct mptcp_sock *msk) +{ + if (!msk->cached_ext) + msk->cached_ext = skb_ext_alloc(); + + return msk->cached_ext; +} + static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, struct msghdr *msg, long *timeo) { @@ -69,7 +77,8 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, * from one substream to another, but do per subflow memory accounting */ pfrag = sk_page_frag(sk); - while (!sk_page_frag_refill(ssk, pfrag)) { + while (!sk_page_frag_refill(ssk, pfrag) || + !mptcp_ext_cache_refill(msk)) { ret = sk_stream_wait_memory(ssk, timeo); if (ret) return ret; @@ -103,19 +112,19 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk, iov_iter_revert(&msg->msg_iter, psize - ret); skb = tcp_write_queue_tail(ssk); - mpext = skb_ext_add(skb, SKB_EXT_MPTCP); - if (mpext) { - memset(mpext, 0, sizeof(*mpext)); - mpext->data_seq = msk->write_seq; - mpext->subflow_seq = mptcp_subflow_ctx(ssk)->rel_write_seq; - mpext->data_len = ret; - mpext->use_map = 1; - mpext->dsn64 = 1; - - pr_debug("data_seq=%llu subflow_seq=%u data_len=%u dsn64=%d", - mpext->data_seq, mpext->subflow_seq, mpext->data_len, - mpext->dsn64); - } /* TODO: else fallback */ + mpext = __skb_ext_add(skb, SKB_EXT_MPTCP, msk->cached_ext); + msk->cached_ext = NULL; + + memset(mpext, 0, sizeof(*mpext)); + mpext->data_seq = msk->write_seq; + mpext->subflow_seq = mptcp_subflow_ctx(ssk)->rel_write_seq; + mpext->data_len = ret; + mpext->use_map = 1; + mpext->dsn64 = 1; + + pr_debug("data_seq=%llu subflow_seq=%u data_len=%u dsn64=%d", + mpext->data_seq, mpext->subflow_seq, mpext->data_len, + mpext->dsn64); pfrag->offset += ret; msk->write_seq += ret; @@ -242,6 +251,8 @@ static void mptcp_close(struct sock *sk, long timeout) sock_release(mptcp_subflow_tcp_socket(subflow)); } + if (msk->cached_ext) + __skb_ext_put(msk->cached_ext); release_sock(sk); sk_common_release(sk); } diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 412718c1ae5c..3b8d1548dda1 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -58,6 +58,7 @@ struct mptcp_sock { u64 write_seq; u64 ack_seq; u32 token; + struct skb_ext *cached_ext; /* for the next sendmsg */ struct list_head conn_list; struct socket *subflow; /* outgoing connect/listener/!mp_capable */ }; -- 2.21.0