@@ -1745,6 +1745,20 @@ int tcp_set_rcvlowat(struct sock *sk, int val)
17451745}
17461746EXPORT_SYMBOL (tcp_set_rcvlowat );
17471747
1748+ static void tcp_update_recv_tstamps (struct sk_buff * skb ,
1749+ struct scm_timestamping_internal * tss )
1750+ {
1751+ if (skb -> tstamp )
1752+ tss -> ts [0 ] = ktime_to_timespec64 (skb -> tstamp );
1753+ else
1754+ tss -> ts [0 ] = (struct timespec64 ) {0 };
1755+
1756+ if (skb_hwtstamps (skb )-> hwtstamp )
1757+ tss -> ts [2 ] = ktime_to_timespec64 (skb_hwtstamps (skb )-> hwtstamp );
1758+ else
1759+ tss -> ts [2 ] = (struct timespec64 ) {0 };
1760+ }
1761+
17481762#ifdef CONFIG_MMU
17491763static const struct vm_operations_struct tcp_vm_ops = {
17501764};
@@ -1848,13 +1862,13 @@ static int tcp_recvmsg_locked(struct sock *sk, struct msghdr *msg, size_t len,
18481862 struct scm_timestamping_internal * tss ,
18491863 int * cmsg_flags );
18501864static int receive_fallback_to_copy (struct sock * sk ,
1851- struct tcp_zerocopy_receive * zc , int inq )
1865+ struct tcp_zerocopy_receive * zc , int inq ,
1866+ struct scm_timestamping_internal * tss )
18521867{
18531868 unsigned long copy_address = (unsigned long )zc -> copybuf_address ;
1854- struct scm_timestamping_internal tss_unused ;
1855- int err , cmsg_flags_unused ;
18561869 struct msghdr msg = {};
18571870 struct iovec iov ;
1871+ int err ;
18581872
18591873 zc -> length = 0 ;
18601874 zc -> recv_skip_hint = 0 ;
@@ -1868,7 +1882,7 @@ static int receive_fallback_to_copy(struct sock *sk,
18681882 return err ;
18691883
18701884 err = tcp_recvmsg_locked (sk , & msg , inq , /*nonblock=*/ 1 , /*flags=*/ 0 ,
1871- & tss_unused , & cmsg_flags_unused );
1885+ tss , & zc -> msg_flags );
18721886 if (err < 0 )
18731887 return err ;
18741888
@@ -1909,21 +1923,27 @@ static int tcp_copy_straggler_data(struct tcp_zerocopy_receive *zc,
19091923 return (__s32 )copylen ;
19101924}
19111925
1912- static int tcp_zerocopy_handle_leftover_data (struct tcp_zerocopy_receive * zc ,
1913- struct sock * sk ,
1914- struct sk_buff * skb ,
1915- u32 * seq ,
1916- s32 copybuf_len )
1926+ static int tcp_zc_handle_leftover (struct tcp_zerocopy_receive * zc ,
1927+ struct sock * sk ,
1928+ struct sk_buff * skb ,
1929+ u32 * seq ,
1930+ s32 copybuf_len ,
1931+ struct scm_timestamping_internal * tss )
19171932{
19181933 u32 offset , copylen = min_t (u32 , copybuf_len , zc -> recv_skip_hint );
19191934
19201935 if (!copylen )
19211936 return 0 ;
19221937 /* skb is null if inq < PAGE_SIZE. */
1923- if (skb )
1938+ if (skb ) {
19241939 offset = * seq - TCP_SKB_CB (skb )-> seq ;
1925- else
1940+ } else {
19261941 skb = tcp_recv_skb (sk , * seq , & offset );
1942+ if (TCP_SKB_CB (skb )-> has_rxtstamp ) {
1943+ tcp_update_recv_tstamps (skb , tss );
1944+ zc -> msg_flags |= TCP_CMSG_TS ;
1945+ }
1946+ }
19271947
19281948 zc -> copybuf_len = tcp_copy_straggler_data (zc , skb , copylen , & offset ,
19291949 seq );
@@ -2010,9 +2030,37 @@ static int tcp_zerocopy_vm_insert_batch(struct vm_area_struct *vma,
20102030 err );
20112031}
20122032
2033+ static void tcp_recv_timestamp (struct msghdr * msg , const struct sock * sk ,
2034+ struct scm_timestamping_internal * tss );
2035+ static void tcp_zc_finalize_rx_tstamp (struct sock * sk ,
2036+ struct tcp_zerocopy_receive * zc ,
2037+ struct scm_timestamping_internal * tss )
2038+ {
2039+ unsigned long msg_control_addr ;
2040+ struct msghdr cmsg_dummy ;
2041+
2042+ msg_control_addr = (unsigned long )zc -> msg_control ;
2043+ cmsg_dummy .msg_control = (void * )msg_control_addr ;
2044+ cmsg_dummy .msg_controllen =
2045+ (__kernel_size_t )zc -> msg_controllen ;
2046+ cmsg_dummy .msg_flags = in_compat_syscall ()
2047+ ? MSG_CMSG_COMPAT : 0 ;
2048+ zc -> msg_flags = 0 ;
2049+ if (zc -> msg_control == msg_control_addr &&
2050+ zc -> msg_controllen == cmsg_dummy .msg_controllen ) {
2051+ tcp_recv_timestamp (& cmsg_dummy , sk , tss );
2052+ zc -> msg_control = (__u64 )
2053+ ((uintptr_t )cmsg_dummy .msg_control );
2054+ zc -> msg_controllen =
2055+ (__u64 )cmsg_dummy .msg_controllen ;
2056+ zc -> msg_flags = (__u32 )cmsg_dummy .msg_flags ;
2057+ }
2058+ }
2059+
20132060#define TCP_ZEROCOPY_PAGE_BATCH_SIZE 32
20142061static int tcp_zerocopy_receive (struct sock * sk ,
2015- struct tcp_zerocopy_receive * zc )
2062+ struct tcp_zerocopy_receive * zc ,
2063+ struct scm_timestamping_internal * tss )
20162064{
20172065 u32 length = 0 , offset , vma_len , avail_len , copylen = 0 ;
20182066 unsigned long address = (unsigned long )zc -> address ;
@@ -2029,6 +2077,7 @@ static int tcp_zerocopy_receive(struct sock *sk,
20292077 int ret ;
20302078
20312079 zc -> copybuf_len = 0 ;
2080+ zc -> msg_flags = 0 ;
20322081
20332082 if (address & (PAGE_SIZE - 1 ) || address != zc -> address )
20342083 return - EINVAL ;
@@ -2039,7 +2088,7 @@ static int tcp_zerocopy_receive(struct sock *sk,
20392088 sock_rps_record_flow (sk );
20402089
20412090 if (inq && inq <= copybuf_len )
2042- return receive_fallback_to_copy (sk , zc , inq );
2091+ return receive_fallback_to_copy (sk , zc , inq , tss );
20432092
20442093 if (inq < PAGE_SIZE ) {
20452094 zc -> length = 0 ;
@@ -2084,6 +2133,11 @@ static int tcp_zerocopy_receive(struct sock *sk,
20842133 } else {
20852134 skb = tcp_recv_skb (sk , seq , & offset );
20862135 }
2136+
2137+ if (TCP_SKB_CB (skb )-> has_rxtstamp ) {
2138+ tcp_update_recv_tstamps (skb , tss );
2139+ zc -> msg_flags |= TCP_CMSG_TS ;
2140+ }
20872141 zc -> recv_skip_hint = skb -> len - offset ;
20882142 frags = skb_advance_to_frag (skb , offset , & offset_frag );
20892143 if (!frags || offset_frag )
@@ -2126,8 +2180,7 @@ static int tcp_zerocopy_receive(struct sock *sk,
21262180 mmap_read_unlock (current -> mm );
21272181 /* Try to copy straggler data. */
21282182 if (!ret )
2129- copylen = tcp_zerocopy_handle_leftover_data (zc , sk , skb , & seq ,
2130- copybuf_len );
2183+ copylen = tcp_zc_handle_leftover (zc , sk , skb , & seq , copybuf_len , tss );
21312184
21322185 if (length + copylen ) {
21332186 WRITE_ONCE (tp -> copied_seq , seq );
@@ -2148,20 +2201,6 @@ static int tcp_zerocopy_receive(struct sock *sk,
21482201}
21492202#endif
21502203
2151- static void tcp_update_recv_tstamps (struct sk_buff * skb ,
2152- struct scm_timestamping_internal * tss )
2153- {
2154- if (skb -> tstamp )
2155- tss -> ts [0 ] = ktime_to_timespec64 (skb -> tstamp );
2156- else
2157- tss -> ts [0 ] = (struct timespec64 ) {0 };
2158-
2159- if (skb_hwtstamps (skb )-> hwtstamp )
2160- tss -> ts [2 ] = ktime_to_timespec64 (skb_hwtstamps (skb )-> hwtstamp );
2161- else
2162- tss -> ts [2 ] = (struct timespec64 ) {0 };
2163- }
2164-
21652204/* Similar to __sock_recv_timestamp, but does not require an skb */
21662205static void tcp_recv_timestamp (struct msghdr * msg , const struct sock * sk ,
21672206 struct scm_timestamping_internal * tss )
@@ -4105,6 +4144,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
41054144 }
41064145#ifdef CONFIG_MMU
41074146 case TCP_ZEROCOPY_RECEIVE : {
4147+ struct scm_timestamping_internal tss ;
41084148 struct tcp_zerocopy_receive zc = {};
41094149 int err ;
41104150
@@ -4120,11 +4160,18 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
41204160 if (copy_from_user (& zc , optval , len ))
41214161 return - EFAULT ;
41224162 lock_sock (sk );
4123- err = tcp_zerocopy_receive (sk , & zc );
4163+ err = tcp_zerocopy_receive (sk , & zc , & tss );
41244164 release_sock (sk );
4125- if (len >= offsetofend (struct tcp_zerocopy_receive , err ))
4126- goto zerocopy_rcv_sk_err ;
4165+ if (len >= offsetofend (struct tcp_zerocopy_receive , msg_flags ))
4166+ goto zerocopy_rcv_cmsg ;
41274167 switch (len ) {
4168+ case offsetofend (struct tcp_zerocopy_receive , msg_flags ):
4169+ goto zerocopy_rcv_cmsg ;
4170+ case offsetofend (struct tcp_zerocopy_receive , msg_controllen ):
4171+ case offsetofend (struct tcp_zerocopy_receive , msg_control ):
4172+ case offsetofend (struct tcp_zerocopy_receive , flags ):
4173+ case offsetofend (struct tcp_zerocopy_receive , copybuf_len ):
4174+ case offsetofend (struct tcp_zerocopy_receive , copybuf_address ):
41284175 case offsetofend (struct tcp_zerocopy_receive , err ):
41294176 goto zerocopy_rcv_sk_err ;
41304177 case offsetofend (struct tcp_zerocopy_receive , inq ):
@@ -4133,6 +4180,11 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
41334180 default :
41344181 goto zerocopy_rcv_out ;
41354182 }
4183+ zerocopy_rcv_cmsg :
4184+ if (zc .msg_flags & TCP_CMSG_TS )
4185+ tcp_zc_finalize_rx_tstamp (sk , & zc , & tss );
4186+ else
4187+ zc .msg_flags = 0 ;
41364188zerocopy_rcv_sk_err :
41374189 if (!err )
41384190 zc .err = sock_error (sk );
0 commit comments