]> git.hungrycats.org Git - linux/commitdiff
[NET]: Do lazy gettimeofday for network packets.
authorAndi Kleen <ak@suse.de>
Fri, 16 Apr 2004 06:49:08 +0000 (23:49 -0700)
committerStephen Hemminger <shemminger@osdl.org>
Fri, 16 Apr 2004 06:49:08 +0000 (23:49 -0700)
23 files changed:
include/net/neighbour.h
include/net/sock.h
net/appletalk/ddp.c
net/atm/ioctl.c
net/ax25/af_ax25.c
net/core/dev.c
net/core/neighbour.c
net/core/sock.c
net/econet/af_econet.c
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv6/af_inet6.c
net/ipv6/ndisc.c
net/ipx/af_ipx.c
net/irda/af_irda.c
net/netrom/af_netrom.c
net/packet/af_packet.c
net/rose/af_rose.c
net/rxrpc/transport.c
net/sctp/input.c
net/sunrpc/svcsock.c
net/wanrouter/af_wanpipe.c
net/x25/af_x25.c

index 857f03acaffd1c0becf38e76c16505ac42af56f0..464203b2abac83a0883ba24addf4ddc44197a946 100644 (file)
@@ -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
 
index bc35b54869998599b8ea94f6354a306b12da1200..3fd86b12eb3e8080122482c26336e225e0e2b8c2 100644 (file)
@@ -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 
  */
index 75f0da4afb51cdd165ccaca98e051a8ffc11e78b..af571e3e319796a0b86e95f2ec0c1ff36c0616c1 100644 (file)
@@ -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:
index a1a7811a9001c7d6432831b7d679ff68d7c4a029..b8133d17d1d44e8fbb0820806a3af50f293eab1c 100644 (file)
@@ -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");
index 671c355910750c2b62b0cac115c0bd49718b4b80..75ab89d5cb1e360706382a6461df266ff205e62e 100644 (file)
@@ -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;
index e5a87037af19b398aecd0563be066544d92f208d..ff9defc681d77b67d1da71bd9730067fff5fb0dd 100644 (file)
@@ -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);
 
index 0c90774fd5021148f29b7c4cd7e2e4ad0713c753..c5b4cddcd2eafdbd6bc4ee20de99216cf0abd7a7 100644 (file)
@@ -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);
index 4076080ca4b67db5d5020ae77d9b2430d7dd2156..97e3ebea522280e0205ae8b0e9391d5a9a66cc5b 100644 (file)
@@ -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);
index fa876ce6cc55c627b4b1d8e30b49b64d5406e1c6..ddd470edb9c915426593731ab6a0ba5fff4485ac 100644 (file)
@@ -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);
index 600b45000e5f84ff3d149597e2a22461ad7b14fa..edf45709017806f8f847f652a15706eb2346d912 100644 (file)
@@ -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:
index 2520e7889bbf8c7f675b2ae9968d682036718d96..ec25d9b9da2cffad95b3f6e5bb4a139bbf50917e 100644 (file)
@@ -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);
index a6afc2f79654c5ad21d82259bfbd39c5f22c7623..eba2cec0d81ad55c52542d1a76651a1ae6f5958d 100644 (file)
@@ -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:
index bef43cda8d10a9a8dc8e8ccae5201e94b882d10a..b12511a138beb649b15d4d4232683d88be00c4a1 100644 (file)
@@ -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) {
index 2e231e0371e63119e265b43fe06daf0c7e0668c4..85cb6a1c39a1260c9550349813c60cb0be0c9275 100644 (file)
@@ -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:
index 8755709686a18beb68c17237f2362e16c6989609..9e56f712e45dbef9d7d15eb0219fe6e0b1be4ee7 100644 (file)
@@ -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:
index eb129999cdede610022cefc9e2a78758e24a4f2e..bb5ac58a66cf961658b2bcbf2fb2d4c770982209 100644 (file)
@@ -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:
index d298ed11a66a694022cae00a735492d701df7268..7ebb64d522820df855e5ec71685df0c0752e041c 100644 (file)
@@ -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:
index 89a7ef01bf2101f0671752180d247071b3376950..aa770bce7cebff06d2b16a8c7462d1f45c9e4386 100644 (file)
@@ -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:
index 70002b501f8788a75ee43fd252254be4836f7109..f53284d8fdc4d3879599ce1ebaee57aa32517703 100644 (file)
@@ -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 */
index 8392d7f83d614ce94b1982a3babbe44e925d978b..d761fddb3bb968385be68fccc796303bfbe9464d 100644 (file)
@@ -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;
 
index 1633d5f13c4c85007ea94cdef7e251c198d2ab3f..8c39d85c51230350c1147789be5b88ae8675ec29 100644 (file)
@@ -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... */
 
index 38b39aef466391ffec33ba5fdef821763481d12c..d4d13d430a88126f685f490601e6c0814227c806 100644 (file)
@@ -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:
 
index 96608845e68c782dd46da5b2528a175abb2c3641..614f959b0f699a3a13e6359b6c61eae264226514 100644 (file)
@@ -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: