History

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.

Arnd Bergmann committed 9 years ago

Commit f5599351 parent 294ec5b4 files · +37 −33Browse files

Unified · Split

4 files
  1. include/linux/sunrpc/cache.h +23 −19
  2. net/sunrpc/auth_gss/svcauth_gss.c +1 −1
  3. net/sunrpc/cache.c +8 −8
  4. net/sunrpc/svcauth_unix.c +5 −5
include/linux/sunrpc/cache.h+23−19
@@ -45,8 +45,8 @@ · 44 unmodified lines
45 */45 */
46struct cache_head {46struct 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 was49 time64_t last_refresh; /* If CACHE_PENDING, this is when upcall was
50 * sent, else this is when update was50 * sent, else this is when update was
51 * received, though it is alway set to51 * 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 use95 /* fields below this comment are for internal use
96 * and should not be touched by cache owners96 * and should not be touched by cache owners
97 */97 */
98 time_t flush_time; /* flush all cache items with98 time64_t flush_time; /* flush all cache items with
99 * last_refresh at or earlier99 * last_refresh at or earlier
100 * than this. last_refresh100 * than this. last_refresh
101 * is never set at or earlier101 * 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 seconds147 * timestamps kept in the cache are expressed in seconds
148 * since boot. This is the best for measuring differences in148 * 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 */
151static inline time_t seconds_since_boot(void)155static 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
158static inline time_t convert_to_wallclock(time_t sinceboot)162static 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
276static inline int get_time(char **bpp, time_t *time)280static 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
294static inline time_t get_expiry(char **bpp)298static 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
net/sunrpc/auth_gss/svcauth_gss.c+1−1
@@ -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));
net/sunrpc/cache.c+8−8
@@ -42,7 +42,7 @@ static bool cache_listeners_exist(struct cache_detail *detail); · 41 unmodified lines
42 42
43static void cache_init(struct cache_head *h, struct cache_detail *detail)43static 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
140static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);140static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
141 141
142static void cache_fresh_locked(struct cache_head *head, time_t expiry,142static 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;
net/sunrpc/svcauth_unix.c+5−5
@@ -166,7 +166,7 @@ static void ip_map_request(struct cache_detail *cd, · 165 unmodified lines
166}166}
167 167
168static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr);168static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr);
169static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time_t expiry);169static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time64_t expiry);
170 170
171static int ip_map_parse(struct cache_detail *cd,171static 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
310static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,310static 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
330static inline int ip_map_update(struct net *net, struct ip_map *ipm,330static 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')

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t