aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-08-12 02:55:22 -0400
committerJ. Bruce Fields <bfields@redhat.com>2010-09-07 19:21:20 -0400
commitc5b29f885afe890f953f7f23424045cdad31d3e4 (patch)
treecc2016f256da966974b4ed7a24ff9378a77facb2
parent17cebf658e088935d4bdebfc7ad9800e9fc4a0b2 (diff)
sunrpc: use seconds since boot in expiry cache
This protects us from confusion when the wallclock time changes. We convert to and from wallclock when setting or reading expiry times. Also use seconds since boot for last_clost time. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfs/dns_resolve.c6
-rw-r--r--fs/nfsd/nfs4idmap.c2
-rw-r--r--include/linux/sunrpc/cache.h28
-rw-r--r--net/sunrpc/cache.c36
4 files changed, 48 insertions, 24 deletions
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c
index dba50a5625db..a6e711ad130f 100644
--- a/fs/nfs/dns_resolve.c
+++ b/fs/nfs/dns_resolve.c
@@ -167,7 +167,7 @@ static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd,
167 return 0; 167 return 0;
168 } 168 }
169 item = container_of(h, struct nfs_dns_ent, h); 169 item = container_of(h, struct nfs_dns_ent, h);
170 ttl = (long)item->h.expiry_time - (long)get_seconds(); 170 ttl = item->h.expiry_time - seconds_since_boot();
171 if (ttl < 0) 171 if (ttl < 0)
172 ttl = 0; 172 ttl = 0;
173 173
@@ -239,7 +239,7 @@ static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
239 ttl = get_expiry(&buf); 239 ttl = get_expiry(&buf);
240 if (ttl == 0) 240 if (ttl == 0)
241 goto out; 241 goto out;
242 key.h.expiry_time = ttl + get_seconds(); 242 key.h.expiry_time = ttl + seconds_since_boot();
243 243
244 ret = -ENOMEM; 244 ret = -ENOMEM;
245 item = nfs_dns_lookup(cd, &key); 245 item = nfs_dns_lookup(cd, &key);
@@ -301,7 +301,7 @@ static int do_cache_lookup_nowait(struct cache_detail *cd,
301 goto out_err; 301 goto out_err;
302 ret = -ETIMEDOUT; 302 ret = -ETIMEDOUT;
303 if (!test_bit(CACHE_VALID, &(*item)->h.flags) 303 if (!test_bit(CACHE_VALID, &(*item)->h.flags)
304 || (*item)->h.expiry_time < get_seconds() 304 || (*item)->h.expiry_time < seconds_since_boot()
305 || cd->flush_time > (*item)->h.last_refresh) 305 || cd->flush_time > (*item)->h.last_refresh)
306 goto out_put; 306 goto out_put;
307 ret = -ENOENT; 307 ret = -ENOENT;
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index c78dbf493424..808b33a4a090 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -550,7 +550,7 @@ do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *),
550 goto out_err; 550 goto out_err;
551 ret = -ETIMEDOUT; 551 ret = -ETIMEDOUT;
552 if (!test_bit(CACHE_VALID, &(*item)->h.flags) 552 if (!test_bit(CACHE_VALID, &(*item)->h.flags)
553 || (*item)->h.expiry_time < get_seconds() 553 || (*item)->h.expiry_time < seconds_since_boot()
554 || detail->flush_time > (*item)->h.last_refresh) 554 || detail->flush_time > (*item)->h.last_refresh)
555 goto out_put; 555 goto out_put;
556 ret = -ENOENT; 556 ret = -ENOENT;
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 0e1febf4e5bc..ece432b7f87f 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -218,20 +218,42 @@ static inline int get_int(char **bpp, int *anint)
218 return 0; 218 return 0;
219} 219}
220 220
221/*
222 * timestamps kept in the cache are expressed in seconds
223 * since boot. This is the best for measuring differences in
224 * real time.
225 */
226static inline time_t seconds_since_boot(void)
227{
228 struct timespec boot;
229 getboottime(&boot);
230 return get_seconds() - boot.tv_sec;
231}
232
233static inline time_t convert_to_wallclock(time_t sinceboot)
234{
235 struct timespec boot;
236 getboottime(&boot);
237 return boot.tv_sec + sinceboot;
238}
239
221static inline time_t get_expiry(char **bpp) 240static inline time_t get_expiry(char **bpp)
222{ 241{
223 int rv; 242 int rv;
243 struct timespec boot;
244
224 if (get_int(bpp, &rv)) 245 if (get_int(bpp, &rv))
225 return 0; 246 return 0;
226 if (rv < 0) 247 if (rv < 0)
227 return 0; 248 return 0;
228 return rv; 249 getboottime(&boot);
250 return rv - boot.tv_sec;
229} 251}
230 252
231static inline void sunrpc_invalidate(struct cache_head *h, 253static inline void sunrpc_invalidate(struct cache_head *h,
232 struct cache_detail *detail) 254 struct cache_detail *detail)
233{ 255{
234 h->expiry_time = get_seconds() - 1; 256 h->expiry_time = seconds_since_boot() - 1;
235 detail->nextcheck = get_seconds(); 257 detail->nextcheck = seconds_since_boot();
236} 258}
237#endif /* _LINUX_SUNRPC_CACHE_H_ */ 259#endif /* _LINUX_SUNRPC_CACHE_H_ */
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 2b06410e584e..8dc121955fdc 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -42,7 +42,7 @@ static void cache_revisit_request(struct cache_head *item);
42 42
43static void cache_init(struct cache_head *h) 43static void cache_init(struct cache_head *h)
44{ 44{
45 time_t now = get_seconds(); 45 time_t now = seconds_since_boot();
46 h->next = NULL; 46 h->next = NULL;
47 h->flags = 0; 47 h->flags = 0;
48 kref_init(&h->ref); 48 kref_init(&h->ref);
@@ -52,7 +52,7 @@ static void cache_init(struct cache_head *h)
52 52
53static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h) 53static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h)
54{ 54{
55 return (h->expiry_time < get_seconds()) || 55 return (h->expiry_time < seconds_since_boot()) ||
56 (detail->flush_time > h->last_refresh); 56 (detail->flush_time > h->last_refresh);
57} 57}
58 58
@@ -127,7 +127,7 @@ static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
127static void cache_fresh_locked(struct cache_head *head, time_t expiry) 127static void cache_fresh_locked(struct cache_head *head, time_t expiry)
128{ 128{
129 head->expiry_time = expiry; 129 head->expiry_time = expiry;
130 head->last_refresh = get_seconds(); 130 head->last_refresh = seconds_since_boot();
131 set_bit(CACHE_VALID, &head->flags); 131 set_bit(CACHE_VALID, &head->flags);
132} 132}
133 133
@@ -238,7 +238,7 @@ int cache_check(struct cache_detail *detail,
238 238
239 /* now see if we want to start an upcall */ 239 /* now see if we want to start an upcall */
240 refresh_age = (h->expiry_time - h->last_refresh); 240 refresh_age = (h->expiry_time - h->last_refresh);
241 age = get_seconds() - h->last_refresh; 241 age = seconds_since_boot() - h->last_refresh;
242 242
243 if (rqstp == NULL) { 243 if (rqstp == NULL) {
244 if (rv == -EAGAIN) 244 if (rv == -EAGAIN)
@@ -253,7 +253,7 @@ int cache_check(struct cache_detail *detail,
253 cache_revisit_request(h); 253 cache_revisit_request(h);
254 if (rv == -EAGAIN) { 254 if (rv == -EAGAIN) {
255 set_bit(CACHE_NEGATIVE, &h->flags); 255 set_bit(CACHE_NEGATIVE, &h->flags);
256 cache_fresh_locked(h, get_seconds()+CACHE_NEW_EXPIRY); 256 cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
257 cache_fresh_unlocked(h, detail); 257 cache_fresh_unlocked(h, detail);
258 rv = -ENOENT; 258 rv = -ENOENT;
259 } 259 }
@@ -388,11 +388,11 @@ static int cache_clean(void)
388 return -1; 388 return -1;
389 } 389 }
390 current_detail = list_entry(next, struct cache_detail, others); 390 current_detail = list_entry(next, struct cache_detail, others);
391 if (current_detail->nextcheck > get_seconds()) 391 if (current_detail->nextcheck > seconds_since_boot())
392 current_index = current_detail->hash_size; 392 current_index = current_detail->hash_size;
393 else { 393 else {
394 current_index = 0; 394 current_index = 0;
395 current_detail->nextcheck = get_seconds()+30*60; 395 current_detail->nextcheck = seconds_since_boot()+30*60;
396 } 396 }
397 } 397 }
398 398
@@ -477,7 +477,7 @@ EXPORT_SYMBOL_GPL(cache_flush);
477void cache_purge(struct cache_detail *detail) 477void cache_purge(struct cache_detail *detail)
478{ 478{
479 detail->flush_time = LONG_MAX; 479 detail->flush_time = LONG_MAX;
480 detail->nextcheck = get_seconds(); 480 detail->nextcheck = seconds_since_boot();
481 cache_flush(); 481 cache_flush();
482 detail->flush_time = 1; 482 detail->flush_time = 1;
483} 483}
@@ -902,7 +902,7 @@ static int cache_release(struct inode *inode, struct file *filp,
902 filp->private_data = NULL; 902 filp->private_data = NULL;
903 kfree(rp); 903 kfree(rp);
904 904
905 cd->last_close = get_seconds(); 905 cd->last_close = seconds_since_boot();
906 atomic_dec(&cd->readers); 906 atomic_dec(&cd->readers);
907 } 907 }
908 module_put(cd->owner); 908 module_put(cd->owner);
@@ -1034,7 +1034,7 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h,
1034 int len; 1034 int len;
1035 1035
1036 if (atomic_read(&detail->readers) == 0 && 1036 if (atomic_read(&detail->readers) == 0 &&
1037 detail->last_close < get_seconds() - 30) { 1037 detail->last_close < seconds_since_boot() - 30) {
1038 warn_no_listener(detail); 1038 warn_no_listener(detail);
1039 return -EINVAL; 1039 return -EINVAL;
1040 } 1040 }
@@ -1219,7 +1219,8 @@ static int c_show(struct seq_file *m, void *p)
1219 1219
1220 ifdebug(CACHE) 1220 ifdebug(CACHE)
1221 seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n", 1221 seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx\n",
1222 cp->expiry_time, atomic_read(&cp->ref.refcount), cp->flags); 1222 convert_to_wallclock(cp->expiry_time),
1223 atomic_read(&cp->ref.refcount), cp->flags);
1223 cache_get(cp); 1224 cache_get(cp);
1224 if (cache_check(cd, cp, NULL)) 1225 if (cache_check(cd, cp, NULL))
1225 /* cache_check does a cache_put on failure */ 1226 /* cache_check does a cache_put on failure */
@@ -1285,7 +1286,7 @@ static ssize_t read_flush(struct file *file, char __user *buf,
1285 unsigned long p = *ppos; 1286 unsigned long p = *ppos;
1286 size_t len; 1287 size_t len;
1287 1288
1288 sprintf(tbuf, "%lu\n", cd->flush_time); 1289 sprintf(tbuf, "%lu\n", convert_to_wallclock(cd->flush_time));
1289 len = strlen(tbuf); 1290 len = strlen(tbuf);
1290 if (p >= len) 1291 if (p >= len)
1291 return 0; 1292 return 0;
@@ -1303,19 +1304,20 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
1303 struct cache_detail *cd) 1304 struct cache_detail *cd)
1304{ 1305{
1305 char tbuf[20]; 1306 char tbuf[20];
1306 char *ep; 1307 char *bp, *ep;
1307 long flushtime; 1308
1308 if (*ppos || count > sizeof(tbuf)-1) 1309 if (*ppos || count > sizeof(tbuf)-1)
1309 return -EINVAL; 1310 return -EINVAL;
1310 if (copy_from_user(tbuf, buf, count)) 1311 if (copy_from_user(tbuf, buf, count))
1311 return -EFAULT; 1312 return -EFAULT;
1312 tbuf[count] = 0; 1313 tbuf[count] = 0;
1313 flushtime = simple_strtoul(tbuf, &ep, 0); 1314 simple_strtoul(tbuf, &ep, 0);
1314 if (*ep && *ep != '\n') 1315 if (*ep && *ep != '\n')
1315 return -EINVAL; 1316 return -EINVAL;
1316 1317
1317 cd->flush_time = flushtime; 1318 bp = tbuf;
1318 cd->nextcheck = get_seconds(); 1319 cd->flush_time = get_expiry(&bp);
1320 cd->nextcheck = seconds_since_boot();
1319 cache_flush(); 1321 cache_flush();
1320 1322
1321 *ppos += count; 1323 *ppos += count;