Commit 7c9c0ff6 authored by Andi Kleen's avatar Andi Kleen Committed by Stephen Hemminger

[NET]: Do lazy gettimeofday for network packets.

parent eccf6f14
......@@ -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
......
......@@ -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
*/
......
......@@ -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:
......
......@@ -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");
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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:
......
......@@ -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);
......
......@@ -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:
......
......@@ -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) {
......
......@@ -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:
......
......@@ -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:
......
......@@ -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:
......
......@@ -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:
......
......@@ -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:
......
......@@ -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 */
......
......@@ -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;
......
......@@ -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... */
......
......@@ -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:
......
......@@ -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:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment