Skip to content

Commit b796d04

Browse files
Paolo Abenikuba-moo
authored andcommitted
tcp: factor out tcp_build_frag()
Will be needed by the next patch, as MPTCP needs to handle directly the error/memory-allocation-needed path. No functional changes intended. Additionally let MPTCP code access the tcp_remove_empty_skb() helper. Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent c0a645a commit b796d04

File tree

2 files changed

+70
-52
lines changed

2 files changed

+70
-52
lines changed

include/net/tcp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,13 +322,16 @@ void tcp_shutdown(struct sock *sk, int how);
322322
int tcp_v4_early_demux(struct sk_buff *skb);
323323
int tcp_v4_rcv(struct sk_buff *skb);
324324

325+
void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb);
325326
int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
326327
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
327328
int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size);
328329
int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
329330
int flags);
330331
int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset,
331332
size_t size, int flags);
333+
struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags,
334+
struct page *page, int offset, size_t *size);
332335
ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
333336
size_t size, int flags);
334337
int tcp_send_mss(struct sock *sk, int *size_goal, int flags);

net/ipv4/tcp.c

Lines changed: 67 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,7 @@ int tcp_send_mss(struct sock *sk, int *size_goal, int flags)
954954
* importantly be able to generate EPOLLOUT for Edge Trigger epoll()
955955
* users.
956956
*/
957-
static void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb)
957+
void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb)
958958
{
959959
if (skb && !skb->len) {
960960
tcp_unlink_write_queue(skb, sk);
@@ -964,6 +964,68 @@ static void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb)
964964
}
965965
}
966966

967+
struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags,
968+
struct page *page, int offset, size_t *size)
969+
{
970+
struct sk_buff *skb = tcp_write_queue_tail(sk);
971+
struct tcp_sock *tp = tcp_sk(sk);
972+
bool can_coalesce;
973+
int copy, i;
974+
975+
if (!skb || (copy = size_goal - skb->len) <= 0 ||
976+
!tcp_skb_can_collapse_to(skb)) {
977+
new_segment:
978+
if (!sk_stream_memory_free(sk))
979+
return NULL;
980+
981+
skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation,
982+
tcp_rtx_and_write_queues_empty(sk));
983+
if (!skb)
984+
return NULL;
985+
986+
#ifdef CONFIG_TLS_DEVICE
987+
skb->decrypted = !!(flags & MSG_SENDPAGE_DECRYPTED);
988+
#endif
989+
skb_entail(sk, skb);
990+
copy = size_goal;
991+
}
992+
993+
if (copy > *size)
994+
copy = *size;
995+
996+
i = skb_shinfo(skb)->nr_frags;
997+
can_coalesce = skb_can_coalesce(skb, i, page, offset);
998+
if (!can_coalesce && i >= sysctl_max_skb_frags) {
999+
tcp_mark_push(tp, skb);
1000+
goto new_segment;
1001+
}
1002+
if (!sk_wmem_schedule(sk, copy))
1003+
return NULL;
1004+
1005+
if (can_coalesce) {
1006+
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
1007+
} else {
1008+
get_page(page);
1009+
skb_fill_page_desc(skb, i, page, offset, copy);
1010+
}
1011+
1012+
if (!(flags & MSG_NO_SHARED_FRAGS))
1013+
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
1014+
1015+
skb->len += copy;
1016+
skb->data_len += copy;
1017+
skb->truesize += copy;
1018+
sk_wmem_queued_add(sk, copy);
1019+
sk_mem_charge(sk, copy);
1020+
skb->ip_summed = CHECKSUM_PARTIAL;
1021+
WRITE_ONCE(tp->write_seq, tp->write_seq + copy);
1022+
TCP_SKB_CB(skb)->end_seq += copy;
1023+
tcp_skb_pcount_set(skb, 0);
1024+
1025+
*size = copy;
1026+
return skb;
1027+
}
1028+
9671029
ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
9681030
size_t size, int flags)
9691031
{
@@ -999,60 +1061,13 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
9991061
goto out_err;
10001062

10011063
while (size > 0) {
1002-
struct sk_buff *skb = tcp_write_queue_tail(sk);
1003-
int copy, i;
1004-
bool can_coalesce;
1005-
1006-
if (!skb || (copy = size_goal - skb->len) <= 0 ||
1007-
!tcp_skb_can_collapse_to(skb)) {
1008-
new_segment:
1009-
if (!sk_stream_memory_free(sk))
1010-
goto wait_for_space;
1011-
1012-
skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation,
1013-
tcp_rtx_and_write_queues_empty(sk));
1014-
if (!skb)
1015-
goto wait_for_space;
1016-
1017-
#ifdef CONFIG_TLS_DEVICE
1018-
skb->decrypted = !!(flags & MSG_SENDPAGE_DECRYPTED);
1019-
#endif
1020-
skb_entail(sk, skb);
1021-
copy = size_goal;
1022-
}
1064+
struct sk_buff *skb;
1065+
size_t copy = size;
10231066

1024-
if (copy > size)
1025-
copy = size;
1026-
1027-
i = skb_shinfo(skb)->nr_frags;
1028-
can_coalesce = skb_can_coalesce(skb, i, page, offset);
1029-
if (!can_coalesce && i >= sysctl_max_skb_frags) {
1030-
tcp_mark_push(tp, skb);
1031-
goto new_segment;
1032-
}
1033-
if (!sk_wmem_schedule(sk, copy))
1067+
skb = tcp_build_frag(sk, size_goal, flags, page, offset, &copy);
1068+
if (!skb)
10341069
goto wait_for_space;
10351070

1036-
if (can_coalesce) {
1037-
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
1038-
} else {
1039-
get_page(page);
1040-
skb_fill_page_desc(skb, i, page, offset, copy);
1041-
}
1042-
1043-
if (!(flags & MSG_NO_SHARED_FRAGS))
1044-
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
1045-
1046-
skb->len += copy;
1047-
skb->data_len += copy;
1048-
skb->truesize += copy;
1049-
sk_wmem_queued_add(sk, copy);
1050-
sk_mem_charge(sk, copy);
1051-
skb->ip_summed = CHECKSUM_PARTIAL;
1052-
WRITE_ONCE(tp->write_seq, tp->write_seq + copy);
1053-
TCP_SKB_CB(skb)->end_seq += copy;
1054-
tcp_skb_pcount_set(skb, 0);
1055-
10561071
if (!copied)
10571072
TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH;
10581073

0 commit comments

Comments
 (0)