net: use ktime_t in struct scm_timestamping_internal

Instead of using struct timespec64 in scm_timestamping_internal,
use ktime_t, saving 24 bytes in kernel stack.

This makes tcp_update_recv_tstamps() small enough to be inlined.

The ktime_t -> timespec64 conversions happen after socket lock
has been released in tcp_recvmsg(), and only if the application
requested them.

$ scripts/bloat-o-meter -t vmlinux.0 vmlinux
add/remove: 0/2 grow/shrink: 5/4 up/down: 146/-277 (-131)
Function                                     old     new   delta
tcp_zerocopy_receive                        2383    2425     +42
mptcp_recvmsg                               1565    1607     +42
tcp_recvmsg_locked                          3797    3823     +26
put_cmsg_scm_timestamping64                  131     149     +18
put_cmsg_scm_timestamping                    131     149     +18
__pfx_tcp_update_recv_tstamps                 16       -     -16
do_tcp_getsockopt                           4024    4006     -18
tcp_recv_timestamp                           474     430     -44
tcp_zc_handle_leftover                       417     371     -46
__sock_recv_timestamp                       1087    1031     -56
tcp_update_recv_tstamps                       97       -     -97
Total: Before=25223788, After=25223657, chg -0.00%

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
Link: https://patch.msgid.link/20260304012747.881644-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Eric Dumazet 2026-03-04 01:27:47 +00:00 committed by Jakub Kicinski
parent 39ae83b0f5
commit c66e0f453d
5 changed files with 51 additions and 58 deletions

View File

@ -415,7 +415,7 @@ struct __kernel_timespec;
struct old_timespec32; struct old_timespec32;
struct scm_timestamping_internal { struct scm_timestamping_internal {
struct timespec64 ts[3]; ktime_t ts[3];
}; };
extern void put_cmsg_scm_timestamping64(struct msghdr *msg, struct scm_timestamping_internal *tss); extern void put_cmsg_scm_timestamping64(struct msghdr *msg, struct scm_timestamping_internal *tss);

View File

@ -503,8 +503,15 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
int flags); int flags);
int tcp_set_rcvlowat(struct sock *sk, int val); int tcp_set_rcvlowat(struct sock *sk, int val);
int tcp_set_window_clamp(struct sock *sk, int val); int tcp_set_window_clamp(struct sock *sk, int val);
void tcp_update_recv_tstamps(struct sk_buff *skb,
struct scm_timestamping_internal *tss); static inline void
tcp_update_recv_tstamps(struct sk_buff *skb,
struct scm_timestamping_internal *tss)
{
tss->ts[0] = skb->tstamp;
tss->ts[2] = skb_hwtstamps(skb)->hwtstamp;
}
void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk, void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
struct scm_timestamping_internal *tss); struct scm_timestamping_internal *tss);
void tcp_data_ready(struct sock *sk); void tcp_data_ready(struct sock *sk);

View File

@ -318,8 +318,10 @@ void put_cmsg_scm_timestamping64(struct msghdr *msg, struct scm_timestamping_int
int i; int i;
for (i = 0; i < ARRAY_SIZE(tss.ts); i++) { for (i = 0; i < ARRAY_SIZE(tss.ts); i++) {
tss.ts[i].tv_sec = tss_internal->ts[i].tv_sec; struct timespec64 tv = ktime_to_timespec64(tss_internal->ts[i]);
tss.ts[i].tv_nsec = tss_internal->ts[i].tv_nsec;
tss.ts[i].tv_sec = tv.tv_sec;
tss.ts[i].tv_nsec = tv.tv_nsec;
} }
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_NEW, sizeof(tss), &tss); put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_NEW, sizeof(tss), &tss);
@ -332,8 +334,10 @@ void put_cmsg_scm_timestamping(struct msghdr *msg, struct scm_timestamping_inter
int i; int i;
for (i = 0; i < ARRAY_SIZE(tss.ts); i++) { for (i = 0; i < ARRAY_SIZE(tss.ts); i++) {
tss.ts[i].tv_sec = tss_internal->ts[i].tv_sec; struct timespec64 tv = ktime_to_timespec64(tss_internal->ts[i]);
tss.ts[i].tv_nsec = tss_internal->ts[i].tv_nsec;
tss.ts[i].tv_sec = tv.tv_sec;
tss.ts[i].tv_nsec = tv.tv_nsec;
} }
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_OLD, sizeof(tss), &tss); put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_OLD, sizeof(tss), &tss);

View File

@ -1871,20 +1871,6 @@ int tcp_set_rcvlowat(struct sock *sk, int val)
} }
EXPORT_IPV6_MOD(tcp_set_rcvlowat); EXPORT_IPV6_MOD(tcp_set_rcvlowat);
void tcp_update_recv_tstamps(struct sk_buff *skb,
struct scm_timestamping_internal *tss)
{
if (skb->tstamp)
tss->ts[0] = ktime_to_timespec64(skb->tstamp);
else
tss->ts[0] = (struct timespec64) {0};
if (skb_hwtstamps(skb)->hwtstamp)
tss->ts[2] = ktime_to_timespec64(skb_hwtstamps(skb)->hwtstamp);
else
tss->ts[2] = (struct timespec64) {0};
}
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
static const struct vm_operations_struct tcp_vm_ops = { static const struct vm_operations_struct tcp_vm_ops = {
}; };
@ -2376,22 +2362,23 @@ void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
{ {
int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW); int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
u32 tsflags = READ_ONCE(sk->sk_tsflags); u32 tsflags = READ_ONCE(sk->sk_tsflags);
bool has_timestamping = false;
if (tss->ts[0].tv_sec || tss->ts[0].tv_nsec) { if (tss->ts[0]) {
if (sock_flag(sk, SOCK_RCVTSTAMP)) { if (sock_flag(sk, SOCK_RCVTSTAMP)) {
struct timespec64 tv = ktime_to_timespec64(tss->ts[0]);
if (sock_flag(sk, SOCK_RCVTSTAMPNS)) { if (sock_flag(sk, SOCK_RCVTSTAMPNS)) {
if (new_tstamp) { if (new_tstamp) {
struct __kernel_timespec kts = { struct __kernel_timespec kts = {
.tv_sec = tss->ts[0].tv_sec, .tv_sec = tv.tv_sec,
.tv_nsec = tss->ts[0].tv_nsec, .tv_nsec = tv.tv_nsec,
}; };
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_NEW, put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_NEW,
sizeof(kts), &kts); sizeof(kts), &kts);
} else { } else {
struct __kernel_old_timespec ts_old = { struct __kernel_old_timespec ts_old = {
.tv_sec = tss->ts[0].tv_sec, .tv_sec = tv.tv_sec,
.tv_nsec = tss->ts[0].tv_nsec, .tv_nsec = tv.tv_nsec,
}; };
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD, put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD,
sizeof(ts_old), &ts_old); sizeof(ts_old), &ts_old);
@ -2399,41 +2386,37 @@ void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
} else { } else {
if (new_tstamp) { if (new_tstamp) {
struct __kernel_sock_timeval stv = { struct __kernel_sock_timeval stv = {
.tv_sec = tss->ts[0].tv_sec, .tv_sec = tv.tv_sec,
.tv_usec = tss->ts[0].tv_nsec / 1000, .tv_usec = tv.tv_nsec / 1000,
}; };
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_NEW, put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_NEW,
sizeof(stv), &stv); sizeof(stv), &stv);
} else { } else {
struct __kernel_old_timeval tv = { struct __kernel_old_timeval otv = {
.tv_sec = tss->ts[0].tv_sec, .tv_sec = tv.tv_sec,
.tv_usec = tss->ts[0].tv_nsec / 1000, .tv_usec = tv.tv_nsec / 1000,
}; };
put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD, put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD,
sizeof(tv), &tv); sizeof(otv), &otv);
} }
} }
} }
if (tsflags & SOF_TIMESTAMPING_SOFTWARE && if (!(tsflags & SOF_TIMESTAMPING_SOFTWARE &&
(tsflags & SOF_TIMESTAMPING_RX_SOFTWARE || (tsflags & SOF_TIMESTAMPING_RX_SOFTWARE ||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) !(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))))
has_timestamping = true; tss->ts[0] = 0;
else
tss->ts[0] = (struct timespec64) {0};
} }
if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) { if (tss->ts[2]) {
if (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE && if (!(tsflags & SOF_TIMESTAMPING_RAW_HARDWARE &&
(tsflags & SOF_TIMESTAMPING_RX_HARDWARE || (tsflags & SOF_TIMESTAMPING_RX_HARDWARE ||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) !(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))))
has_timestamping = true; tss->ts[2] = 0;
else
tss->ts[2] = (struct timespec64) {0};
} }
if (has_timestamping) { if (tss->ts[0] | tss->ts[2]) {
tss->ts[1] = (struct timespec64) {0}; tss->ts[1] = 0;
if (sock_flag(sk, SOCK_TSTAMP_NEW)) if (sock_flag(sk, SOCK_TSTAMP_NEW))
put_cmsg_scm_timestamping64(msg, tss); put_cmsg_scm_timestamping64(msg, tss);
else else

View File

@ -912,11 +912,10 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
{ {
int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW); int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
struct scm_timestamping_internal tss;
int empty = 1, false_tstamp = 0;
struct skb_shared_hwtstamps *shhwtstamps = struct skb_shared_hwtstamps *shhwtstamps =
skb_hwtstamps(skb); skb_hwtstamps(skb);
int if_index; struct scm_timestamping_internal tss;
int if_index, false_tstamp = 0;
ktime_t hwtstamp; ktime_t hwtstamp;
u32 tsflags; u32 tsflags;
@ -961,12 +960,12 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
memset(&tss, 0, sizeof(tss)); memset(&tss, 0, sizeof(tss));
tsflags = READ_ONCE(sk->sk_tsflags); tsflags = READ_ONCE(sk->sk_tsflags);
if ((tsflags & SOF_TIMESTAMPING_SOFTWARE && if (tsflags & SOF_TIMESTAMPING_SOFTWARE &&
(tsflags & SOF_TIMESTAMPING_RX_SOFTWARE || (tsflags & SOF_TIMESTAMPING_RX_SOFTWARE ||
skb_is_err_queue(skb) || skb_is_err_queue(skb) ||
!(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER))) && !(tsflags & SOF_TIMESTAMPING_OPT_RX_FILTER)))
ktime_to_timespec64_cond(skb->tstamp, tss.ts + 0)) tss.ts[0] = skb->tstamp;
empty = 0;
if (shhwtstamps && if (shhwtstamps &&
(tsflags & SOF_TIMESTAMPING_RAW_HARDWARE && (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE &&
(tsflags & SOF_TIMESTAMPING_RX_HARDWARE || (tsflags & SOF_TIMESTAMPING_RX_HARDWARE ||
@ -983,15 +982,15 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
hwtstamp = ptp_convert_timestamp(&hwtstamp, hwtstamp = ptp_convert_timestamp(&hwtstamp,
READ_ONCE(sk->sk_bind_phc)); READ_ONCE(sk->sk_bind_phc));
if (ktime_to_timespec64_cond(hwtstamp, tss.ts + 2)) { if (hwtstamp) {
empty = 0; tss.ts[2] = hwtstamp;
if ((tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) && if ((tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) &&
!skb_is_err_queue(skb)) !skb_is_err_queue(skb))
put_ts_pktinfo(msg, skb, if_index); put_ts_pktinfo(msg, skb, if_index);
} }
} }
if (!empty) { if (tss.ts[0] | tss.ts[2]) {
if (sock_flag(sk, SOCK_TSTAMP_NEW)) if (sock_flag(sk, SOCK_TSTAMP_NEW))
put_cmsg_scm_timestamping64(msg, &tss); put_cmsg_scm_timestamping64(msg, &tss);
else else