From 7c9c0ff60eb9d4b0524f81ae15152f544439e360 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 15 Apr 2004 23:49:08 -0700 Subject: [PATCH] [NET]: Do lazy gettimeofday for network packets. --- include/net/neighbour.h | 2 ++ include/net/sock.h | 31 ++++++++++++++++++++++++---- net/appletalk/ddp.c | 8 +------- net/atm/ioctl.c | 8 ++------ net/ax25/af_ax25.c | 7 +------ net/core/dev.c | 8 ++++---- net/core/neighbour.c | 2 +- net/core/sock.c | 42 +++++++++++++++++++++++++++++++++++++- net/econet/af_econet.c | 6 ++---- net/ipv4/af_inet.c | 6 +----- net/ipv4/arp.c | 2 +- net/ipv6/af_inet6.c | 8 +------- net/ipv6/ndisc.c | 2 +- net/ipx/af_ipx.c | 14 ++++--------- net/irda/af_irda.c | 10 ++------- net/netrom/af_netrom.c | 14 ++++--------- net/packet/af_packet.c | 13 ++++++------ net/rose/af_rose.c | 8 ++------ net/rxrpc/transport.c | 5 +++++ net/sctp/input.c | 6 ++++++ net/sunrpc/svcsock.c | 6 ++++++ net/wanrouter/af_wanpipe.c | 8 +------- net/x25/af_x25.c | 10 +++------ 23 files changed, 124 insertions(+), 102 deletions(-) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 857f03acaffd1..464203b2abac8 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -281,6 +281,8 @@ __neigh_lookup_errno(struct neigh_table *tbl, const void *pkey, return neigh_create(tbl, pkey, dev); } +#define LOCALLY_ENQUEUED -2 + #endif #endif diff --git a/include/net/sock.h b/include/net/sock.h index bc35b54869998..3fd86b12eb3e8 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -382,6 +382,7 @@ enum sock_flags { SOCK_LINGER, SOCK_DESTROY, SOCK_BROADCAST, + SOCK_TIMESTAMP, }; static inline void sock_set_flag(struct sock *sk, enum sock_flags flag) @@ -1023,12 +1024,34 @@ static inline int sock_intr_errno(long timeo) static __inline__ void sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) { - if (sk->sk_rcvtstamp) - put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP, sizeof(skb->stamp), &skb->stamp); - else - sk->sk_stamp = skb->stamp; + struct timeval *stamp = &skb->stamp; + if (sk->sk_rcvtstamp) { + /* Race occurred between timestamp enabling and packet + receiving. Fill in the current time for now. */ + if (stamp->tv_sec == 0) + do_gettimeofday(stamp); + put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP, sizeof(struct timeval), + stamp); + } else + sk->sk_stamp = *stamp; } +extern atomic_t netstamp_needed; +extern void sock_enable_timestamp(struct sock *sk); +extern void sock_disable_timestamp(struct sock *sk); + +static inline void net_timestamp(struct timeval *stamp) +{ + if (atomic_read(&netstamp_needed)) + do_gettimeofday(stamp); + else { + stamp->tv_sec = 0; + stamp->tv_usec = 0; + } +} + +extern int sock_get_timestamp(struct sock *, struct timeval *); + /* * Enable debug/info messages */ diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 75f0da4afb51c..af571e3e31979 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1795,13 +1795,7 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; } case SIOCGSTAMP: - if (!sk) - break; - rc = -ENOENT; - if (!sk->sk_stamp.tv_sec) - break; - rc = copy_to_user((void *)arg, &sk->sk_stamp, - sizeof(struct timeval)) ? -EFAULT : 0; + rc = sock_get_timestamp(sk, (struct timeval *)arg); break; /* Routing */ case SIOCADDRT: diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index a1a7811a9001c..b8133d17d1d44 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c @@ -76,12 +76,8 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) goto done; } case SIOCGSTAMP: /* borrowed from IP */ - if (!vcc->sk->sk_stamp.tv_sec) { - error = -ENOENT; - goto done; - } - error = copy_to_user((void *)arg, &vcc->sk->sk_stamp, - sizeof(struct timeval)) ? -EFAULT : 0; + error = sock_get_timestamp(vcc->sk, (struct timeval *) + arg); goto done; case ATM_SETSC: printk(KERN_WARNING "ATM_SETSC is obsolete\n"); diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 671c355910750..75ab89d5cb1e3 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1694,12 +1694,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCGSTAMP: if (sk != NULL) { - if (!sk->sk_stamp.tv_sec) { - res = -ENOENT; - break; - } - res = copy_to_user((void *)arg, &sk->sk_stamp, - sizeof(struct timeval)) ? -EFAULT : 0; + res = sock_get_timestamp(sk, (struct timeval *)arg); break; } res = -EINVAL; diff --git a/net/core/dev.c b/net/core/dev.c index e5a87037af19b..ff9defc681d77 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1125,7 +1125,7 @@ int call_netdevice_notifiers(unsigned long val, void *v) void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) { struct packet_type *ptype; - do_gettimeofday(&skb->stamp); + net_timestamp(&skb->stamp); rcu_read_lock(); list_for_each_entry_rcu(ptype, &ptype_all, list) { @@ -1546,9 +1546,9 @@ int netif_rx(struct sk_buff *skb) return NET_RX_DROP; } #endif - + if (!skb->stamp.tv_sec) - do_gettimeofday(&skb->stamp); + net_timestamp(&skb->stamp); /* * The code is rearranged so that the path is the most @@ -1710,7 +1710,7 @@ int netif_receive_skb(struct sk_buff *skb) #endif if (!skb->stamp.tv_sec) - do_gettimeofday(&skb->stamp); + net_timestamp(&skb->stamp); skb_bond(skb); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 0c90774fd5021..c5b4cddcd2eaf 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1094,7 +1094,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, kfree_skb(skb); return; } - skb->stamp.tv_sec = 0; + skb->stamp.tv_sec = LOCALLY_ENQUEUED; skb->stamp.tv_usec = now + sched_next; spin_lock(&tbl->proxy_queue.lock); diff --git a/net/core/sock.c b/net/core/sock.c index 4076080ca4b67..97e3ebea52228 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -328,6 +328,8 @@ int sock_setsockopt(struct socket *sock, int level, int optname, case SO_TIMESTAMP: sk->sk_rcvtstamp = valbool; + if (valbool) + sock_enable_timestamp(sk); break; case SO_RCVLOWAT: @@ -642,6 +644,8 @@ void sk_free(struct sock *sk) sk->sk_filter = NULL; } + sock_disable_timestamp(sk); + if (atomic_read(&sk->sk_omem_alloc)) printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n", __FUNCTION__, atomic_read(&sk->sk_omem_alloc)); @@ -1135,6 +1139,9 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; sk->sk_owner = NULL; + sk->sk_stamp.tv_sec = -1L; + sk->sk_stamp.tv_usec = -1L; + atomic_set(&sk->sk_refcnt, 1); } @@ -1160,9 +1167,42 @@ void fastcall release_sock(struct sock *sk) wake_up(&(sk->sk_lock.wq)); spin_unlock_bh(&(sk->sk_lock.slock)); } - EXPORT_SYMBOL(release_sock); +/* When > 0 there are consumers of rx skb time stamps */ +atomic_t netstamp_needed = ATOMIC_INIT(0); + +int sock_get_timestamp(struct sock *sk, struct timeval *userstamp) +{ + if (!sock_flag(sk, SOCK_TIMESTAMP)) + sock_enable_timestamp(sk); + if (sk->sk_stamp.tv_sec == -1) + return -ENOENT; + if (sk->sk_stamp.tv_sec == 0) + do_gettimeofday(&sk->sk_stamp); + return copy_to_user(userstamp, &sk->sk_stamp, sizeof(struct timeval)) ? + -EFAULT : 0; +} +EXPORT_SYMBOL(sock_get_timestamp); + +void sock_enable_timestamp(struct sock *sk) +{ + if (!sock_flag(sk, SOCK_TIMESTAMP)) { + sock_set_flag(sk, SOCK_TIMESTAMP); + atomic_inc(&netstamp_needed); + } +} +EXPORT_SYMBOL(sock_enable_timestamp); + +void sock_disable_timestamp(struct sock *sk) +{ + if (sock_flag(sk, SOCK_TIMESTAMP)) { + sock_reset_flag(sk, SOCK_TIMESTAMP); + atomic_dec(&netstamp_needed); + } +} +EXPORT_SYMBOL(sock_disable_timestamp); + EXPORT_SYMBOL(__lock_sock); EXPORT_SYMBOL(__release_sock); EXPORT_SYMBOL(sk_alloc); diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index fa876ce6cc55c..ddd470edb9c91 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -665,10 +665,8 @@ static int econet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg switch(cmd) { case SIOCGSTAMP: - if (!sk->sk_stamp.tv_sec) - return -ENOENT; - return copy_to_user((void *)arg, &sk->sk_stamp, - sizeof(struct timeval)) ? -EFAULT : 0; + return sock_get_timestamp(sk,(struct timeval *)arg); + case SIOCSIFADDR: case SIOCGIFADDR: return ec_dev_ioctl(sock, cmd, (void *)arg); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 600b45000e5f8..edf4570901780 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -843,11 +843,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) switch (cmd) { case SIOCGSTAMP: - if (!sk->sk_stamp.tv_sec) - err = -ENOENT; - else if (copy_to_user((void *)arg, &sk->sk_stamp, - sizeof(struct timeval))) - err = -EFAULT; + err = sock_get_timestamp(sk, (struct timeval *)arg); break; case SIOCADDRT: case SIOCDELRT: diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 2520e7889bbf8..ec25d9b9da2cf 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -860,7 +860,7 @@ int arp_process(struct sk_buff *skb) if (n) neigh_release(n); - if (skb->stamp.tv_sec == 0 || + if (skb->stamp.tv_sec == LOCALLY_ENQUEUED || skb->pkt_type == PACKET_HOST || in_dev->arp_parms->proxy_delay == 0) { arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index a6afc2f79654c..eba2cec0d81ad 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -474,13 +474,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) switch(cmd) { case SIOCGSTAMP: - if (!sk->sk_stamp.tv_sec) - return -ENOENT; - err = copy_to_user((void *)arg, &sk->sk_stamp, - sizeof(struct timeval)); - if (err) - return -EFAULT; - return 0; + return sock_get_timestamp(sk, (struct timeval *)arg); case SIOCADDRT: case SIOCDELRT: diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index bef43cda8d10a..b12511a138beb 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -764,7 +764,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) if (ipv6_chk_acast_addr(dev, &msg->target) || (idev->cnf.forwarding && pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) { - if (skb->stamp.tv_sec != 0 && + if (skb->stamp.tv_sec != LOCALLY_ENQUEUED && skb->pkt_type != PACKET_HOST && inc != 0 && idev->nd_parms->proxy_delay != 0) { diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 2e231e0371e63..85cb6a1c39a12 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1797,7 +1797,8 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock, copied); if (rc) goto out_free; - sk->sk_stamp = skb->stamp; + if (skb->stamp.tv_sec) + sk->sk_stamp = skb->stamp; msg->msg_namelen = sizeof(*sipx); @@ -1870,15 +1871,8 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; case SIOCGSTAMP: rc = -EINVAL; - if (sk) { - rc = -ENOENT; - if (!sk->sk_stamp.tv_sec) - break; - rc = -EFAULT; - if (!copy_to_user((void *)arg, &sk->sk_stamp, - sizeof(struct timeval))) - rc = 0; - } + if (sk) + rc = sock_get_timestamp(sk, (struct timeval *)arg); break; case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 8755709686a18..9e56f712e45db 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -1796,14 +1796,8 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } case SIOCGSTAMP: - if (sk != NULL) { - if (!sk->sk_stamp.tv_sec) - return -ENOENT; - if (copy_to_user((void *)arg, &sk->sk_stamp, - sizeof(struct timeval))) - return -EFAULT; - return 0; - } + if (sk != NULL) + return sock_get_timestamp(sk, (struct timeval *)arg); return -EINVAL; case SIOCGIFADDR: diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index eb129999cdede..bb5ac58a66cf9 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -1200,17 +1200,11 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } case SIOCGSTAMP: - if (sk != NULL) { - if (!sk->sk_stamp.tv_sec) { - release_sock(sk); - return -ENOENT; - } - ret = copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0; - release_sock(sk); - return ret; - } + ret = -EINVAL; + if (sk != NULL) + ret = sock_get_timestamp(sk, (struct timeval *)arg); release_sock(sk); - return -EINVAL; + return ret; case SIOCGIFADDR: case SIOCSIFADDR: diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d298ed11a66a6..7ebb64d522820 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -625,6 +625,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct pack h->tp_snaplen = snaplen; h->tp_mac = macoff; h->tp_net = netoff; + if (skb->stamp.tv_sec == 0) { + do_gettimeofday(&skb->stamp); + sock_enable_timestamp(sk); + } h->tp_sec = skb->stamp.tv_sec; h->tp_usec = skb->stamp.tv_usec; @@ -1461,13 +1465,8 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, return put_user(amount, (int *)arg); } case SIOCGSTAMP: - if (!sk->sk_stamp.tv_sec) - return -ENOENT; - if (copy_to_user((void *)arg, &sk->sk_stamp, - sizeof(struct timeval))) - return -EFAULT; - break; - + return sock_get_timestamp(sk, (struct timeval *)arg); + #ifdef CONFIG_INET case SIOCADDRT: case SIOCDELRT: diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 89a7ef01bf210..aa770bce7cebf 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1269,12 +1269,8 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } case SIOCGSTAMP: - if (sk != NULL) { - if (!sk->sk_stamp.tv_sec) - return -ENOENT; - return copy_to_user((void *)arg, &sk->sk_stamp, - sizeof(struct timeval)) ? -EFAULT : 0; - } + if (sk != NULL) + return sock_get_timestamp(sk, (struct timeval *)arg); return -EINVAL; case SIOCGIFADDR: diff --git a/net/rxrpc/transport.c b/net/rxrpc/transport.c index 70002b501f878..f53284d8fdc4d 100644 --- a/net/rxrpc/transport.c +++ b/net/rxrpc/transport.c @@ -341,6 +341,11 @@ static int rxrpc_incoming_msg(struct rxrpc_transport *trans, msg->trans = trans; msg->state = RXRPC_MSG_RECEIVED; msg->stamp = pkt->stamp; + if (msg->stamp.tv_sec == 0) { + do_gettimeofday(&msg->stamp); + if (pkt->sk) + sock_enable_timestamp(pkt->sk); + } msg->seq = ntohl(msg->hdr.seq); /* attach the packet */ diff --git a/net/sctp/input.c b/net/sctp/input.c index 8392d7f83d614..d761fddb3bb96 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -175,6 +175,12 @@ int sctp_rcv(struct sk_buff *skb) rcvr = asoc ? &asoc->base : &ep->base; sk = rcvr->sk; + /* SCTP seems to always need a timestamp right now (FIXME) */ + if (skb->stamp.tv_sec == 0) { + do_gettimeofday(&skb->stamp); + sock_enable_timestamp(sk); + } + if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family)) goto discard_release; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 1633d5f13c4c8..8c39d85c51230 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -591,6 +591,12 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) /* possibly an icmp error */ dprintk("svc: recvfrom returned error %d\n", -err); } + if (skb->stamp.tv_sec == 0) { + skb->stamp.tv_sec = xtime.tv_sec; + skb->stamp.tv_usec = xtime.tv_nsec * 1000; + /* Don't enable netstamp, sunrpc doesn't + need that much accuracy */ + } svsk->sk_sk->sk_stamp = skb->stamp; set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */ diff --git a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c index 38b39aef46639..d4d13d430a881 100644 --- a/net/wanrouter/af_wanpipe.c +++ b/net/wanrouter/af_wanpipe.c @@ -1765,13 +1765,7 @@ static int wanpipe_ioctl(struct socket *sock, unsigned int cmd, unsigned long ar switch(cmd) { case SIOCGSTAMP: - if (!sk->sk_stamp.tv_sec) - return -ENOENT; - err = -EFAULT; - if (!copy_to_user((void *)arg, &sk->sk_stamp, - sizeof(struct timeval))) - err = 0; - return err; + return sock_get_timestamp(sk, (struct timeval *)arg); case SIOC_WANPIPE_CHECK_TX: diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 96608845e68c7..614f959b0f699 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1206,14 +1206,10 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } case SIOCGSTAMP: - if (sk) { - rc = -ENOENT; - if (!sk->sk_stamp.tv_sec) - break; - rc = copy_to_user((void *)arg, &sk->sk_stamp, - sizeof(struct timeval)) ? -EFAULT : 0; - } rc = -EINVAL; + if (sk) + rc = sock_get_timestamp(sk, + (struct timeval *)arg); break; case SIOCGIFADDR: case SIOCSIFADDR: -- 2.53.0