/*
* net/sunrpc/cache.c
*
* Generic code for various authentication-related caches
* used by sunrpc clients and servers.
*
* Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au>
*
* Released under terms in GPL version 2. See COPYING.
*
*/
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kmod.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/ctype.h>
#include <asm/uaccess.h>
#include <linux/poll.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/net.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <asm/ioctls.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/cache.h>
#include <linux/sunrpc/stats.h>
#define RPCDBG_FACILITY RPCDBG_CACHE
static void cache_defer_req(struct cache_req *req, struct cache_head *item);
static void cache_revisit_request(struct cache_head *item);
void cache_init(struct cache_head *h)
{
time_t now = get_seconds();
h->next = NULL;
h->flags = 0;
atomic_set(&h->refcnt, 1);
h->expiry_time = now + CACHE_NEW_EXPIRY;
h->last_refresh = now;
}
static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h);
/*
* This is the generic cache management routine for all
* the authentication caches.
* It checks the currency of a cache item and will (later)
* initiate an upcall to fill it if needed.
*
*
* Returns 0 if the cache_head can be used, or cache_puts it and returns
* -EAGAIN if upcall is pending,
* -ENOENT if cache entry was negative
*/
int cache_check(struct cache_detail *detail,
struct cache_head *h, struct cache_req *rqstp)
{
int rv;
long refresh_age, age;
/* First decide return status as best we can */
if (!test_bit(CACHE_VALID, &h->flags) ||
h->expiry_time < get_seconds())
rv = -EAGAIN;
else if (detail->flush_time > h->last_refresh)
rv = -EAGAIN;
else {
/* entry is valid */
if (test_bit(CACHE_NEGATIVE, &h->flags))
rv = -ENOENT;
else rv = 0;
}
/* now see if we want to start an upcall */
refresh_age = (h->expiry_time - h->last_refresh);
age = get_seconds() - h->last_refresh;
if (rqstp == NULL) {
if (rv == -EAGAIN)
rv = -ENOENT;
} else if (rv == -EAGAIN || age > refresh_age/2) {
dprintk("Want update, refage=%ld, age=%ld\n", refresh_age, age);
if (!test_and_set_bit(CACHE_PENDING, &h->flags)) {
switch (cache_make_upcall(detail, h)) {
case -EINVAL:
clear_bit(CACHE_PENDING, &h->flags);
if (rv == -EAGAIN) {
set_bit(CACHE_NEGATIVE, &h->flags);
cache_fresh(detail, h, get_seconds()+CACHE_NEW_EXPIRY);
rv = -ENOENT;
}
break;
case -EAGAIN:
clear_bit(CACHE_PENDING, &h->flags);
cache_revis