Commit f559935e authored by Arnd Bergmann's avatar Arnd Bergmann

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: default avatarArnd Bergmann <arnd@arndb.de>
parent 294ec5b8
...@@ -45,8 +45,8 @@ ...@@ -45,8 +45,8 @@
*/ */
struct cache_head { struct cache_head {
struct hlist_node cache_list; struct hlist_node cache_list;
time_t expiry_time; /* After time time, don't use the data */ time64_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 last_refresh; /* If CACHE_PENDING, this is when upcall was
* sent, else this is when update was * sent, else this is when update was
* received, though it is alway set to * received, though it is alway set to
* be *after* ->flush_time. * be *after* ->flush_time.
...@@ -95,22 +95,22 @@ struct cache_detail { ...@@ -95,22 +95,22 @@ struct cache_detail {
/* fields below this comment are for internal use /* fields below this comment are for internal use
* and should not be touched by cache owners * 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 * last_refresh at or earlier
* than this. last_refresh * than this. last_refresh
* is never set at or earlier * is never set at or earlier
* than this. * than this.
*/ */
struct list_head others; struct list_head others;
time_t nextcheck; time64_t nextcheck;
int entries; int entries;
/* fields for communication over channel */ /* fields for communication over channel */
struct list_head queue; struct list_head queue;
atomic_t writers; /* how many time is /channel open */ atomic_t writers; /* how many time is /channel open */
time_t last_close; /* if no writers, when did last close */ time64_t last_close; /* if no writers, when did last close */
time_t last_warn; /* when we last warned about no writers */ time64_t last_warn; /* when we last warned about no writers */
union { union {
struct proc_dir_entry *procfs; struct proc_dir_entry *procfs;
...@@ -147,18 +147,22 @@ struct cache_deferred_req { ...@@ -147,18 +147,22 @@ struct cache_deferred_req {
* timestamps kept in the cache are expressed in seconds * timestamps kept in the cache are expressed in seconds
* since boot. This is the best for measuring differences in * since boot. This is the best for measuring differences in
* real time. * 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; struct timespec64 boot;
getboottime(&boot); getboottime64(&boot);
return get_seconds() - boot.tv_sec; 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; struct timespec64 boot;
getboottime(&boot); getboottime64(&boot);
return boot.tv_sec + sinceboot; return boot.tv_sec + sinceboot;
} }
...@@ -273,7 +277,7 @@ static inline int get_uint(char **bpp, unsigned int *anint) ...@@ -273,7 +277,7 @@ static inline int get_uint(char **bpp, unsigned int *anint)
return 0; 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]; char buf[50];
long long ll; long long ll;
...@@ -287,20 +291,20 @@ static inline int get_time(char **bpp, time_t *time) ...@@ -287,20 +291,20 @@ static inline int get_time(char **bpp, time_t *time)
if (kstrtoll(buf, 0, &ll)) if (kstrtoll(buf, 0, &ll))
return -EINVAL; return -EINVAL;
*time = (time_t)ll; *time = ll;
return 0; return 0;
} }
static inline time_t get_expiry(char **bpp) static inline time64_t get_expiry(char **bpp)
{ {
time_t rv; time64_t rv;
struct timespec boot; struct timespec64 boot;
if (get_time(bpp, &rv)) if (get_time(bpp, &rv))
return 0; return 0;
if (rv < 0) if (rv < 0)
return 0; return 0;
getboottime(&boot); getboottime64(&boot);
return rv - boot.tv_sec; return rv - boot.tv_sec;
} }
......
...@@ -203,7 +203,7 @@ static int rsi_parse(struct cache_detail *cd, ...@@ -203,7 +203,7 @@ static int rsi_parse(struct cache_detail *cd,
char *ep; char *ep;
int len; int len;
struct rsi rsii, *rsip = NULL; struct rsi rsii, *rsip = NULL;
time_t expiry; time64_t expiry;
int status = -EINVAL; int status = -EINVAL;
memset(&rsii, 0, sizeof(rsii)); memset(&rsii, 0, sizeof(rsii));
......
...@@ -42,7 +42,7 @@ static bool cache_listeners_exist(struct cache_detail *detail); ...@@ -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) 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); INIT_HLIST_NODE(&h->cache_list);
h->flags = 0; h->flags = 0;
kref_init(&h->ref); kref_init(&h->ref);
...@@ -139,10 +139,10 @@ EXPORT_SYMBOL_GPL(sunrpc_cache_lookup_rcu); ...@@ -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_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) struct cache_detail *detail)
{ {
time_t now = seconds_since_boot(); time64_t now = seconds_since_boot();
if (now <= detail->flush_time) if (now <= detail->flush_time)
/* ensure it isn't immediately treated as expired */ /* ensure it isn't immediately treated as expired */
now = detail->flush_time + 1; now = detail->flush_time + 1;
...@@ -274,7 +274,7 @@ int cache_check(struct cache_detail *detail, ...@@ -274,7 +274,7 @@ int cache_check(struct cache_detail *detail,
struct cache_head *h, struct cache_req *rqstp) struct cache_head *h, struct cache_req *rqstp)
{ {
int rv; int rv;
long refresh_age, age; time64_t refresh_age, age;
/* First decide return status as best we can */ /* First decide return status as best we can */
rv = cache_is_valid(h); rv = cache_is_valid(h);
...@@ -288,7 +288,7 @@ int cache_check(struct cache_detail *detail, ...@@ -288,7 +288,7 @@ int cache_check(struct cache_detail *detail,
rv = -ENOENT; rv = -ENOENT;
} else if (rv == -EAGAIN || } else if (rv == -EAGAIN ||
(h->expiry_time != 0 && age > refresh_age/2)) { (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); refresh_age, age);
if (!test_and_set_bit(CACHE_PENDING, &h->flags)) { if (!test_and_set_bit(CACHE_PENDING, &h->flags)) {
switch (cache_make_upcall(detail, h)) { switch (cache_make_upcall(detail, h)) {
...@@ -1404,7 +1404,7 @@ static int c_show(struct seq_file *m, void *p) ...@@ -1404,7 +1404,7 @@ static int c_show(struct seq_file *m, void *p)
return cd->cache_show(m, cd, NULL); return cd->cache_show(m, cd, NULL);
ifdebug(CACHE) 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), convert_to_wallclock(cp->expiry_time),
kref_read(&cp->ref), cp->flags); kref_read(&cp->ref), cp->flags);
cache_get(cp); cache_get(cp);
...@@ -1477,7 +1477,7 @@ static ssize_t read_flush(struct file *file, char __user *buf, ...@@ -1477,7 +1477,7 @@ static ssize_t read_flush(struct file *file, char __user *buf,
char tbuf[22]; char tbuf[22];
size_t len; size_t len;
len = snprintf(tbuf, sizeof(tbuf), "%lu\n", len = snprintf(tbuf, sizeof(tbuf), "%llu\n",
convert_to_wallclock(cd->flush_time)); convert_to_wallclock(cd->flush_time));
return simple_read_from_buffer(buf, count, ppos, tbuf, len); 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, ...@@ -1488,7 +1488,7 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
{ {
char tbuf[20]; char tbuf[20];
char *ep; char *ep;
time_t now; time64_t now;
if (*ppos || count > sizeof(tbuf)-1) if (*ppos || count > sizeof(tbuf)-1)
return -EINVAL; return -EINVAL;
......
...@@ -166,7 +166,7 @@ static void ip_map_request(struct cache_detail *cd, ...@@ -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 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, static int ip_map_parse(struct cache_detail *cd,
char *mesg, int mlen) char *mesg, int mlen)
...@@ -187,7 +187,7 @@ static int ip_map_parse(struct cache_detail *cd, ...@@ -187,7 +187,7 @@ static int ip_map_parse(struct cache_detail *cd,
struct ip_map *ipmp; struct ip_map *ipmp;
struct auth_domain *dom; struct auth_domain *dom;
time_t expiry; time64_t expiry;
if (mesg[mlen-1] != '\n') if (mesg[mlen-1] != '\n')
return -EINVAL; return -EINVAL;
...@@ -308,7 +308,7 @@ static inline struct ip_map *ip_map_lookup(struct net *net, char *class, ...@@ -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, 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 ip_map ip;
struct cache_head *ch; struct cache_head *ch;
...@@ -328,7 +328,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, ...@@ -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, 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; struct sunrpc_net *sn;
...@@ -491,7 +491,7 @@ static int unix_gid_parse(struct cache_detail *cd, ...@@ -491,7 +491,7 @@ static int unix_gid_parse(struct cache_detail *cd,
int rv; int rv;
int i; int i;
int err; int err;
time_t expiry; time64_t expiry;
struct unix_gid ug, *ugp; struct unix_gid ug, *ugp;
if (mesg[mlen - 1] != '\n') if (mesg[mlen - 1] != '\n')
......
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