@@ -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+
9671029ssize_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