#define RPCDBG_FACILITY RPCDBG_CACHE
-static void cache_defer_req(struct cache_req *req, struct cache_head *item);
+static int cache_defer_req(struct cache_req *req, struct cache_head *item);
static void cache_revisit_request(struct cache_head *item);
static void cache_init(struct cache_head *h)
*
* Returns 0 if the cache_head can be used, or cache_puts it and returns
* -EAGAIN if upcall is pending,
+ * -ETIMEDOUT if upcall failed and should be retried,
* -ENOENT if cache entry was negative
*/
int cache_check(struct cache_detail *detail,
if (rv == -EAGAIN)
rv = -ENOENT;
} else if (rv == -EAGAIN || age > refresh_age/2) {
- dprintk("Want update, refage=%ld, age=%ld\n", refresh_age, age);
+ dprintk("RPC: 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:
}
if (rv == -EAGAIN)
- cache_defer_req(rqstp, h);
+ if (cache_defer_req(rqstp, h) != 0)
+ rv = -ETIMEDOUT;
if (rv)
cache_put(h, detail);
*
* A table is then only scanned if the current time is at least
* the nextcheck time.
- *
+ *
*/
static LIST_HEAD(cache_list);
static struct cache_detail *current_detail;
static int current_index;
-static struct file_operations cache_file_operations;
-static struct file_operations content_file_operations;
-static struct file_operations cache_flush_operations;
+static const struct file_operations cache_file_operations;
+static const struct file_operations content_file_operations;
+static const struct file_operations cache_flush_operations;
static void do_cache_clean(struct work_struct *work);
static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean);
struct proc_dir_entry *p;
cd->proc_ent->owner = cd->owner;
cd->channel_ent = cd->content_ent = NULL;
-
- p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR,
- cd->proc_ent);
+
+ p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR,
+ cd->proc_ent);
cd->flush_ent = p;
- if (p) {
- p->proc_fops = &cache_flush_operations;
- p->owner = cd->owner;
- p->data = cd;
- }
-
+ if (p) {
+ p->proc_fops = &cache_flush_operations;
+ p->owner = cd->owner;
+ p->data = cd;
+ }
+
if (cd->cache_request || cd->cache_parse) {
p = create_proc_entry("channel", S_IFREG|S_IRUSR|S_IWUSR,
cd->proc_ent);
p->data = cd;
}
}
- if (cd->cache_show) {
- p = create_proc_entry("content", S_IFREG|S_IRUSR|S_IWUSR,
- cd->proc_ent);
+ if (cd->cache_show) {
+ p = create_proc_entry("content", S_IFREG|S_IRUSR|S_IWUSR,
+ cd->proc_ent);
cd->content_ent = p;
- if (p) {
- p->proc_fops = &content_file_operations;
- p->owner = cd->owner;
- p->data = cd;
- }
- }
+ if (p) {
+ p->proc_fops = &content_file_operations;
+ p->owner = cd->owner;
+ p->data = cd;
+ }
+ }
}
rwlock_init(&cd->hash_lock);
INIT_LIST_HEAD(&cd->queue);
current_index++;
/* find a cleanable entry in the bucket and clean it, or set to next bucket */
-
+
if (current_detail && current_index < current_detail->hash_size) {
struct cache_head *ch, **cp;
struct cache_detail *d;
-
+
write_lock(¤t_detail->hash_lock);
/* Ok, now to clean this strand */
-
+
cp = & current_detail->hash_table[current_index];
ch = *cp;
for (; ch; cp= & ch->next, ch= *cp) {
}
-/*
+/*
* Clean all caches promptly. This just calls cache_clean
- * repeatedly until we are sure that every cache has had a chance to
+ * repeatedly until we are sure that every cache has had a chance to
* be fully cleaned
*/
void cache_flush(void)
* All deferred requests are stored in a hash table,
* indexed by "struct cache_head *".
* As it may be wasteful to store a whole request
- * structure, we allow the request to provide a
+ * structure, we allow the request to provide a
* deferred form, which must contain a
* 'struct cache_deferred_req'
* This cache_deferred_req contains a method to allow
static struct list_head cache_defer_hash[DFR_HASHSIZE];
static int cache_defer_cnt;
-static void cache_defer_req(struct cache_req *req, struct cache_head *item)
+static int cache_defer_req(struct cache_req *req, struct cache_head *item)
{
struct cache_deferred_req *dreq;
int hash = DFR_HASH(item);
+ if (cache_defer_cnt >= DFR_MAX) {
+ /* too much in the cache, randomly drop this one,
+ * or continue and drop the oldest below
+ */
+ if (net_random()&1)
+ return -ETIMEDOUT;
+ }
dreq = req->defer(req);
if (dreq == NULL)
- return;
+ return -ETIMEDOUT;
dreq->item = item;
dreq->recv_time = get_seconds();
/* it is in, now maybe clean up */
dreq = NULL;
if (++cache_defer_cnt > DFR_MAX) {
- /* too much in the cache, randomly drop
- * first or last
- */
- if (net_random()&1)
- dreq = list_entry(cache_defer_list.next,
- struct cache_deferred_req,
- recent);
- else
- dreq = list_entry(cache_defer_list.prev,
- struct cache_deferred_req,
- recent);
+ dreq = list_entry(cache_defer_list.prev,
+ struct cache_deferred_req, recent);
list_del(&dreq->recent);
list_del(&dreq->hash);
cache_defer_cnt--;
/* must have just been validated... */
cache_revisit_request(item);
}
+ return 0;
}
static void cache_revisit_request(struct cache_head *item)
INIT_LIST_HEAD(&pending);
spin_lock(&cache_defer_lock);
-
+
lp = cache_defer_hash[hash].next;
if (lp) {
while (lp != &cache_defer_hash[hash]) {
INIT_LIST_HEAD(&pending);
spin_lock(&cache_defer_lock);
-
+
list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) {
if (dreq->owner == owner) {
list_del(&dreq->hash);
* On write, an update request is processed
* Poll works if anything to read, and always allows write
*
- * Implemented by linked list of requests. Each open file has
+ * Implemented by linked list of requests. Each open file has
* a ->private that also exists in this list. New request are added
* to the end and may wakeup and preceding readers.
* New readers are added to the head. If, on read, an item is found with
-static struct file_operations cache_file_operations = {
+static const struct file_operations cache_file_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = cache_read,
* Messages are, like requests, separated into fields by
* spaces and dequotes as \xHEXSTRING or embedded \nnn octal
*
- * Message is
+ * Message is
* reply cachename expiry key ... content....
*
- * key and content are both parsed by cache
+ * key and content are both parsed by cache
*/
#define isodigit(c) (isdigit(c) && c <= '7')
unsigned hash, entry;
struct cache_head *ch;
struct cache_detail *cd = ((struct handle*)m->private)->cd;
-
+
read_lock(&cd->hash_lock);
if (!n--)
do {
hash++;
n += 1LL<<32;
- } while(hash < cd->hash_size &&
+ } while(hash < cd->hash_size &&
cd->hash_table[hash]==NULL);
if (hash >= cd->hash_size)
return NULL;
return res;
}
-static int content_release(struct inode *inode, struct file *file)
-{
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct handle *han = m->private;
- kfree(han);
- m->private = NULL;
- return seq_release(inode, file);
-}
-static struct file_operations content_file_operations = {
+static const struct file_operations content_file_operations = {
.open = content_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = content_release,
+ .release = seq_release_private,
};
static ssize_t read_flush(struct file *file, char __user *buf,
return count;
}
-static struct file_operations cache_flush_operations = {
+static const struct file_operations cache_flush_operations = {
.open = nonseekable_open,
.read = read_flush,
.write = write_flush,