nfs: use time64_t internally
authorArnd Bergmann <arnd@arndb.de>
Fri, 20 Oct 2017 14:34:42 +0000 (16:34 +0200)
committerArnd Bergmann <arnd@arndb.de>
Wed, 18 Dec 2019 17:07:32 +0000 (18:07 +0100)
The timestamps for the cache are all in boottime seconds, so they
don't overflow 32-bit values, but the use of time_t is deprecated
because it generally does overflow when used with wall-clock time.

There are multiple possible ways of avoiding it:

- leave time_t, which is safe here, but forces others to
  look into this code to determine that it is over and over.

- use a more generic type, like 'int' or 'long', which is known
  to be sufficient here but loses the documentation of referring
  to timestamps

- use ktime_t everywhere, and convert into seconds in the few
  places where we want realtime-seconds. The conversion is
  sometimes expensive, but not more so than the conversion we
  do today.

- use time64_t to clarify that this code is safe. Nothing would
  change for 64-bit architectures, but it is slightly less
  efficient on 32-bit architectures.

Without a clear winner of the three approaches above, this picks
the last one, favouring readability over a small performance
loss on 32-bit architectures.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
include/linux/sunrpc/cache.h
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/svcauth_unix.c

index f860372..0f64de7 100644 (file)
@@ -45,8 +45,8 @@
  */
 struct cache_head {
        struct hlist_node       cache_list;
-       time_t          expiry_time;    /* After time time, don't use the data */
-       time_t          last_refresh;   /* If CACHE_PENDING, this is when upcall was
+       time64_t        expiry_time;    /* After time time, don't use the data */
+       time64_t        last_refresh;   /* If CACHE_PENDING, this is when upcall was
                                         * sent, else this is when update was
                                         * received, though it is alway set to
                                         * be *after* ->flush_time.
@@ -95,22 +95,22 @@ struct cache_detail {
        /* fields below this comment are for internal use
         * and should not be touched by cache owners
         */
-       time_t                  flush_time;             /* flush all cache items with
+       time64_t                flush_time;             /* flush all cache items with
                                                         * last_refresh at or earlier
                                                         * than this.  last_refresh
                                                         * is never set at or earlier
                                                         * than this.
                                                         */
        struct list_head        others;
-       time_t                  nextcheck;
+       time64_t                nextcheck;
        int                     entries;
 
        /* fields for communication over channel */
        struct list_head        queue;
 
        atomic_t                writers;                /* how many time is /channel open */
-       time_t                  last_close;             /* if no writers, when did last close */
-       time_t                  last_warn;              /* when we last warned about no writers */
+       time64_t                last_close;             /* if no writers, when did last close */
+       time64_t                last_warn;              /* when we last warned about no writers */
 
        union {
                struct proc_dir_entry   *procfs;
@@ -147,18 +147,22 @@ struct cache_deferred_req {
  * timestamps kept in the cache are expressed in seconds
  * since boot.  This is the best for measuring differences in
  * real time.
+ * This reimplemnts ktime_get_boottime_seconds() in a slightly
+ * faster but less accurate way. When we end up converting
+ * back to wallclock (CLOCK_REALTIME), that error often
+ * cancels out during the reverse operation.
  */
-static inline time_t seconds_since_boot(void)
+static inline time64_t seconds_since_boot(void)
 {
-       struct timespec boot;
-       getboottime(&boot);
-       return get_seconds() - boot.tv_sec;
+       struct timespec64 boot;
+       getboottime64(&boot);
+       return ktime_get_real_seconds() - boot.tv_sec;
 }
 
-static inline time_t convert_to_wallclock(time_t sinceboot)
+static inline time64_t convert_to_wallclock(time64_t sinceboot)
 {
-       struct timespec boot;
-       getboottime(&boot);
+       struct timespec64 boot;
+       getboottime64(&boot);
        return boot.tv_sec + sinceboot;
 }
 
@@ -273,7 +277,7 @@ static inline int get_uint(char **bpp, unsigned int *anint)
        return 0;
 }
 
-static inline int get_time(char **bpp, time_t *time)
+static inline int get_time(char **bpp, time64_t *time)
 {
        char buf[50];
        long long ll;
@@ -287,20 +291,20 @@ static inline int get_time(char **bpp, time_t *time)
        if (kstrtoll(buf, 0, &ll))
                return -EINVAL;
 
-       *time = (time_t)ll;
+       *time = ll;
        return 0;
 }
 
-static inline time_t get_expiry(char **bpp)
+static inline time64_t get_expiry(char **bpp)
 {
-       time_t rv;
-       struct timespec boot;
+       time64_t rv;
+       struct timespec64 boot;
 
        if (get_time(bpp, &rv))
                return 0;
        if (rv < 0)
                return 0;
-       getboottime(&boot);
+       getboottime64(&boot);
        return rv - boot.tv_sec;
 }
 
index 0c3e228..3111817 100644 (file)
@@ -203,7 +203,7 @@ static int rsi_parse(struct cache_detail *cd,
        char *ep;
        int len;
        struct rsi rsii, *rsip = NULL;
-       time_t expiry;
+       time64_t expiry;
        int status = -EINVAL;
 
        memset(&rsii, 0, sizeof(rsii));
index f740cb5..d996bf8 100644 (file)
@@ -42,7 +42,7 @@ static bool cache_listeners_exist(struct cache_detail *detail);
 
 static void cache_init(struct cache_head *h, struct cache_detail *detail)
 {
-       time_t now = seconds_since_boot();
+       time64_t now = seconds_since_boot();
        INIT_HLIST_NODE(&h->cache_list);
        h->flags = 0;
        kref_init(&h->ref);
@@ -139,10 +139,10 @@ EXPORT_SYMBOL_GPL(sunrpc_cache_lookup_rcu);
 
 static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
 
-static void cache_fresh_locked(struct cache_head *head, time_t expiry,
+static void cache_fresh_locked(struct cache_head *head, time64_t expiry,
                               struct cache_detail *detail)
 {
-       time_t now = seconds_since_boot();
+       time64_t now = seconds_since_boot();
        if (now <= detail->flush_time)
                /* ensure it isn't immediately treated as expired */
                now = detail->flush_time + 1;
@@ -274,7 +274,7 @@ int cache_check(struct cache_detail *detail,
                    struct cache_head *h, struct cache_req *rqstp)
 {
        int rv;
-       long refresh_age, age;
+       time64_t refresh_age, age;
 
        /* First decide return status as best we can */
        rv = cache_is_valid(h);
@@ -288,7 +288,7 @@ int cache_check(struct cache_detail *detail,
                        rv = -ENOENT;
        } else if (rv == -EAGAIN ||
                   (h->expiry_time != 0 && age > refresh_age/2)) {
-               dprintk("RPC:       Want update, refage=%ld, age=%ld\n",
+               dprintk("RPC:       Want update, refage=%lld, age=%lld\n",
                                refresh_age, age);
                if (!test_and_set_bit(CACHE_PENDING, &h->flags)) {
                        switch (cache_make_upcall(detail, h)) {
@@ -1404,7 +1404,7 @@ static int c_show(struct seq_file *m, void *p)
                return cd->cache_show(m, cd, NULL);
 
        ifdebug(CACHE)
-               seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n",
+               seq_printf(m, "# expiry=%lld refcnt=%d flags=%lx\n",
                           convert_to_wallclock(cp->expiry_time),
                           kref_read(&cp->ref), cp->flags);
        cache_get(cp);
@@ -1477,7 +1477,7 @@ static ssize_t read_flush(struct file *file, char __user *buf,
        char tbuf[22];
        size_t len;
 
-       len = snprintf(tbuf, sizeof(tbuf), "%lu\n",
+       len = snprintf(tbuf, sizeof(tbuf), "%llu\n",
                        convert_to_wallclock(cd->flush_time));
        return simple_read_from_buffer(buf, count, ppos, tbuf, len);
 }
@@ -1488,7 +1488,7 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
 {
        char tbuf[20];
        char *ep;
-       time_t now;
+       time64_t now;
 
        if (*ppos || count > sizeof(tbuf)-1)
                return -EINVAL;
index 5c04ba7..04aa80a 100644 (file)
@@ -166,7 +166,7 @@ static void ip_map_request(struct cache_detail *cd,
 }
 
 static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr);
-static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
+static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time64_t expiry);
 
 static int ip_map_parse(struct cache_detail *cd,
                          char *mesg, int mlen)
@@ -187,7 +187,7 @@ static int ip_map_parse(struct cache_detail *cd,
 
        struct ip_map *ipmp;
        struct auth_domain *dom;
-       time_t expiry;
+       time64_t expiry;
 
        if (mesg[mlen-1] != '\n')
                return -EINVAL;
@@ -308,7 +308,7 @@ static inline struct ip_map *ip_map_lookup(struct net *net, char *class,
 }
 
 static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
-               struct unix_domain *udom, time_t expiry)
+               struct unix_domain *udom, time64_t expiry)
 {
        struct ip_map ip;
        struct cache_head *ch;
@@ -328,7 +328,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
 }
 
 static inline int ip_map_update(struct net *net, struct ip_map *ipm,
-               struct unix_domain *udom, time_t expiry)
+               struct unix_domain *udom, time64_t expiry)
 {
        struct sunrpc_net *sn;
 
@@ -491,7 +491,7 @@ static int unix_gid_parse(struct cache_detail *cd,
        int rv;
        int i;
        int err;
-       time_t expiry;
+       time64_t expiry;
        struct unix_gid ug, *ugp;
 
        if (mesg[mlen - 1] != '\n')