nfscache.c 12.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10
/*
 * Request reply cache. This is currently a global cache, but this may
 * change in the future and be a per-client cache.
 *
 * This code is heavily inspired by the 44BSD implementation, although
 * it does things a bit differently.
 *
 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
 */

11
#include <linux/slab.h>
12
#include <linux/sunrpc/addr.h>
13
#include <linux/highmem.h>
14
#include <net/checksum.h>
15

16 17
#include "nfsd.h"
#include "cache.h"
L
Linus Torvalds 已提交
18

19 20
#define NFSDDBG_FACILITY	NFSDDBG_REPCACHE

L
Linus Torvalds 已提交
21 22
#define HASHSIZE		64

G
Greg Banks 已提交
23
static struct hlist_head *	cache_hash;
L
Linus Torvalds 已提交
24
static struct list_head 	lru_head;
25
static struct kmem_cache	*drc_slab;
26
static unsigned int		num_drc_entries;
27
static unsigned int		max_drc_entries;
L
Linus Torvalds 已提交
28

G
Greg Banks 已提交
29 30 31 32 33 34 35 36 37 38
/*
 * Calculate the hash index from an XID.
 */
static inline u32 request_hash(u32 xid)
{
	u32 h = xid;
	h ^= (xid >> 24);
	return h & (HASHSIZE-1);
}

L
Linus Torvalds 已提交
39
static int	nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
40
static void	cache_cleaner_func(struct work_struct *unused);
41 42 43 44 45 46 47
static int 	nfsd_reply_cache_shrink(struct shrinker *shrink,
					struct shrink_control *sc);

struct shrinker nfsd_reply_cache_shrinker = {
	.shrink	= nfsd_reply_cache_shrink,
	.seeks	= 1,
};
L
Linus Torvalds 已提交
48

G
Greg Banks 已提交
49
/*
L
Linus Torvalds 已提交
50 51 52 53 54
 * locking for the reply cache:
 * A cache entry is "single use" if c_state == RC_INPROG
 * Otherwise, it when accessing _prev or _next, the lock must be held.
 */
static DEFINE_SPINLOCK(cache_lock);
55
static DECLARE_DELAYED_WORK(cache_cleaner, cache_cleaner_func);
L
Linus Torvalds 已提交
56

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
/*
 * Put a cap on the size of the DRC based on the amount of available
 * low memory in the machine.
 *
 *  64MB:    8192
 * 128MB:   11585
 * 256MB:   16384
 * 512MB:   23170
 *   1GB:   32768
 *   2GB:   46340
 *   4GB:   65536
 *   8GB:   92681
 *  16GB:  131072
 *
 * ...with a hard cap of 256k entries. In the worst case, each entry will be
 * ~1k, so the above numbers should give a rough max of the amount of memory
 * used in k.
 */
static unsigned int
nfsd_cache_size_limit(void)
{
	unsigned int limit;
	unsigned long low_pages = totalram_pages - totalhigh_pages;

	limit = (16 * int_sqrt(low_pages)) << (PAGE_SHIFT-10);
	return min_t(unsigned int, limit, 256*1024);
}

85 86
static struct svc_cacherep *
nfsd_reply_cache_alloc(void)
L
Linus Torvalds 已提交
87 88
{
	struct svc_cacherep	*rp;
89 90 91 92 93 94 95 96 97 98 99 100 101 102

	rp = kmem_cache_alloc(drc_slab, GFP_KERNEL);
	if (rp) {
		rp->c_state = RC_UNUSED;
		rp->c_type = RC_NOCACHE;
		INIT_LIST_HEAD(&rp->c_lru);
		INIT_HLIST_NODE(&rp->c_hash);
	}
	return rp;
}

static void
nfsd_reply_cache_free_locked(struct svc_cacherep *rp)
{
103
	if (rp->c_type == RC_REPLBUFF)
104
		kfree(rp->c_replvec.iov_base);
105
	hlist_del(&rp->c_hash);
106
	list_del(&rp->c_lru);
107
	--num_drc_entries;
108 109 110
	kmem_cache_free(drc_slab, rp);
}

111 112 113 114 115 116 117 118
static void
nfsd_reply_cache_free(struct svc_cacherep *rp)
{
	spin_lock(&cache_lock);
	nfsd_reply_cache_free_locked(rp);
	spin_unlock(&cache_lock);
}

119 120
int nfsd_reply_cache_init(void)
{
121
	register_shrinker(&nfsd_reply_cache_shrinker);
122 123 124 125 126
	drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep),
					0, 0, NULL);
	if (!drc_slab)
		goto out_nomem;

127
	cache_hash = kcalloc(HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL);
G
Greg Banks 已提交
128
	if (!cache_hash)
129
		goto out_nomem;
L
Linus Torvalds 已提交
130

131 132 133
	INIT_LIST_HEAD(&lru_head);
	max_drc_entries = nfsd_cache_size_limit();
	num_drc_entries = 0;
134

135 136 137 138 139
	return 0;
out_nomem:
	printk(KERN_ERR "nfsd: failed to allocate reply cache\n");
	nfsd_reply_cache_shutdown();
	return -ENOMEM;
L
Linus Torvalds 已提交
140 141
}

142
void nfsd_reply_cache_shutdown(void)
L
Linus Torvalds 已提交
143 144 145
{
	struct svc_cacherep	*rp;

146
	unregister_shrinker(&nfsd_reply_cache_shrinker);
147 148
	cancel_delayed_work_sync(&cache_cleaner);

L
Linus Torvalds 已提交
149 150
	while (!list_empty(&lru_head)) {
		rp = list_entry(lru_head.next, struct svc_cacherep, c_lru);
151
		nfsd_reply_cache_free_locked(rp);
L
Linus Torvalds 已提交
152 153
	}

G
Greg Banks 已提交
154 155
	kfree (cache_hash);
	cache_hash = NULL;
156 157 158 159 160

	if (drc_slab) {
		kmem_cache_destroy(drc_slab);
		drc_slab = NULL;
	}
L
Linus Torvalds 已提交
161 162 163
}

/*
164 165
 * Move cache entry to end of LRU list, and queue the cleaner to run if it's
 * not already scheduled.
L
Linus Torvalds 已提交
166 167 168 169
 */
static void
lru_put_end(struct svc_cacherep *rp)
{
170
	rp->c_timestamp = jiffies;
A
Akinobu Mita 已提交
171
	list_move_tail(&rp->c_lru, &lru_head);
172
	schedule_delayed_work(&cache_cleaner, RC_EXPIRE);
L
Linus Torvalds 已提交
173 174 175 176 177 178 179 180 181
}

/*
 * Move a cache entry from one hash list to another
 */
static void
hash_refile(struct svc_cacherep *rp)
{
	hlist_del_init(&rp->c_hash);
G
Greg Banks 已提交
182
	hlist_add_head(&rp->c_hash, cache_hash + request_hash(rp->c_xid));
L
Linus Torvalds 已提交
183 184
}

185 186 187 188 189 190 191
static inline bool
nfsd_cache_entry_expired(struct svc_cacherep *rp)
{
	return rp->c_state != RC_INPROG &&
	       time_after(jiffies, rp->c_timestamp + RC_EXPIRE);
}

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
/*
 * Walk the LRU list and prune off entries that are older than RC_EXPIRE.
 * Also prune the oldest ones when the total exceeds the max number of entries.
 */
static void
prune_cache_entries(void)
{
	struct svc_cacherep *rp, *tmp;

	list_for_each_entry_safe(rp, tmp, &lru_head, c_lru) {
		if (!nfsd_cache_entry_expired(rp) &&
		    num_drc_entries <= max_drc_entries)
			break;
		nfsd_reply_cache_free_locked(rp);
	}

	/*
	 * Conditionally rearm the job. If we cleaned out the list, then
	 * cancel any pending run (since there won't be any work to do).
	 * Otherwise, we rearm the job or modify the existing one to run in
	 * RC_EXPIRE since we just ran the pruner.
	 */
	if (list_empty(&lru_head))
		cancel_delayed_work(&cache_cleaner);
	else
		mod_delayed_work(system_wq, &cache_cleaner, RC_EXPIRE);
}

static void
cache_cleaner_func(struct work_struct *unused)
{
	spin_lock(&cache_lock);
	prune_cache_entries();
	spin_unlock(&cache_lock);
}

228 229 230 231 232 233 234 235 236 237 238 239 240 241
static int
nfsd_reply_cache_shrink(struct shrinker *shrink, struct shrink_control *sc)
{
	unsigned int num;

	spin_lock(&cache_lock);
	if (sc->nr_to_scan)
		prune_cache_entries();
	num = num_drc_entries;
	spin_unlock(&cache_lock);

	return num;
}

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
/*
 * Walk an xdr_buf and get a CRC for at most the first RC_CSUMLEN bytes
 */
static __wsum
nfsd_cache_csum(struct svc_rqst *rqstp)
{
	int idx;
	unsigned int base;
	__wsum csum;
	struct xdr_buf *buf = &rqstp->rq_arg;
	const unsigned char *p = buf->head[0].iov_base;
	size_t csum_len = min_t(size_t, buf->head[0].iov_len + buf->page_len,
				RC_CSUMLEN);
	size_t len = min(buf->head[0].iov_len, csum_len);

	/* rq_arg.head first */
	csum = csum_partial(p, len, 0);
	csum_len -= len;

	/* Continue into page array */
	idx = buf->page_base / PAGE_SIZE;
	base = buf->page_base & ~PAGE_MASK;
	while (csum_len) {
		p = page_address(buf->pages[idx]) + base;
266
		len = min_t(size_t, PAGE_SIZE - base, csum_len);
267 268 269 270 271 272 273 274
		csum = csum_partial(p, len, csum);
		csum_len -= len;
		base = 0;
		++idx;
	}
	return csum;
}

275 276 277 278 279 280
/*
 * Search the request hash for an entry that matches the given rqstp.
 * Must be called with cache_lock held. Returns the found entry or
 * NULL on failure.
 */
static struct svc_cacherep *
281
nfsd_cache_search(struct svc_rqst *rqstp, __wsum csum)
282 283 284 285 286 287 288 289 290 291 292
{
	struct svc_cacherep	*rp;
	struct hlist_node	*hn;
	struct hlist_head 	*rh;
	__be32			xid = rqstp->rq_xid;
	u32			proto =  rqstp->rq_prot,
				vers = rqstp->rq_vers,
				proc = rqstp->rq_proc;

	rh = &cache_hash[request_hash(xid)];
	hlist_for_each_entry(rp, hn, rh, c_hash) {
293
		if (xid == rp->c_xid && proc == rp->c_proc &&
294
		    proto == rp->c_prot && vers == rp->c_vers &&
295
		    rqstp->rq_arg.len == rp->c_len && csum == rp->c_csum &&
296 297 298 299 300 301 302
		    rpc_cmp_addr(svc_addr(rqstp), (struct sockaddr *)&rp->c_addr) &&
		    rpc_get_port(svc_addr(rqstp)) == rpc_get_port((struct sockaddr *)&rp->c_addr))
			return rp;
	}
	return NULL;
}

L
Linus Torvalds 已提交
303 304
/*
 * Try to find an entry matching the current call in the cache. When none
305 306 307 308
 * is found, we try to grab the oldest expired entry off the LRU list. If
 * a suitable one isn't there, then drop the cache_lock and allocate a
 * new one, then search again in case one got inserted while this thread
 * didn't hold the lock.
L
Linus Torvalds 已提交
309 310
 */
int
311
nfsd_cache_lookup(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
312
{
313
	struct svc_cacherep	*rp, *found;
314 315
	__be32			xid = rqstp->rq_xid;
	u32			proto =  rqstp->rq_prot,
L
Linus Torvalds 已提交
316 317
				vers = rqstp->rq_vers,
				proc = rqstp->rq_proc;
318
	__wsum			csum;
L
Linus Torvalds 已提交
319
	unsigned long		age;
320
	int type = rqstp->rq_cachetype;
L
Linus Torvalds 已提交
321 322 323
	int rtn;

	rqstp->rq_cacherep = NULL;
324
	if (type == RC_NOCACHE) {
L
Linus Torvalds 已提交
325 326 327 328
		nfsdstats.rcnocache++;
		return RC_DOIT;
	}

329 330
	csum = nfsd_cache_csum(rqstp);

L
Linus Torvalds 已提交
331 332 333
	spin_lock(&cache_lock);
	rtn = RC_DOIT;

334
	rp = nfsd_cache_search(rqstp, csum);
335
	if (rp)
336
		goto found_entry;
337 338 339 340 341

	/* Try to use the first entry on the LRU */
	if (!list_empty(&lru_head)) {
		rp = list_first_entry(&lru_head, struct svc_cacherep, c_lru);
		if (nfsd_cache_entry_expired(rp) ||
342 343 344
		    num_drc_entries >= max_drc_entries) {
			lru_put_end(rp);
			prune_cache_entries();
345
			goto setup_entry;
346
		}
L
Linus Torvalds 已提交
347 348
	}

349
	/* Drop the lock and allocate a new entry */
350 351 352 353 354
	spin_unlock(&cache_lock);
	rp = nfsd_reply_cache_alloc();
	if (!rp) {
		dprintk("nfsd: unable to allocate DRC entry!\n");
		return RC_DOIT;
L
Linus Torvalds 已提交
355
	}
356 357 358 359 360 361 362
	spin_lock(&cache_lock);
	++num_drc_entries;

	/*
	 * Must search again just in case someone inserted one
	 * after we dropped the lock above.
	 */
363
	found = nfsd_cache_search(rqstp, csum);
364 365 366 367
	if (found) {
		nfsd_reply_cache_free_locked(rp);
		rp = found;
		goto found_entry;
L
Linus Torvalds 已提交
368 369
	}

370 371 372 373 374 375 376 377
	/*
	 * We're keeping the one we just allocated. Are we now over the
	 * limit? Prune one off the tip of the LRU in trade for the one we
	 * just allocated if so.
	 */
	if (num_drc_entries >= max_drc_entries)
		nfsd_reply_cache_free_locked(list_first_entry(&lru_head,
						struct svc_cacherep, c_lru));
L
Linus Torvalds 已提交
378

379 380
setup_entry:
	nfsdstats.rcmisses++;
L
Linus Torvalds 已提交
381 382 383 384
	rqstp->rq_cacherep = rp;
	rp->c_state = RC_INPROG;
	rp->c_xid = xid;
	rp->c_proc = proc;
385 386
	rpc_copy_addr((struct sockaddr *)&rp->c_addr, svc_addr(rqstp));
	rpc_set_port((struct sockaddr *)&rp->c_addr, rpc_get_port(svc_addr(rqstp)));
L
Linus Torvalds 已提交
387 388
	rp->c_prot = proto;
	rp->c_vers = vers;
389 390
	rp->c_len = rqstp->rq_arg.len;
	rp->c_csum = csum;
L
Linus Torvalds 已提交
391 392

	hash_refile(rp);
393
	lru_put_end(rp);
L
Linus Torvalds 已提交
394 395 396 397 398 399 400 401 402 403 404 405

	/* release any buffer */
	if (rp->c_type == RC_REPLBUFF) {
		kfree(rp->c_replvec.iov_base);
		rp->c_replvec.iov_base = NULL;
	}
	rp->c_type = RC_NOCACHE;
 out:
	spin_unlock(&cache_lock);
	return rtn;

found_entry:
406
	nfsdstats.rchits++;
L
Linus Torvalds 已提交
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
	/* We found a matching entry which is either in progress or done. */
	age = jiffies - rp->c_timestamp;
	lru_put_end(rp);

	rtn = RC_DROPIT;
	/* Request being processed or excessive rexmits */
	if (rp->c_state == RC_INPROG || age < RC_DELAY)
		goto out;

	/* From the hall of fame of impractical attacks:
	 * Is this a user who tries to snoop on the cache? */
	rtn = RC_DOIT;
	if (!rqstp->rq_secure && rp->c_secure)
		goto out;

	/* Compose RPC reply header */
	switch (rp->c_type) {
	case RC_NOCACHE:
		break;
	case RC_REPLSTAT:
		svc_putu32(&rqstp->rq_res.head[0], rp->c_replstat);
		rtn = RC_REPLY;
		break;
	case RC_REPLBUFF:
		if (!nfsd_cache_append(rqstp, &rp->c_replvec))
			goto out;	/* should not happen */
		rtn = RC_REPLY;
		break;
	default:
		printk(KERN_WARNING "nfsd: bad repcache type %d\n", rp->c_type);
437
		nfsd_reply_cache_free_locked(rp);
L
Linus Torvalds 已提交
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
	}

	goto out;
}

/*
 * Update a cache entry. This is called from nfsd_dispatch when
 * the procedure has been executed and the complete reply is in
 * rqstp->rq_res.
 *
 * We're copying around data here rather than swapping buffers because
 * the toplevel loop requires max-sized buffers, which would be a waste
 * of memory for a cache with a max reply size of 100 bytes (diropokres).
 *
 * If we should start to use different types of cache entries tailored
 * specifically for attrstat and fh's, we may save even more space.
 *
 * Also note that a cachetype of RC_NOCACHE can legally be passed when
 * nfsd failed to encode a reply that otherwise would have been cached.
 * In this case, nfsd_cache_update is called with statp == NULL.
 */
void
460
nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp)
L
Linus Torvalds 已提交
461
{
462
	struct svc_cacherep *rp = rqstp->rq_cacherep;
L
Linus Torvalds 已提交
463 464 465
	struct kvec	*resv = &rqstp->rq_res.head[0], *cachv;
	int		len;

466
	if (!rp)
L
Linus Torvalds 已提交
467 468 469 470
		return;

	len = resv->iov_len - ((char*)statp - (char*)resv->iov_base);
	len >>= 2;
G
Greg Banks 已提交
471

L
Linus Torvalds 已提交
472 473
	/* Don't cache excessive amounts of data and XDR failures */
	if (!statp || len > (256 >> 2)) {
474
		nfsd_reply_cache_free(rp);
L
Linus Torvalds 已提交
475 476 477 478 479 480 481 482 483 484 485 486 487
		return;
	}

	switch (cachetype) {
	case RC_REPLSTAT:
		if (len != 1)
			printk("nfsd: RC_REPLSTAT/reply len %d!\n",len);
		rp->c_replstat = *statp;
		break;
	case RC_REPLBUFF:
		cachv = &rp->c_replvec;
		cachv->iov_base = kmalloc(len << 2, GFP_KERNEL);
		if (!cachv->iov_base) {
488
			nfsd_reply_cache_free(rp);
L
Linus Torvalds 已提交
489 490 491 492 493
			return;
		}
		cachv->iov_len = len << 2;
		memcpy(cachv->iov_base, statp, len << 2);
		break;
494 495 496
	case RC_NOCACHE:
		nfsd_reply_cache_free(rp);
		return;
L
Linus Torvalds 已提交
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
	}
	spin_lock(&cache_lock);
	lru_put_end(rp);
	rp->c_secure = rqstp->rq_secure;
	rp->c_type = cachetype;
	rp->c_state = RC_DONE;
	spin_unlock(&cache_lock);
	return;
}

/*
 * Copy cached reply to current reply buffer. Should always fit.
 * FIXME as reply is in a page, we should just attach the page, and
 * keep a refcount....
 */
static int
nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *data)
{
	struct kvec	*vec = &rqstp->rq_res.head[0];

	if (vec->iov_len + data->iov_len > PAGE_SIZE) {
		printk(KERN_WARNING "nfsd: cached reply too large (%Zd).\n",
				data->iov_len);
		return 0;
	}
	memcpy((char*)vec->iov_base + vec->iov_len, data->iov_base, data->iov_len);
	vec->iov_len += data->iov_len;
	return 1;
}