From f559935e7ce4e5d448bb6588f7fa82b0cc2cc2c0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 20 Oct 2017 16:34:42 +0200 Subject: nfs: use time64_t internally 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 --- include/linux/sunrpc/cache.h | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index f8603724fbee..0f64de7caa39 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -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; } -- cgit v1.2.3-59-g8ed1b