diff options
Diffstat (limited to 'net/sunrpc/cache.c')
| -rw-r--r-- | net/sunrpc/cache.c | 79 |
1 files changed, 55 insertions, 24 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 39bddba53ba1..2b06410e584e 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
| 29 | #include <linux/mutex.h> | 29 | #include <linux/mutex.h> |
| 30 | #include <linux/pagemap.h> | 30 | #include <linux/pagemap.h> |
| 31 | #include <linux/smp_lock.h> | ||
| 31 | #include <asm/ioctls.h> | 32 | #include <asm/ioctls.h> |
| 32 | #include <linux/sunrpc/types.h> | 33 | #include <linux/sunrpc/types.h> |
| 33 | #include <linux/sunrpc/cache.h> | 34 | #include <linux/sunrpc/cache.h> |
| @@ -49,11 +50,17 @@ static void cache_init(struct cache_head *h) | |||
| 49 | h->last_refresh = now; | 50 | h->last_refresh = now; |
| 50 | } | 51 | } |
| 51 | 52 | ||
| 53 | static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h) | ||
| 54 | { | ||
| 55 | return (h->expiry_time < get_seconds()) || | ||
| 56 | (detail->flush_time > h->last_refresh); | ||
| 57 | } | ||
| 58 | |||
| 52 | struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, | 59 | struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, |
| 53 | struct cache_head *key, int hash) | 60 | struct cache_head *key, int hash) |
| 54 | { | 61 | { |
| 55 | struct cache_head **head, **hp; | 62 | struct cache_head **head, **hp; |
| 56 | struct cache_head *new = NULL; | 63 | struct cache_head *new = NULL, *freeme = NULL; |
| 57 | 64 | ||
| 58 | head = &detail->hash_table[hash]; | 65 | head = &detail->hash_table[hash]; |
| 59 | 66 | ||
| @@ -62,6 +69,9 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, | |||
| 62 | for (hp=head; *hp != NULL ; hp = &(*hp)->next) { | 69 | for (hp=head; *hp != NULL ; hp = &(*hp)->next) { |
| 63 | struct cache_head *tmp = *hp; | 70 | struct cache_head *tmp = *hp; |
| 64 | if (detail->match(tmp, key)) { | 71 | if (detail->match(tmp, key)) { |
| 72 | if (cache_is_expired(detail, tmp)) | ||
| 73 | /* This entry is expired, we will discard it. */ | ||
| 74 | break; | ||
| 65 | cache_get(tmp); | 75 | cache_get(tmp); |
| 66 | read_unlock(&detail->hash_lock); | 76 | read_unlock(&detail->hash_lock); |
| 67 | return tmp; | 77 | return tmp; |
| @@ -86,6 +96,13 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, | |||
| 86 | for (hp=head; *hp != NULL ; hp = &(*hp)->next) { | 96 | for (hp=head; *hp != NULL ; hp = &(*hp)->next) { |
| 87 | struct cache_head *tmp = *hp; | 97 | struct cache_head *tmp = *hp; |
| 88 | if (detail->match(tmp, key)) { | 98 | if (detail->match(tmp, key)) { |
| 99 | if (cache_is_expired(detail, tmp)) { | ||
| 100 | *hp = tmp->next; | ||
| 101 | tmp->next = NULL; | ||
| 102 | detail->entries --; | ||
| 103 | freeme = tmp; | ||
| 104 | break; | ||
| 105 | } | ||
| 89 | cache_get(tmp); | 106 | cache_get(tmp); |
| 90 | write_unlock(&detail->hash_lock); | 107 | write_unlock(&detail->hash_lock); |
| 91 | cache_put(new, detail); | 108 | cache_put(new, detail); |
| @@ -98,6 +115,8 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, | |||
| 98 | cache_get(new); | 115 | cache_get(new); |
| 99 | write_unlock(&detail->hash_lock); | 116 | write_unlock(&detail->hash_lock); |
| 100 | 117 | ||
| 118 | if (freeme) | ||
| 119 | cache_put(freeme, detail); | ||
| 101 | return new; | 120 | return new; |
| 102 | } | 121 | } |
| 103 | EXPORT_SYMBOL_GPL(sunrpc_cache_lookup); | 122 | EXPORT_SYMBOL_GPL(sunrpc_cache_lookup); |
| @@ -183,10 +202,7 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) | |||
| 183 | 202 | ||
| 184 | static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) | 203 | static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) |
| 185 | { | 204 | { |
| 186 | if (!test_bit(CACHE_VALID, &h->flags) || | 205 | if (!test_bit(CACHE_VALID, &h->flags)) |
| 187 | h->expiry_time < get_seconds()) | ||
| 188 | return -EAGAIN; | ||
| 189 | else if (detail->flush_time > h->last_refresh) | ||
| 190 | return -EAGAIN; | 206 | return -EAGAIN; |
| 191 | else { | 207 | else { |
| 192 | /* entry is valid */ | 208 | /* entry is valid */ |
| @@ -303,7 +319,7 @@ static struct cache_detail *current_detail; | |||
| 303 | static int current_index; | 319 | static int current_index; |
| 304 | 320 | ||
| 305 | static void do_cache_clean(struct work_struct *work); | 321 | static void do_cache_clean(struct work_struct *work); |
| 306 | static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean); | 322 | static struct delayed_work cache_cleaner; |
| 307 | 323 | ||
| 308 | static void sunrpc_init_cache_detail(struct cache_detail *cd) | 324 | static void sunrpc_init_cache_detail(struct cache_detail *cd) |
| 309 | { | 325 | { |
| @@ -397,31 +413,27 @@ static int cache_clean(void) | |||
| 397 | /* Ok, now to clean this strand */ | 413 | /* Ok, now to clean this strand */ |
| 398 | 414 | ||
| 399 | cp = & current_detail->hash_table[current_index]; | 415 | cp = & current_detail->hash_table[current_index]; |
| 400 | ch = *cp; | 416 | for (ch = *cp ; ch ; cp = & ch->next, ch = *cp) { |
| 401 | for (; ch; cp= & ch->next, ch= *cp) { | ||
| 402 | if (current_detail->nextcheck > ch->expiry_time) | 417 | if (current_detail->nextcheck > ch->expiry_time) |
| 403 | current_detail->nextcheck = ch->expiry_time+1; | 418 | current_detail->nextcheck = ch->expiry_time+1; |
| 404 | if (ch->expiry_time >= get_seconds() && | 419 | if (!cache_is_expired(current_detail, ch)) |
| 405 | ch->last_refresh >= current_detail->flush_time) | ||
| 406 | continue; | 420 | continue; |
| 407 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) | ||
| 408 | cache_dequeue(current_detail, ch); | ||
| 409 | 421 | ||
| 410 | if (atomic_read(&ch->ref.refcount) == 1) | ||
| 411 | break; | ||
| 412 | } | ||
| 413 | if (ch) { | ||
| 414 | *cp = ch->next; | 422 | *cp = ch->next; |
| 415 | ch->next = NULL; | 423 | ch->next = NULL; |
| 416 | current_detail->entries--; | 424 | current_detail->entries--; |
| 417 | rv = 1; | 425 | rv = 1; |
| 426 | break; | ||
| 418 | } | 427 | } |
| 428 | |||
| 419 | write_unlock(¤t_detail->hash_lock); | 429 | write_unlock(¤t_detail->hash_lock); |
| 420 | d = current_detail; | 430 | d = current_detail; |
| 421 | if (!ch) | 431 | if (!ch) |
| 422 | current_index ++; | 432 | current_index ++; |
| 423 | spin_unlock(&cache_list_lock); | 433 | spin_unlock(&cache_list_lock); |
| 424 | if (ch) { | 434 | if (ch) { |
| 435 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) | ||
| 436 | cache_dequeue(current_detail, ch); | ||
| 425 | cache_revisit_request(ch); | 437 | cache_revisit_request(ch); |
| 426 | cache_put(ch, d); | 438 | cache_put(ch, d); |
| 427 | } | 439 | } |
| @@ -1233,8 +1245,10 @@ static int content_open(struct inode *inode, struct file *file, | |||
| 1233 | if (!cd || !try_module_get(cd->owner)) | 1245 | if (!cd || !try_module_get(cd->owner)) |
| 1234 | return -EACCES; | 1246 | return -EACCES; |
| 1235 | han = __seq_open_private(file, &cache_content_op, sizeof(*han)); | 1247 | han = __seq_open_private(file, &cache_content_op, sizeof(*han)); |
| 1236 | if (han == NULL) | 1248 | if (han == NULL) { |
| 1249 | module_put(cd->owner); | ||
| 1237 | return -ENOMEM; | 1250 | return -ENOMEM; |
| 1251 | } | ||
| 1238 | 1252 | ||
| 1239 | han->cd = cd; | 1253 | han->cd = cd; |
| 1240 | return 0; | 1254 | return 0; |
| @@ -1331,12 +1345,18 @@ static unsigned int cache_poll_procfs(struct file *filp, poll_table *wait) | |||
| 1331 | return cache_poll(filp, wait, cd); | 1345 | return cache_poll(filp, wait, cd); |
| 1332 | } | 1346 | } |
| 1333 | 1347 | ||
| 1334 | static int cache_ioctl_procfs(struct inode *inode, struct file *filp, | 1348 | static long cache_ioctl_procfs(struct file *filp, |
| 1335 | unsigned int cmd, unsigned long arg) | 1349 | unsigned int cmd, unsigned long arg) |
| 1336 | { | 1350 | { |
| 1351 | long ret; | ||
| 1352 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
| 1337 | struct cache_detail *cd = PDE(inode)->data; | 1353 | struct cache_detail *cd = PDE(inode)->data; |
| 1338 | 1354 | ||
| 1339 | return cache_ioctl(inode, filp, cmd, arg, cd); | 1355 | lock_kernel(); |
| 1356 | ret = cache_ioctl(inode, filp, cmd, arg, cd); | ||
| 1357 | unlock_kernel(); | ||
| 1358 | |||
| 1359 | return ret; | ||
| 1340 | } | 1360 | } |
| 1341 | 1361 | ||
| 1342 | static int cache_open_procfs(struct inode *inode, struct file *filp) | 1362 | static int cache_open_procfs(struct inode *inode, struct file *filp) |
| @@ -1359,7 +1379,7 @@ static const struct file_operations cache_file_operations_procfs = { | |||
| 1359 | .read = cache_read_procfs, | 1379 | .read = cache_read_procfs, |
| 1360 | .write = cache_write_procfs, | 1380 | .write = cache_write_procfs, |
| 1361 | .poll = cache_poll_procfs, | 1381 | .poll = cache_poll_procfs, |
| 1362 | .ioctl = cache_ioctl_procfs, /* for FIONREAD */ | 1382 | .unlocked_ioctl = cache_ioctl_procfs, /* for FIONREAD */ |
| 1363 | .open = cache_open_procfs, | 1383 | .open = cache_open_procfs, |
| 1364 | .release = cache_release_procfs, | 1384 | .release = cache_release_procfs, |
| 1365 | }; | 1385 | }; |
| @@ -1483,6 +1503,11 @@ static int create_cache_proc_entries(struct cache_detail *cd) | |||
| 1483 | } | 1503 | } |
| 1484 | #endif | 1504 | #endif |
| 1485 | 1505 | ||
| 1506 | void __init cache_initialize(void) | ||
| 1507 | { | ||
| 1508 | INIT_DELAYED_WORK_DEFERRABLE(&cache_cleaner, do_cache_clean); | ||
| 1509 | } | ||
| 1510 | |||
| 1486 | int cache_register(struct cache_detail *cd) | 1511 | int cache_register(struct cache_detail *cd) |
| 1487 | { | 1512 | { |
| 1488 | int ret; | 1513 | int ret; |
| @@ -1525,12 +1550,18 @@ static unsigned int cache_poll_pipefs(struct file *filp, poll_table *wait) | |||
| 1525 | return cache_poll(filp, wait, cd); | 1550 | return cache_poll(filp, wait, cd); |
| 1526 | } | 1551 | } |
| 1527 | 1552 | ||
| 1528 | static int cache_ioctl_pipefs(struct inode *inode, struct file *filp, | 1553 | static long cache_ioctl_pipefs(struct file *filp, |
| 1529 | unsigned int cmd, unsigned long arg) | 1554 | unsigned int cmd, unsigned long arg) |
| 1530 | { | 1555 | { |
| 1556 | struct inode *inode = filp->f_dentry->d_inode; | ||
| 1531 | struct cache_detail *cd = RPC_I(inode)->private; | 1557 | struct cache_detail *cd = RPC_I(inode)->private; |
| 1558 | long ret; | ||
| 1559 | |||
| 1560 | lock_kernel(); | ||
| 1561 | ret = cache_ioctl(inode, filp, cmd, arg, cd); | ||
| 1562 | unlock_kernel(); | ||
| 1532 | 1563 | ||
| 1533 | return cache_ioctl(inode, filp, cmd, arg, cd); | 1564 | return ret; |
| 1534 | } | 1565 | } |
| 1535 | 1566 | ||
| 1536 | static int cache_open_pipefs(struct inode *inode, struct file *filp) | 1567 | static int cache_open_pipefs(struct inode *inode, struct file *filp) |
| @@ -1553,7 +1584,7 @@ const struct file_operations cache_file_operations_pipefs = { | |||
| 1553 | .read = cache_read_pipefs, | 1584 | .read = cache_read_pipefs, |
| 1554 | .write = cache_write_pipefs, | 1585 | .write = cache_write_pipefs, |
| 1555 | .poll = cache_poll_pipefs, | 1586 | .poll = cache_poll_pipefs, |
| 1556 | .ioctl = cache_ioctl_pipefs, /* for FIONREAD */ | 1587 | .unlocked_ioctl = cache_ioctl_pipefs, /* for FIONREAD */ |
| 1557 | .open = cache_open_pipefs, | 1588 | .open = cache_open_pipefs, |
| 1558 | .release = cache_release_pipefs, | 1589 | .release = cache_release_pipefs, |
| 1559 | }; | 1590 | }; |
