@@ -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);
}
@@ -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 */
};
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 actually 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 <pabeni@redhat.com> --- v1 -> v2: - properly convert to bool mptcp_ext_cache_refill() return value Note: a rebased tree including DATA_FIN, v1 and this patches is avaliable here: https://github.com/pabeni/mptcp/tree/mptcp_net-next_FIN_v1_recvmsg --- net/mptcp/protocol.c | 39 +++++++++++++++++++++++++-------------- net/mptcp/protocol.h | 1 + 2 files changed, 26 insertions(+), 14 deletions(-)