Blame view
fs/nfsd/nfscache.c
15.3 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 7 8 9 |
* 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> */ |
5a0e3ad6a include cleanup: ... |
10 |
#include <linux/slab.h> |
5976687a2 sunrpc: move addr... |
11 |
#include <linux/sunrpc/addr.h> |
0338dd157 nfsd: dynamically... |
12 |
#include <linux/highmem.h> |
0733c7ba1 nfsd: scale up th... |
13 14 |
#include <linux/log2.h> #include <linux/hash.h> |
01a7decf7 nfsd: keep a chec... |
15 |
#include <net/checksum.h> |
5a0e3ad6a include cleanup: ... |
16 |
|
9a74af213 nfsd: Move privat... |
17 18 |
#include "nfsd.h" #include "cache.h" |
1da177e4c Linux-2.6.12-rc2 |
19 |
|
0338dd157 nfsd: dynamically... |
20 |
#define NFSDDBG_FACILITY NFSDDBG_REPCACHE |
0733c7ba1 nfsd: scale up th... |
21 22 23 24 25 26 |
/* * We use this value to determine the number of hash buckets from the max * cache size, the idea being that when the cache is at its maximum number * of entries, then this should be the average number of entries per bucket. */ #define TARGET_BUCKET_SIZE 64 |
1da177e4c Linux-2.6.12-rc2 |
27 |
|
7142b98d9 nfsd: Clean up dr... |
28 |
struct nfsd_drc_bucket { |
bedd4b61a nfsd: convert the... |
29 |
struct list_head lru_head; |
89a26b3d2 nfsd: split DRC g... |
30 |
spinlock_t cache_lock; |
7142b98d9 nfsd: Clean up dr... |
31 32 33 |
}; static struct nfsd_drc_bucket *drc_hashtbl; |
8a8bc40d9 nfsd: create a de... |
34 |
static struct kmem_cache *drc_slab; |
9dc56143c nfsd: break out c... |
35 36 |
/* max number of entries allowed in the cache */ |
0338dd157 nfsd: dynamically... |
37 |
static unsigned int max_drc_entries; |
1da177e4c Linux-2.6.12-rc2 |
38 |
|
0733c7ba1 nfsd: scale up th... |
39 40 |
/* number of significant bits in the hash value */ static unsigned int maskbits; |
bedd4b61a nfsd: convert the... |
41 |
static unsigned int drc_hashsize; |
0733c7ba1 nfsd: scale up th... |
42 |
|
fca4217c5 knfsd: reply cach... |
43 |
/* |
9dc56143c nfsd: break out c... |
44 45 46 47 48 |
* Stats and other tracking of on the duplicate reply cache. All of these and * the "rc" fields in nfsdstats are protected by the cache_lock */ /* total number of entries */ |
31e60f522 nfsd: convert num... |
49 |
static atomic_t num_drc_entries; |
9dc56143c nfsd: break out c... |
50 51 52 |
/* cache misses due only to checksum comparison failures */ static unsigned int payload_misses; |
6c6910cd4 nfsd: track memor... |
53 54 |
/* amount of memory (in bytes) currently consumed by the DRC */ static unsigned int drc_mem_usage; |
98d821bda nfsd: keep stats ... |
55 56 57 58 59 |
/* longest hash chain seen */ static unsigned int longest_chain; /* size of cache when we saw the longest hash chain */ static unsigned int longest_chain_cachesize; |
1da177e4c Linux-2.6.12-rc2 |
60 |
static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); |
1ab6c4997 fs: convert fs sh... |
61 62 63 64 |
static unsigned long nfsd_reply_cache_count(struct shrinker *shrink, struct shrink_control *sc); static unsigned long nfsd_reply_cache_scan(struct shrinker *shrink, struct shrink_control *sc); |
b4e7f2c94 nfsd: register a ... |
65 |
|
c8c797f9f nfsd: make symbol... |
66 |
static struct shrinker nfsd_reply_cache_shrinker = { |
1ab6c4997 fs: convert fs sh... |
67 68 |
.scan_objects = nfsd_reply_cache_scan, .count_objects = nfsd_reply_cache_count, |
b4e7f2c94 nfsd: register a ... |
69 70 |
.seeks = 1, }; |
1da177e4c Linux-2.6.12-rc2 |
71 |
|
fca4217c5 knfsd: reply cach... |
72 |
/* |
0338dd157 nfsd: dynamically... |
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
* 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); } |
0733c7ba1 nfsd: scale up th... |
99 100 101 102 103 104 105 106 107 |
/* * Compute the number of hash buckets we need. Divide the max cachesize by * the "target" max bucket size, and round up to next power of two. */ static unsigned int nfsd_hashsize(unsigned int limit) { return roundup_pow_of_two(limit / TARGET_BUCKET_SIZE); } |
7142b98d9 nfsd: Clean up dr... |
108 109 110 111 112 |
static u32 nfsd_cache_hash(__be32 xid) { return hash_32(be32_to_cpu(xid), maskbits); } |
f09841fdf nfsd: add alloc a... |
113 114 |
static struct svc_cacherep * nfsd_reply_cache_alloc(void) |
1da177e4c Linux-2.6.12-rc2 |
115 116 |
{ struct svc_cacherep *rp; |
1da177e4c Linux-2.6.12-rc2 |
117 |
|
f09841fdf nfsd: add alloc a... |
118 119 |
rp = kmem_cache_alloc(drc_slab, GFP_KERNEL); if (rp) { |
1da177e4c Linux-2.6.12-rc2 |
120 121 |
rp->c_state = RC_UNUSED; rp->c_type = RC_NOCACHE; |
f09841fdf nfsd: add alloc a... |
122 |
INIT_LIST_HEAD(&rp->c_lru); |
1da177e4c Linux-2.6.12-rc2 |
123 |
} |
f09841fdf nfsd: add alloc a... |
124 125 |
return rp; } |
1da177e4c Linux-2.6.12-rc2 |
126 |
|
f09841fdf nfsd: add alloc a... |
127 128 129 |
static void nfsd_reply_cache_free_locked(struct svc_cacherep *rp) { |
6c6910cd4 nfsd: track memor... |
130 131 |
if (rp->c_type == RC_REPLBUFF && rp->c_replvec.iov_base) { drc_mem_usage -= rp->c_replvec.iov_len; |
f09841fdf nfsd: add alloc a... |
132 |
kfree(rp->c_replvec.iov_base); |
6c6910cd4 nfsd: track memor... |
133 |
} |
f09841fdf nfsd: add alloc a... |
134 |
list_del(&rp->c_lru); |
31e60f522 nfsd: convert num... |
135 |
atomic_dec(&num_drc_entries); |
6c6910cd4 nfsd: track memor... |
136 |
drc_mem_usage -= sizeof(*rp); |
f09841fdf nfsd: add alloc a... |
137 138 |
kmem_cache_free(drc_slab, rp); } |
2c6b691c0 nfsd: when updati... |
139 |
static void |
89a26b3d2 nfsd: split DRC g... |
140 |
nfsd_reply_cache_free(struct nfsd_drc_bucket *b, struct svc_cacherep *rp) |
2c6b691c0 nfsd: when updati... |
141 |
{ |
89a26b3d2 nfsd: split DRC g... |
142 |
spin_lock(&b->cache_lock); |
2c6b691c0 nfsd: when updati... |
143 |
nfsd_reply_cache_free_locked(rp); |
89a26b3d2 nfsd: split DRC g... |
144 |
spin_unlock(&b->cache_lock); |
2c6b691c0 nfsd: when updati... |
145 |
} |
f09841fdf nfsd: add alloc a... |
146 147 |
int nfsd_reply_cache_init(void) { |
0733c7ba1 nfsd: scale up th... |
148 |
unsigned int hashsize; |
bedd4b61a nfsd: convert the... |
149 |
unsigned int i; |
a68465c9c NFSD: Error out w... |
150 |
int status = 0; |
0733c7ba1 nfsd: scale up th... |
151 |
|
ac534ff2d nfsd: fix startup... |
152 |
max_drc_entries = nfsd_cache_size_limit(); |
31e60f522 nfsd: convert num... |
153 |
atomic_set(&num_drc_entries, 0); |
0733c7ba1 nfsd: scale up th... |
154 155 |
hashsize = nfsd_hashsize(max_drc_entries); maskbits = ilog2(hashsize); |
ac534ff2d nfsd: fix startup... |
156 |
|
a68465c9c NFSD: Error out w... |
157 158 159 |
status = register_shrinker(&nfsd_reply_cache_shrinker); if (status) return status; |
8a8bc40d9 nfsd: create a de... |
160 161 162 163 |
drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep), 0, 0, NULL); if (!drc_slab) goto out_nomem; |
7142b98d9 nfsd: Clean up dr... |
164 165 |
drc_hashtbl = kcalloc(hashsize, sizeof(*drc_hashtbl), GFP_KERNEL); if (!drc_hashtbl) |
d5c3428b2 nfsd: fail module... |
166 |
goto out_nomem; |
89a26b3d2 nfsd: split DRC g... |
167 |
for (i = 0; i < hashsize; i++) { |
bedd4b61a nfsd: convert the... |
168 |
INIT_LIST_HEAD(&drc_hashtbl[i].lru_head); |
89a26b3d2 nfsd: split DRC g... |
169 170 |
spin_lock_init(&drc_hashtbl[i].cache_lock); } |
bedd4b61a nfsd: convert the... |
171 |
drc_hashsize = hashsize; |
1da177e4c Linux-2.6.12-rc2 |
172 |
|
d5c3428b2 nfsd: fail module... |
173 174 175 176 177 178 |
return 0; out_nomem: printk(KERN_ERR "nfsd: failed to allocate reply cache "); nfsd_reply_cache_shutdown(); return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
179 |
} |
d5c3428b2 nfsd: fail module... |
180 |
void nfsd_reply_cache_shutdown(void) |
1da177e4c Linux-2.6.12-rc2 |
181 182 |
{ struct svc_cacherep *rp; |
bedd4b61a nfsd: convert the... |
183 |
unsigned int i; |
1da177e4c Linux-2.6.12-rc2 |
184 |
|
b4e7f2c94 nfsd: register a ... |
185 |
unregister_shrinker(&nfsd_reply_cache_shrinker); |
aca8a23de nfsd: add recurri... |
186 |
|
bedd4b61a nfsd: convert the... |
187 188 189 190 191 192 |
for (i = 0; i < drc_hashsize; i++) { struct list_head *head = &drc_hashtbl[i].lru_head; while (!list_empty(head)) { rp = list_first_entry(head, struct svc_cacherep, c_lru); nfsd_reply_cache_free_locked(rp); } |
1da177e4c Linux-2.6.12-rc2 |
193 |
} |
7142b98d9 nfsd: Clean up dr... |
194 195 |
kfree (drc_hashtbl); drc_hashtbl = NULL; |
bedd4b61a nfsd: convert the... |
196 |
drc_hashsize = 0; |
8a8bc40d9 nfsd: create a de... |
197 |
|
e79017ddc nfsd: drop null t... |
198 199 |
kmem_cache_destroy(drc_slab); drc_slab = NULL; |
1da177e4c Linux-2.6.12-rc2 |
200 201 202 |
} /* |
aca8a23de nfsd: add recurri... |
203 204 |
* Move cache entry to end of LRU list, and queue the cleaner to run if it's * not already scheduled. |
1da177e4c Linux-2.6.12-rc2 |
205 206 |
*/ static void |
bedd4b61a nfsd: convert the... |
207 |
lru_put_end(struct nfsd_drc_bucket *b, struct svc_cacherep *rp) |
1da177e4c Linux-2.6.12-rc2 |
208 |
{ |
56c2548b2 nfsd: always move... |
209 |
rp->c_timestamp = jiffies; |
bedd4b61a nfsd: convert the... |
210 |
list_move_tail(&rp->c_lru, &b->lru_head); |
1da177e4c Linux-2.6.12-rc2 |
211 |
} |
1ab6c4997 fs: convert fs sh... |
212 |
static long |
bedd4b61a nfsd: convert the... |
213 |
prune_bucket(struct nfsd_drc_bucket *b) |
aca8a23de nfsd: add recurri... |
214 215 |
{ struct svc_cacherep *rp, *tmp; |
1ab6c4997 fs: convert fs sh... |
216 |
long freed = 0; |
aca8a23de nfsd: add recurri... |
217 |
|
bedd4b61a nfsd: convert the... |
218 |
list_for_each_entry_safe(rp, tmp, &b->lru_head, c_lru) { |
1b19453d1 nfsd: don't halt ... |
219 220 221 222 223 224 |
/* * Don't free entries attached to calls that are still * in-progress, but do keep scanning the list. */ if (rp->c_state == RC_INPROG) continue; |
31e60f522 nfsd: convert num... |
225 |
if (atomic_read(&num_drc_entries) <= max_drc_entries && |
1b19453d1 nfsd: don't halt ... |
226 |
time_before(jiffies, rp->c_timestamp + RC_EXPIRE)) |
aca8a23de nfsd: add recurri... |
227 228 |
break; nfsd_reply_cache_free_locked(rp); |
1ab6c4997 fs: convert fs sh... |
229 |
freed++; |
aca8a23de nfsd: add recurri... |
230 |
} |
bedd4b61a nfsd: convert the... |
231 232 233 234 235 236 237 238 239 240 241 242 |
return freed; } /* * 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 long prune_cache_entries(void) { unsigned int i; long freed = 0; |
bedd4b61a nfsd: convert the... |
243 244 245 |
for (i = 0; i < drc_hashsize; i++) { struct nfsd_drc_bucket *b = &drc_hashtbl[i]; |
89a26b3d2 nfsd: split DRC g... |
246 247 248 |
if (list_empty(&b->lru_head)) continue; spin_lock(&b->cache_lock); |
bedd4b61a nfsd: convert the... |
249 |
freed += prune_bucket(b); |
89a26b3d2 nfsd: split DRC g... |
250 |
spin_unlock(&b->cache_lock); |
bedd4b61a nfsd: convert the... |
251 |
} |
1ab6c4997 fs: convert fs sh... |
252 |
return freed; |
aca8a23de nfsd: add recurri... |
253 |
} |
1ab6c4997 fs: convert fs sh... |
254 255 |
static unsigned long nfsd_reply_cache_count(struct shrinker *shrink, struct shrink_control *sc) |
b4e7f2c94 nfsd: register a ... |
256 |
{ |
31e60f522 nfsd: convert num... |
257 |
return atomic_read(&num_drc_entries); |
b4e7f2c94 nfsd: register a ... |
258 |
} |
1ab6c4997 fs: convert fs sh... |
259 260 261 |
static unsigned long nfsd_reply_cache_scan(struct shrinker *shrink, struct shrink_control *sc) { |
89a26b3d2 nfsd: split DRC g... |
262 |
return prune_cache_entries(); |
1ab6c4997 fs: convert fs sh... |
263 |
} |
aca8a23de nfsd: add recurri... |
264 |
/* |
01a7decf7 nfsd: keep a chec... |
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
* 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; |
56edc86b5 nfsd: fix compile... |
288 |
len = min_t(size_t, PAGE_SIZE - base, csum_len); |
01a7decf7 nfsd: keep a chec... |
289 290 291 292 293 294 295 |
csum = csum_partial(p, len, csum); csum_len -= len; base = 0; ++idx; } return csum; } |
9dc56143c nfsd: break out c... |
296 297 298 |
static bool nfsd_cache_match(struct svc_rqst *rqstp, __wsum csum, struct svc_cacherep *rp) { |
ef9b16dc6 nfsd: Reorder nfs... |
299 300 |
/* Check RPC XID first */ if (rqstp->rq_xid != rp->c_xid) |
9dc56143c nfsd: break out c... |
301 |
return false; |
9dc56143c nfsd: break out c... |
302 303 304 305 306 |
/* compare checksum of NFS data */ if (csum != rp->c_csum) { ++payload_misses; return false; } |
ef9b16dc6 nfsd: Reorder nfs... |
307 308 309 310 311 312 313 314 |
/* Other discriminators */ if (rqstp->rq_proc != rp->c_proc || rqstp->rq_prot != rp->c_prot || rqstp->rq_vers != rp->c_vers || rqstp->rq_arg.len != rp->c_len || !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 false; |
9dc56143c nfsd: break out c... |
315 316 |
return true; } |
01a7decf7 nfsd: keep a chec... |
317 |
/* |
a4a3ec329 nfsd: break out h... |
318 319 320 321 322 |
* 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 * |
7142b98d9 nfsd: Clean up dr... |
323 324 |
nfsd_cache_search(struct nfsd_drc_bucket *b, struct svc_rqst *rqstp, __wsum csum) |
a4a3ec329 nfsd: break out h... |
325 |
{ |
98d821bda nfsd: keep stats ... |
326 |
struct svc_cacherep *rp, *ret = NULL; |
11acf6ef3 nfsd: Remove the ... |
327 |
struct list_head *rh = &b->lru_head; |
98d821bda nfsd: keep stats ... |
328 |
unsigned int entries = 0; |
a4a3ec329 nfsd: break out h... |
329 |
|
11acf6ef3 nfsd: Remove the ... |
330 |
list_for_each_entry(rp, rh, c_lru) { |
98d821bda nfsd: keep stats ... |
331 332 333 334 335 336 337 338 339 340 |
++entries; if (nfsd_cache_match(rqstp, csum, rp)) { ret = rp; break; } } /* tally hash chain length stats */ if (entries > longest_chain) { longest_chain = entries; |
31e60f522 nfsd: convert num... |
341 |
longest_chain_cachesize = atomic_read(&num_drc_entries); |
98d821bda nfsd: keep stats ... |
342 343 |
} else if (entries == longest_chain) { /* prefer to keep the smallest cachesize possible here */ |
31e60f522 nfsd: convert num... |
344 345 346 |
longest_chain_cachesize = min_t(unsigned int, longest_chain_cachesize, atomic_read(&num_drc_entries)); |
a4a3ec329 nfsd: break out h... |
347 |
} |
98d821bda nfsd: keep stats ... |
348 349 |
return ret; |
a4a3ec329 nfsd: break out h... |
350 |
} |
1da177e4c Linux-2.6.12-rc2 |
351 352 |
/* * Try to find an entry matching the current call in the cache. When none |
1ac836297 nfsd: fix comment... |
353 354 355 356 |
* 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. |
1da177e4c Linux-2.6.12-rc2 |
357 358 |
*/ int |
1091006c5 nfsd: turn on rep... |
359 |
nfsd_cache_lookup(struct svc_rqst *rqstp) |
1da177e4c Linux-2.6.12-rc2 |
360 |
{ |
0338dd157 nfsd: dynamically... |
361 |
struct svc_cacherep *rp, *found; |
c7afef1f9 [PATCH] nfsd: mis... |
362 363 |
__be32 xid = rqstp->rq_xid; u32 proto = rqstp->rq_prot, |
1da177e4c Linux-2.6.12-rc2 |
364 365 |
vers = rqstp->rq_vers, proc = rqstp->rq_proc; |
01a7decf7 nfsd: keep a chec... |
366 |
__wsum csum; |
7142b98d9 nfsd: Clean up dr... |
367 368 |
u32 hash = nfsd_cache_hash(xid); struct nfsd_drc_bucket *b = &drc_hashtbl[hash]; |
1da177e4c Linux-2.6.12-rc2 |
369 |
unsigned long age; |
1091006c5 nfsd: turn on rep... |
370 |
int type = rqstp->rq_cachetype; |
0b9ea37f2 nfsd: eliminate o... |
371 |
int rtn = RC_DOIT; |
1da177e4c Linux-2.6.12-rc2 |
372 373 |
rqstp->rq_cacherep = NULL; |
13cc8a78e nfsd: remove the ... |
374 |
if (type == RC_NOCACHE) { |
1da177e4c Linux-2.6.12-rc2 |
375 |
nfsdstats.rcnocache++; |
0b9ea37f2 nfsd: eliminate o... |
376 |
return rtn; |
1da177e4c Linux-2.6.12-rc2 |
377 |
} |
01a7decf7 nfsd: keep a chec... |
378 |
csum = nfsd_cache_csum(rqstp); |
0b9ea37f2 nfsd: eliminate o... |
379 380 |
/* * Since the common case is a cache miss followed by an insert, |
a0ef5e196 nfsd: don't try t... |
381 |
* preallocate an entry. |
0b9ea37f2 nfsd: eliminate o... |
382 |
*/ |
0338dd157 nfsd: dynamically... |
383 |
rp = nfsd_reply_cache_alloc(); |
89a26b3d2 nfsd: split DRC g... |
384 |
spin_lock(&b->cache_lock); |
6c6910cd4 nfsd: track memor... |
385 |
if (likely(rp)) { |
31e60f522 nfsd: convert num... |
386 |
atomic_inc(&num_drc_entries); |
6c6910cd4 nfsd: track memor... |
387 388 |
drc_mem_usage += sizeof(*rp); } |
0338dd157 nfsd: dynamically... |
389 |
|
a0ef5e196 nfsd: don't try t... |
390 |
/* go ahead and prune the cache */ |
89a26b3d2 nfsd: split DRC g... |
391 |
prune_bucket(b); |
a0ef5e196 nfsd: don't try t... |
392 |
|
7142b98d9 nfsd: Clean up dr... |
393 |
found = nfsd_cache_search(b, rqstp, csum); |
0338dd157 nfsd: dynamically... |
394 |
if (found) { |
0b9ea37f2 nfsd: eliminate o... |
395 396 |
if (likely(rp)) nfsd_reply_cache_free_locked(rp); |
0338dd157 nfsd: dynamically... |
397 398 |
rp = found; goto found_entry; |
1da177e4c Linux-2.6.12-rc2 |
399 |
} |
0b9ea37f2 nfsd: eliminate o... |
400 401 402 403 404 |
if (!rp) { dprintk("nfsd: unable to allocate DRC entry! "); goto out; } |
0338dd157 nfsd: dynamically... |
405 |
nfsdstats.rcmisses++; |
1da177e4c Linux-2.6.12-rc2 |
406 407 408 409 |
rqstp->rq_cacherep = rp; rp->c_state = RC_INPROG; rp->c_xid = xid; rp->c_proc = proc; |
7b9e8522a nfsd: fix IPv6 ad... |
410 411 |
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))); |
1da177e4c Linux-2.6.12-rc2 |
412 413 |
rp->c_prot = proto; rp->c_vers = vers; |
01a7decf7 nfsd: keep a chec... |
414 415 |
rp->c_len = rqstp->rq_arg.len; rp->c_csum = csum; |
1da177e4c Linux-2.6.12-rc2 |
416 |
|
bedd4b61a nfsd: convert the... |
417 |
lru_put_end(b, rp); |
1da177e4c Linux-2.6.12-rc2 |
418 419 420 |
/* release any buffer */ if (rp->c_type == RC_REPLBUFF) { |
6c6910cd4 nfsd: track memor... |
421 |
drc_mem_usage -= rp->c_replvec.iov_len; |
1da177e4c Linux-2.6.12-rc2 |
422 423 424 425 426 |
kfree(rp->c_replvec.iov_base); rp->c_replvec.iov_base = NULL; } rp->c_type = RC_NOCACHE; out: |
89a26b3d2 nfsd: split DRC g... |
427 |
spin_unlock(&b->cache_lock); |
1da177e4c Linux-2.6.12-rc2 |
428 429 430 |
return rtn; found_entry: |
0338dd157 nfsd: dynamically... |
431 |
nfsdstats.rchits++; |
1da177e4c Linux-2.6.12-rc2 |
432 433 |
/* We found a matching entry which is either in progress or done. */ age = jiffies - rp->c_timestamp; |
bedd4b61a nfsd: convert the... |
434 |
lru_put_end(b, rp); |
1da177e4c Linux-2.6.12-rc2 |
435 436 437 438 439 440 441 442 443 |
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; |
4d152e2c9 sunrpc: add a gen... |
444 |
if (!test_bit(RQ_SECURE, &rqstp->rq_flags) && rp->c_secure) |
1da177e4c Linux-2.6.12-rc2 |
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
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 ", rp->c_type); |
0338dd157 nfsd: dynamically... |
463 |
nfsd_reply_cache_free_locked(rp); |
1da177e4c Linux-2.6.12-rc2 |
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 |
} 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 |
c7afef1f9 [PATCH] nfsd: mis... |
486 |
nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) |
1da177e4c Linux-2.6.12-rc2 |
487 |
{ |
13cc8a78e nfsd: remove the ... |
488 |
struct svc_cacherep *rp = rqstp->rq_cacherep; |
1da177e4c Linux-2.6.12-rc2 |
489 |
struct kvec *resv = &rqstp->rq_res.head[0], *cachv; |
bedd4b61a nfsd: convert the... |
490 491 |
u32 hash; struct nfsd_drc_bucket *b; |
1da177e4c Linux-2.6.12-rc2 |
492 |
int len; |
6c6910cd4 nfsd: track memor... |
493 |
size_t bufsize = 0; |
1da177e4c Linux-2.6.12-rc2 |
494 |
|
13cc8a78e nfsd: remove the ... |
495 |
if (!rp) |
1da177e4c Linux-2.6.12-rc2 |
496 |
return; |
bedd4b61a nfsd: convert the... |
497 498 |
hash = nfsd_cache_hash(rp->c_xid); b = &drc_hashtbl[hash]; |
1da177e4c Linux-2.6.12-rc2 |
499 500 |
len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); len >>= 2; |
fca4217c5 knfsd: reply cach... |
501 |
|
1da177e4c Linux-2.6.12-rc2 |
502 503 |
/* Don't cache excessive amounts of data and XDR failures */ if (!statp || len > (256 >> 2)) { |
89a26b3d2 nfsd: split DRC g... |
504 |
nfsd_reply_cache_free(b, rp); |
1da177e4c Linux-2.6.12-rc2 |
505 506 507 508 509 510 511 512 513 514 515 516 |
return; } switch (cachetype) { case RC_REPLSTAT: if (len != 1) printk("nfsd: RC_REPLSTAT/reply len %d! ",len); rp->c_replstat = *statp; break; case RC_REPLBUFF: cachv = &rp->c_replvec; |
6c6910cd4 nfsd: track memor... |
517 518 |
bufsize = len << 2; cachv->iov_base = kmalloc(bufsize, GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
519 |
if (!cachv->iov_base) { |
89a26b3d2 nfsd: split DRC g... |
520 |
nfsd_reply_cache_free(b, rp); |
1da177e4c Linux-2.6.12-rc2 |
521 522 |
return; } |
6c6910cd4 nfsd: track memor... |
523 524 |
cachv->iov_len = bufsize; memcpy(cachv->iov_base, statp, bufsize); |
1da177e4c Linux-2.6.12-rc2 |
525 |
break; |
2c6b691c0 nfsd: when updati... |
526 |
case RC_NOCACHE: |
89a26b3d2 nfsd: split DRC g... |
527 |
nfsd_reply_cache_free(b, rp); |
2c6b691c0 nfsd: when updati... |
528 |
return; |
1da177e4c Linux-2.6.12-rc2 |
529 |
} |
89a26b3d2 nfsd: split DRC g... |
530 |
spin_lock(&b->cache_lock); |
6c6910cd4 nfsd: track memor... |
531 |
drc_mem_usage += bufsize; |
bedd4b61a nfsd: convert the... |
532 |
lru_put_end(b, rp); |
4d152e2c9 sunrpc: add a gen... |
533 |
rp->c_secure = test_bit(RQ_SECURE, &rqstp->rq_flags); |
1da177e4c Linux-2.6.12-rc2 |
534 535 |
rp->c_type = cachetype; rp->c_state = RC_DONE; |
89a26b3d2 nfsd: split DRC g... |
536 |
spin_unlock(&b->cache_lock); |
1da177e4c Linux-2.6.12-rc2 |
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 |
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). ", 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; } |
a2f999a37 nfsd: add new rep... |
560 561 562 563 564 565 566 567 |
/* * Note that fields may be added, removed or reordered in the future. Programs * scraping this file for info should test the labels to ensure they're * getting the correct field. */ static int nfsd_reply_cache_stats_show(struct seq_file *m, void *v) { |
a2f999a37 nfsd: add new rep... |
568 569 |
seq_printf(m, "max entries: %u ", max_drc_entries); |
31e60f522 nfsd: convert num... |
570 571 572 |
seq_printf(m, "num entries: %u ", atomic_read(&num_drc_entries)); |
0733c7ba1 nfsd: scale up th... |
573 574 |
seq_printf(m, "hash buckets: %u ", 1 << maskbits); |
a2f999a37 nfsd: add new rep... |
575 576 577 578 579 580 581 582 583 584 |
seq_printf(m, "mem usage: %u ", drc_mem_usage); seq_printf(m, "cache hits: %u ", nfsdstats.rchits); seq_printf(m, "cache misses: %u ", nfsdstats.rcmisses); seq_printf(m, "not cached: %u ", nfsdstats.rcnocache); seq_printf(m, "payload misses: %u ", payload_misses); |
98d821bda nfsd: keep stats ... |
585 586 587 588 |
seq_printf(m, "longest chain len: %u ", longest_chain); seq_printf(m, "cachesize at longest: %u ", longest_chain_cachesize); |
a2f999a37 nfsd: add new rep... |
589 590 591 592 593 594 595 |
return 0; } int nfsd_reply_cache_stats_open(struct inode *inode, struct file *file) { return single_open(file, nfsd_reply_cache_stats_show, NULL); } |