cache.h 6.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/*
 * include/linux/sunrpc/cache.h
 *
 * 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.
 *
 */

#ifndef _LINUX_SUNRPC_CACHE_H_
#define _LINUX_SUNRPC_CACHE_H_

#include <linux/slab.h>
#include <asm/atomic.h>
#include <linux/proc_fs.h>

/*
 * Each cache requires:
 *  - A 'struct cache_detail' which contains information specific to the cache
 *    for common code to use.
 *  - An item structure that must contain a "struct cache_head"
 *  - A lookup function defined using DefineCacheLookup
 *  - A 'put' function that can release a cache item. It will only
 *    be called after cache_put has succeed, so there are guarantee
 *    to be no references.
 *  - A function to calculate a hash of an item's key.
 *
 * as well as assorted code fragments (e.g. compare keys) and numbers
 * (e.g. hash size, goal_age, etc).
 *
 * Each cache must be registered so that it can be cleaned regularly.
 * When the cache is unregistered, it is flushed completely.
 *
 * Entries have a ref count and a 'hashed' flag which counts the existance
 * in the hash table.
 * We only expire entries when refcount is zero.
 * Existance in the cache is counted  the refcount.
 */

/* Every cache item has a common header that is used
 * for expiring and refreshing entries.
 * 
 */
struct cache_head {
	struct cache_head * next;
	time_t		expiry_time;	/* After time time, don't use the data */
	time_t		last_refresh;   /* If CACHE_PENDING, this is when upcall 
					 * was sent, else this is when update was received
					 */
	atomic_t 	refcnt;
	unsigned long	flags;
};
#define	CACHE_VALID	0	/* Entry contains valid data */
#define	CACHE_NEGATIVE	1	/* Negative entry - there is no match for the key */
#define	CACHE_PENDING	2	/* An upcall has been sent but no reply received yet*/

#define	CACHE_NEW_EXPIRY 120	/* keep new things pending confirmation for 120 seconds */

struct cache_detail {
63
	struct module *		owner;
L
Linus Torvalds 已提交
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
	int			hash_size;
	struct cache_head **	hash_table;
	rwlock_t		hash_lock;

	atomic_t		inuse; /* active user-space update or lookup */

	char			*name;
	void			(*cache_put)(struct cache_head *,
					     struct cache_detail*);

	void			(*cache_request)(struct cache_detail *cd,
						 struct cache_head *h,
						 char **bpp, int *blen);
	int			(*cache_parse)(struct cache_detail *,
					       char *buf, int len);

	int			(*cache_show)(struct seq_file *m,
					      struct cache_detail *cd,
					      struct cache_head *h);

84 85 86 87 88
	struct cache_head *	(*alloc)(void);
	int			(*match)(struct cache_head *orig, struct cache_head *new);
	void			(*init)(struct cache_head *orig, struct cache_head *new);
	void			(*update)(struct cache_head *orig, struct cache_head *new);

L
Linus Torvalds 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
	/* fields below this comment are for internal use
	 * and should not be touched by cache owners
	 */
	time_t			flush_time;		/* flush all cache items with last_refresh
							 * earlier than this */
	struct list_head	others;
	time_t			nextcheck;
	int			entries;

	/* fields for communication over channel */
	struct list_head	queue;
	struct proc_dir_entry	*proc_ent;
	struct proc_dir_entry   *flush_ent, *channel_ent, *content_ent;

	atomic_t		readers;		/* how many time is /chennel open */
	time_t			last_close;		/* if no readers, when did last close */
	time_t			last_warn;		/* when we last warned about no readers */
	void			(*warn_no_listener)(struct cache_detail *cd);
};


/* this must be embedded in any request structure that
 * identifies an object that will want a callback on
 * a cache fill
 */
struct cache_req {
	struct cache_deferred_req *(*defer)(struct cache_req *req);
};
/* this must be embedded in a deferred_request that is being
 * delayed awaiting cache-fill
 */
struct cache_deferred_req {
	struct list_head	hash;	/* on hash chain */
	struct list_head	recent; /* on fifo */
	struct cache_head	*item;  /* cache item we wait on */
	time_t			recv_time;
	void			*owner; /* we might need to discard all defered requests
					 * owned by someone */
	void			(*revisit)(struct cache_deferred_req *req,
					   int too_many);
};

131

132 133 134 135 136 137 138
extern struct cache_head *
sunrpc_cache_lookup(struct cache_detail *detail,
		    struct cache_head *key, int hash);
extern struct cache_head *
sunrpc_cache_update(struct cache_detail *detail,
		    struct cache_head *new, struct cache_head *old, int hash);

L
Linus Torvalds 已提交
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204

#define cache_for_each(pos, detail, index, member) 						\
	for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ;		\
	     ({if (index==0)read_unlock(&(detail)->hash_lock); index--;});			\
		)										\
		for (pos = container_of((detail)->hash_table[index], typeof(*pos), member);	\
		     &pos->member;								\
		     pos = container_of(pos->member.next, typeof(*pos), member))

	     

extern void cache_clean_deferred(void *owner);

static inline struct cache_head  *cache_get(struct cache_head *h)
{
	atomic_inc(&h->refcnt);
	return h;
}


static inline int cache_put(struct cache_head *h, struct cache_detail *cd)
{
	if (atomic_read(&h->refcnt) <= 2 &&
	    h->expiry_time < cd->nextcheck)
		cd->nextcheck = h->expiry_time;
	return atomic_dec_and_test(&h->refcnt);
}

extern void cache_init(struct cache_head *h);
extern int cache_check(struct cache_detail *detail,
		       struct cache_head *h, struct cache_req *rqstp);
extern void cache_flush(void);
extern void cache_purge(struct cache_detail *detail);
#define NEVER (0x7FFFFFFF)
extern void cache_register(struct cache_detail *cd);
extern int cache_unregister(struct cache_detail *cd);

extern void qword_add(char **bpp, int *lp, char *str);
extern void qword_addhex(char **bpp, int *lp, char *buf, int blen);
extern int qword_get(char **bpp, char *dest, int bufsize);

static inline int get_int(char **bpp, int *anint)
{
	char buf[50];
	char *ep;
	int rv;
	int len = qword_get(bpp, buf, 50);
	if (len < 0) return -EINVAL;
	if (len ==0) return -ENOENT;
	rv = simple_strtol(buf, &ep, 0);
	if (*ep) return -EINVAL;
	*anint = rv;
	return 0;
}

static inline time_t get_expiry(char **bpp)
{
	int rv;
	if (get_int(bpp, &rv))
		return 0;
	if (rv < 0)
		return 0;
	return rv;
}

#endif /*  _LINUX_SUNRPC_CACHE_H_ */