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.
Unified · Split
| @@ -45,8 +45,8 @@ · 44 unmodified lines | |||
| 45 | */ | 45 | */ |
| 46 | struct cache_head { | 46 | struct cache_head { |
| 47 | struct hlist_node cache_list; | 47 | struct hlist_node cache_list; |
| 48 | time_t expiry_time; /* After time time, don't use the data */ | 48 | time64_t expiry_time; /* After time time, don't use the data */ |
| 49 | time_t last_refresh; /* If CACHE_PENDING, this is when upcall was | 49 | time64_t last_refresh; /* If CACHE_PENDING, this is when upcall was |
| 50 | * sent, else this is when update was | 50 | * sent, else this is when update was |
| 51 | * received, though it is alway set to | 51 | * received, though it is alway set to |
| 52 | * be *after* ->flush_time. | 52 | * be *after* ->flush_time. |
| @@ -95,22 +95,22 @@ struct cache_detail { · 42 unmodified lines | |||
| 95 | /* fields below this comment are for internal use | 95 | /* fields below this comment are for internal use |
| 96 | * and should not be touched by cache owners | 96 | * and should not be touched by cache owners |
| 97 | */ | 97 | */ |
| 98 | time_t flush_time; /* flush all cache items with | 98 | time64_t flush_time; /* flush all cache items with |
| 99 | * last_refresh at or earlier | 99 | * last_refresh at or earlier |
| 100 | * than this. last_refresh | 100 | * than this. last_refresh |
| 101 | * is never set at or earlier | 101 | * is never set at or earlier |
| 102 | * than this. | 102 | * than this. |
| 103 | */ | 103 | */ |
| 104 | struct list_head others; | 104 | struct list_head others; |
| 105 | time_t nextcheck; | 105 | time64_t nextcheck; |
| 106 | int entries; | 106 | int entries; |
| 107 | 107 | ||
| 108 | /* fields for communication over channel */ | 108 | /* fields for communication over channel */ |
| 109 | struct list_head queue; | 109 | struct list_head queue; |
| 110 | 110 | ||
| 111 | atomic_t writers; /* how many time is /channel open */ | 111 | atomic_t writers; /* how many time is /channel open */ |
| 112 | time_t last_close; /* if no writers, when did last close */ | 112 | time64_t last_close; /* if no writers, when did last close */ |
| 113 | time_t last_warn; /* when we last warned about no writers */ | 113 | time64_t last_warn; /* when we last warned about no writers */ |
| 114 | 114 | ||
| 115 | union { | 115 | union { |
| 116 | struct proc_dir_entry *procfs; | 116 | struct proc_dir_entry *procfs; |
| @@ -147,18 +147,22 @@ struct cache_deferred_req { · 30 unmodified lines | |||
| 147 | * timestamps kept in the cache are expressed in seconds | 147 | * timestamps kept in the cache are expressed in seconds |
| 148 | * since boot. This is the best for measuring differences in | 148 | * since boot. This is the best for measuring differences in |
| 149 | * real time. | 149 | * real time. |
| 150 | * This reimplemnts ktime_get_boottime_seconds() in a slightly | ||
| 151 | * faster but less accurate way. When we end up converting | ||
| 152 | * back to wallclock (CLOCK_REALTIME), that error often | ||
| 153 | * cancels out during the reverse operation. | ||
| 150 | */ | 154 | */ |
| 151 | static inline time_t seconds_since_boot(void) | 155 | static inline time64_t seconds_since_boot(void) |
| 152 | { | 156 | { |
| 153 | struct timespec boot; | 157 | struct timespec64 boot; |
| 154 | getboottime(&boot); | 158 | getboottime64(&boot); |
| 155 | return get_seconds() - boot.tv_sec; | 159 | return ktime_get_real_seconds() - boot.tv_sec; |
| 156 | } | 160 | } |
| 157 | 161 | ||
| 158 | static inline time_t convert_to_wallclock(time_t sinceboot) | 162 | static inline time64_t convert_to_wallclock(time64_t sinceboot) |
| 159 | { | 163 | { |
| 160 | struct timespec boot; | 164 | struct timespec64 boot; |
| 161 | getboottime(&boot); | 165 | getboottime64(&boot); |
| 162 | return boot.tv_sec + sinceboot; | 166 | return boot.tv_sec + sinceboot; |
| 163 | } | 167 | } |
| 164 | 168 | ||
| @@ -273,7 +277,7 @@ static inline int get_uint(char **bpp, unsigned int *anint) · 108 unmodified lines | |||
| 273 | return 0; | 277 | return 0; |
| 274 | } | 278 | } |
| 275 | 279 | ||
| 276 | static inline int get_time(char **bpp, time_t *time) | 280 | static inline int get_time(char **bpp, time64_t *time) |
| 277 | { | 281 | { |
| 278 | char buf[50]; | 282 | char buf[50]; |
| 279 | long long ll; | 283 | long long ll; |
| @@ -287,20 +291,20 @@ static inline int get_time(char **bpp, time_t *time) · 7 unmodified lines | |||
| 287 | if (kstrtoll(buf, 0, &ll)) | 291 | if (kstrtoll(buf, 0, &ll)) |
| 288 | return -EINVAL; | 292 | return -EINVAL; |
| 289 | 293 | ||
| 290 | *time = (time_t)ll; | 294 | *time = ll; |
| 291 | return 0; | 295 | return 0; |
| 292 | } | 296 | } |
| 293 | 297 | ||
| 294 | static inline time_t get_expiry(char **bpp) | 298 | static inline time64_t get_expiry(char **bpp) |
| 295 | { | 299 | { |
| 296 | time_t rv; | 300 | time64_t rv; |
| 297 | struct timespec boot; | 301 | struct timespec64 boot; |
| 298 | 302 | ||
| 299 | if (get_time(bpp, &rv)) | 303 | if (get_time(bpp, &rv)) |
| 300 | return 0; | 304 | return 0; |
| 301 | if (rv < 0) | 305 | if (rv < 0) |
| 302 | return 0; | 306 | return 0; |
| 303 | getboottime(&boot); | 307 | getboottime64(&boot); |
| 304 | return rv - boot.tv_sec; | 308 | return rv - boot.tv_sec; |
| 305 | } | 309 | } |
| 306 | 310 | ||
| @@ -203,7 +203,7 @@ static int rsi_parse(struct cache_detail *cd, · 202 unmodified lines | |||
| 203 | char *ep; | 203 | char *ep; |
| 204 | int len; | 204 | int len; |
| 205 | struct rsi rsii, *rsip = NULL; | 205 | struct rsi rsii, *rsip = NULL; |
| 206 | time_t expiry; | 206 | time64_t expiry; |
| 207 | int status = -EINVAL; | 207 | int status = -EINVAL; |
| 208 | 208 | ||
| 209 | memset(&rsii, 0, sizeof(rsii)); | 209 | memset(&rsii, 0, sizeof(rsii)); |
| @@ -42,7 +42,7 @@ static bool cache_listeners_exist(struct cache_detail *detail); · 41 unmodified lines | |||
| 42 | 42 | ||
| 43 | static void cache_init(struct cache_head *h, struct cache_detail *detail) | 43 | static void cache_init(struct cache_head *h, struct cache_detail *detail) |
| 44 | { | 44 | { |
| 45 | time_t now = seconds_since_boot(); | 45 | time64_t now = seconds_since_boot(); |
| 46 | INIT_HLIST_NODE(&h->cache_list); | 46 | INIT_HLIST_NODE(&h->cache_list); |
| 47 | h->flags = 0; | 47 | h->flags = 0; |
| 48 | kref_init(&h->ref); | 48 | kref_init(&h->ref); |
| @@ -139,10 +139,10 @@ EXPORT_SYMBOL_GPL(sunrpc_cache_lookup_rcu); · 90 unmodified lines | |||
| 139 | 139 | ||
| 140 | static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch); | 140 | static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch); |
| 141 | 141 | ||
| 142 | static void cache_fresh_locked(struct cache_head *head, time_t expiry, | 142 | static void cache_fresh_locked(struct cache_head *head, time64_t expiry, |
| 143 | struct cache_detail *detail) | 143 | struct cache_detail *detail) |
| 144 | { | 144 | { |
| 145 | time_t now = seconds_since_boot(); | 145 | time64_t now = seconds_since_boot(); |
| 146 | if (now <= detail->flush_time) | 146 | if (now <= detail->flush_time) |
| 147 | /* ensure it isn't immediately treated as expired */ | 147 | /* ensure it isn't immediately treated as expired */ |
| 148 | now = detail->flush_time + 1; | 148 | now = detail->flush_time + 1; |
| @@ -274,7 +274,7 @@ int cache_check(struct cache_detail *detail, · 125 unmodified lines | |||
| 274 | struct cache_head *h, struct cache_req *rqstp) | 274 | struct cache_head *h, struct cache_req *rqstp) |
| 275 | { | 275 | { |
| 276 | int rv; | 276 | int rv; |
| 277 | long refresh_age, age; | 277 | time64_t refresh_age, age; |
| 278 | 278 | ||
| 279 | /* First decide return status as best we can */ | 279 | /* First decide return status as best we can */ |
| 280 | rv = cache_is_valid(h); | 280 | rv = cache_is_valid(h); |
| @@ -288,7 +288,7 @@ int cache_check(struct cache_detail *detail, · 7 unmodified lines | |||
| 288 | rv = -ENOENT; | 288 | rv = -ENOENT; |
| 289 | } else if (rv == -EAGAIN || | 289 | } else if (rv == -EAGAIN || |
| 290 | (h->expiry_time != 0 && age > refresh_age/2)) { | 290 | (h->expiry_time != 0 && age > refresh_age/2)) { |
| 291 | dprintk("RPC: Want update, refage=%ld, age=%ld\n", | 291 | dprintk("RPC: Want update, refage=%lld, age=%lld\n", |
| 292 | refresh_age, age); | 292 | refresh_age, age); |
| 293 | if (!test_and_set_bit(CACHE_PENDING, &h->flags)) { | 293 | if (!test_and_set_bit(CACHE_PENDING, &h->flags)) { |
| 294 | switch (cache_make_upcall(detail, h)) { | 294 | switch (cache_make_upcall(detail, h)) { |
| @@ -1404,7 +1404,7 @@ static int c_show(struct seq_file *m, void *p) · 1109 unmodified lines | |||
| 1404 | return cd->cache_show(m, cd, NULL); | 1404 | return cd->cache_show(m, cd, NULL); |
| 1405 | 1405 | ||
| 1406 | ifdebug(CACHE) | 1406 | ifdebug(CACHE) |
| 1407 | seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n", | 1407 | seq_printf(m, "# expiry=%lld refcnt=%d flags=%lx\n", |
| 1408 | convert_to_wallclock(cp->expiry_time), | 1408 | convert_to_wallclock(cp->expiry_time), |
| 1409 | kref_read(&cp->ref), cp->flags); | 1409 | kref_read(&cp->ref), cp->flags); |
| 1410 | cache_get(cp); | 1410 | cache_get(cp); |
| @@ -1477,7 +1477,7 @@ static ssize_t read_flush(struct file *file, char __user *buf, · 66 unmodified lines | |||
| 1477 | char tbuf[22]; | 1477 | char tbuf[22]; |
| 1478 | size_t len; | 1478 | size_t len; |
| 1479 | 1479 | ||
| 1480 | len = snprintf(tbuf, sizeof(tbuf), "%lu\n", | 1480 | len = snprintf(tbuf, sizeof(tbuf), "%llu\n", |
| 1481 | convert_to_wallclock(cd->flush_time)); | 1481 | convert_to_wallclock(cd->flush_time)); |
| 1482 | return simple_read_from_buffer(buf, count, ppos, tbuf, len); | 1482 | return simple_read_from_buffer(buf, count, ppos, tbuf, len); |
| 1483 | } | 1483 | } |
| @@ -1488,7 +1488,7 @@ static ssize_t write_flush(struct file *file, const char __user *buf, · 4 unmodified lines | |||
| 1488 | { | 1488 | { |
| 1489 | char tbuf[20]; | 1489 | char tbuf[20]; |
| 1490 | char *ep; | 1490 | char *ep; |
| 1491 | time_t now; | 1491 | time64_t now; |
| 1492 | 1492 | ||
| 1493 | if (*ppos || count > sizeof(tbuf)-1) | 1493 | if (*ppos || count > sizeof(tbuf)-1) |
| 1494 | return -EINVAL; | 1494 | return -EINVAL; |
| @@ -166,7 +166,7 @@ static void ip_map_request(struct cache_detail *cd, · 165 unmodified lines | |||
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr); | 168 | static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr); |
| 169 | static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time_t expiry); | 169 | static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time64_t expiry); |
| 170 | 170 | ||
| 171 | static int ip_map_parse(struct cache_detail *cd, | 171 | static int ip_map_parse(struct cache_detail *cd, |
| 172 | char *mesg, int mlen) | 172 | char *mesg, int mlen) |
| @@ -187,7 +187,7 @@ static int ip_map_parse(struct cache_detail *cd, · 14 unmodified lines | |||
| 187 | 187 | ||
| 188 | struct ip_map *ipmp; | 188 | struct ip_map *ipmp; |
| 189 | struct auth_domain *dom; | 189 | struct auth_domain *dom; |
| 190 | time_t expiry; | 190 | time64_t expiry; |
| 191 | 191 | ||
| 192 | if (mesg[mlen-1] != '\n') | 192 | if (mesg[mlen-1] != '\n') |
| 193 | return -EINVAL; | 193 | return -EINVAL; |
| @@ -308,7 +308,7 @@ static inline struct ip_map *ip_map_lookup(struct net *net, char *class, · 114 unmodified lines | |||
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, | 310 | static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, |
| 311 | struct unix_domain *udom, time_t expiry) | 311 | struct unix_domain *udom, time64_t expiry) |
| 312 | { | 312 | { |
| 313 | struct ip_map ip; | 313 | struct ip_map ip; |
| 314 | struct cache_head *ch; | 314 | struct cache_head *ch; |
| @@ -328,7 +328,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, · 13 unmodified lines | |||
| 328 | } | 328 | } |
| 329 | 329 | ||
| 330 | static inline int ip_map_update(struct net *net, struct ip_map *ipm, | 330 | static inline int ip_map_update(struct net *net, struct ip_map *ipm, |
| 331 | struct unix_domain *udom, time_t expiry) | 331 | struct unix_domain *udom, time64_t expiry) |
| 332 | { | 332 | { |
| 333 | struct sunrpc_net *sn; | 333 | struct sunrpc_net *sn; |
| 334 | 334 | ||
| @@ -491,7 +491,7 @@ static int unix_gid_parse(struct cache_detail *cd, · 156 unmodified lines | |||
| 491 | int rv; | 491 | int rv; |
| 492 | int i; | 492 | int i; |
| 493 | int err; | 493 | int err; |
| 494 | time_t expiry; | 494 | time64_t expiry; |
| 495 | struct unix_gid ug, *ugp; | 495 | struct unix_gid ug, *ugp; |
| 496 | 496 | ||
| 497 | if (mesg[mlen - 1] != '\n') | 497 | if (mesg[mlen - 1] != '\n') |