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
4545 */
4646 struct cache_head {
4747 struct hlist_node cache_list;
48− time_t expiry_time; /* After time time, don't use the data */
49− time_t last_refresh; /* If CACHE_PENDING, this is when upcall was
48+ time64_t expiry_time; /* After time time, don't use the data */
49+ time64_t last_refresh; /* If CACHE_PENDING, this is when upcall was
5050 * sent, else this is when update was
5151 * received, though it is alway set to
5252 * be *after* ->flush_time.
@@ -95,22 +95,22 @@ struct cache_detail { · 42 unmodified lines
9595 /* fields below this comment are for internal use
9696 * and should not be touched by cache owners
9797 */
98− time_t flush_time; /* flush all cache items with
98+ time64_t flush_time; /* flush all cache items with
9999 * last_refresh at or earlier
100100 * than this. last_refresh
101101 * is never set at or earlier
102102 * than this.
103103 */
104104 struct list_head others;
105− time_t nextcheck;
105+ time64_t nextcheck;
106106 int entries;
107107
108108 /* fields for communication over channel */
109109 struct list_head queue;
110110
111111 atomic_t writers; /* how many time is /channel open */
112− time_t last_close; /* if no writers, when did last close */
113− time_t last_warn; /* when we last warned about no writers */
112+ time64_t last_close; /* if no writers, when did last close */
113+ time64_t last_warn; /* when we last warned about no writers */
114114
115115 union {
116116 struct proc_dir_entry *procfs;
@@ -147,18 +147,22 @@ struct cache_deferred_req { · 30 unmodified lines
147147 * timestamps kept in the cache are expressed in seconds
148148 * since boot. This is the best for measuring differences in
149149 * 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.
150154 */
151−static inline time_t seconds_since_boot(void)
155+static inline time64_t seconds_since_boot(void)
152156 {
153− struct timespec boot;
154− getboottime(&boot);
155− return get_seconds() - boot.tv_sec;
157+ struct timespec64 boot;
158+ getboottime64(&boot);
159+ return ktime_get_real_seconds() - boot.tv_sec;
156160 }
157161
158−static inline time_t convert_to_wallclock(time_t sinceboot)
162+static inline time64_t convert_to_wallclock(time64_t sinceboot)
159163 {
160− struct timespec boot;
161− getboottime(&boot);
164+ struct timespec64 boot;
165+ getboottime64(&boot);
162166 return boot.tv_sec + sinceboot;
163167 }
164168
@@ -273,7 +277,7 @@ static inline int get_uint(char **bpp, unsigned int *anint) · 108 unmodified lines
273277 return 0;
274278 }
275279
276−static inline int get_time(char **bpp, time_t *time)
280+static inline int get_time(char **bpp, time64_t *time)
277281 {
278282 char buf[50];
279283 long long ll;
@@ -287,20 +291,20 @@ static inline int get_time(char **bpp, time_t *time) · 7 unmodified lines
287291 if (kstrtoll(buf, 0, &ll))
288292 return -EINVAL;
289293
290− *time = (time_t)ll;
294+ *time = ll;
291295 return 0;
292296 }
293297
294−static inline time_t get_expiry(char **bpp)
298+static inline time64_t get_expiry(char **bpp)
295299 {
296− time_t rv;
297− struct timespec boot;
300+ time64_t rv;
301+ struct timespec64 boot;
298302
299303 if (get_time(bpp, &rv))
300304 return 0;
301305 if (rv < 0)
302306 return 0;
303− getboottime(&boot);
307+ getboottime64(&boot);
304308 return rv - boot.tv_sec;
305309 }
306310
net/sunrpc/auth_gss/svcauth_gss.c+1−1
@@ -203,7 +203,7 @@ static int rsi_parse(struct cache_detail *cd, · 202 unmodified lines
203203 char *ep;
204204 int len;
205205 struct rsi rsii, *rsip = NULL;
206− time_t expiry;
206+ time64_t expiry;
207207 int status = -EINVAL;
208208
209209 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
4242
4343 static void cache_init(struct cache_head *h, struct cache_detail *detail)
4444 {
45− time_t now = seconds_since_boot();
45+ time64_t now = seconds_since_boot();
4646 INIT_HLIST_NODE(&h->cache_list);
4747 h->flags = 0;
4848 kref_init(&h->ref);
@@ -139,10 +139,10 @@ EXPORT_SYMBOL_GPL(sunrpc_cache_lookup_rcu); · 90 unmodified lines
139139
140140 static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
141141
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,
143143 struct cache_detail *detail)
144144 {
145− time_t now = seconds_since_boot();
145+ time64_t now = seconds_since_boot();
146146 if (now <= detail->flush_time)
147147 /* ensure it isn't immediately treated as expired */
148148 now = detail->flush_time + 1;
@@ -274,7 +274,7 @@ int cache_check(struct cache_detail *detail, · 125 unmodified lines
274274 struct cache_head *h, struct cache_req *rqstp)
275275 {
276276 int rv;
277− long refresh_age, age;
277+ time64_t refresh_age, age;
278278
279279 /* First decide return status as best we can */
280280 rv = cache_is_valid(h);
@@ -288,7 +288,7 @@ int cache_check(struct cache_detail *detail, · 7 unmodified lines
288288 rv = -ENOENT;
289289 } else if (rv == -EAGAIN ||
290290 (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",
292292 refresh_age, age);
293293 if (!test_and_set_bit(CACHE_PENDING, &h->flags)) {
294294 switch (cache_make_upcall(detail, h)) {
@@ -1404,7 +1404,7 @@ static int c_show(struct seq_file *m, void *p) · 1109 unmodified lines
14041404 return cd->cache_show(m, cd, NULL);
14051405
14061406 ifdebug(CACHE)
1407− seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n",
1407+ seq_printf(m, "# expiry=%lld refcnt=%d flags=%lx\n",
14081408 convert_to_wallclock(cp->expiry_time),
14091409 kref_read(&cp->ref), cp->flags);
14101410 cache_get(cp);
@@ -1477,7 +1477,7 @@ static ssize_t read_flush(struct file *file, char __user *buf, · 66 unmodified lines
14771477 char tbuf[22];
14781478 size_t len;
14791479
1480− len = snprintf(tbuf, sizeof(tbuf), "%lu\n",
1480+ len = snprintf(tbuf, sizeof(tbuf), "%llu\n",
14811481 convert_to_wallclock(cd->flush_time));
14821482 return simple_read_from_buffer(buf, count, ppos, tbuf, len);
14831483 }
@@ -1488,7 +1488,7 @@ static ssize_t write_flush(struct file *file, const char __user *buf, · 4 unmodified lines
14881488 {
14891489 char tbuf[20];
14901490 char *ep;
1491− time_t now;
1491+ time64_t now;
14921492
14931493 if (*ppos || count > sizeof(tbuf)-1)
14941494 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
166166 }
167167
168168 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);
170170
171171 static int ip_map_parse(struct cache_detail *cd,
172172 char *mesg, int mlen)
@@ -187,7 +187,7 @@ static int ip_map_parse(struct cache_detail *cd, · 14 unmodified lines
187187
188188 struct ip_map *ipmp;
189189 struct auth_domain *dom;
190− time_t expiry;
190+ time64_t expiry;
191191
192192 if (mesg[mlen-1] != '\n')
193193 return -EINVAL;
@@ -308,7 +308,7 @@ static inline struct ip_map *ip_map_lookup(struct net *net, char *class, · 114 unmodified lines
308308 }
309309
310310 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)
312312 {
313313 struct ip_map ip;
314314 struct cache_head *ch;
@@ -328,7 +328,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, · 13 unmodified lines
328328 }
329329
330330 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)
332332 {
333333 struct sunrpc_net *sn;
334334
@@ -491,7 +491,7 @@ static int unix_gid_parse(struct cache_detail *cd, · 156 unmodified lines
491491 int rv;
492492 int i;
493493 int err;
494− time_t expiry;
494+ time64_t expiry;
495495 struct unix_gid ug, *ugp;
496496
497497 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