aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/nfscache.c94
1 files changed, 44 insertions, 50 deletions
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index cef4686f87ef..527ce4c65765 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -121,7 +121,7 @@ nfsd_cache_hash(__be32 xid)
121} 121}
122 122
123static struct svc_cacherep * 123static struct svc_cacherep *
124nfsd_reply_cache_alloc(void) 124nfsd_reply_cache_alloc(struct svc_rqst *rqstp, __wsum csum)
125{ 125{
126 struct svc_cacherep *rp; 126 struct svc_cacherep *rp;
127 127
@@ -130,6 +130,16 @@ nfsd_reply_cache_alloc(void)
130 rp->c_state = RC_UNUSED; 130 rp->c_state = RC_UNUSED;
131 rp->c_type = RC_NOCACHE; 131 rp->c_type = RC_NOCACHE;
132 INIT_LIST_HEAD(&rp->c_lru); 132 INIT_LIST_HEAD(&rp->c_lru);
133
134 rp->c_xid = rqstp->rq_xid;
135 rp->c_proc = rqstp->rq_proc;
136 memset(&rp->c_addr, 0, sizeof(rp->c_addr));
137 rpc_copy_addr((struct sockaddr *)&rp->c_addr, svc_addr(rqstp));
138 rpc_set_port((struct sockaddr *)&rp->c_addr, rpc_get_port(svc_addr(rqstp)));
139 rp->c_prot = rqstp->rq_prot;
140 rp->c_vers = rqstp->rq_vers;
141 rp->c_len = rqstp->rq_arg.len;
142 rp->c_csum = csum;
133 } 143 }
134 return rp; 144 return rp;
135} 145}
@@ -141,9 +151,11 @@ nfsd_reply_cache_free_locked(struct svc_cacherep *rp)
141 drc_mem_usage -= rp->c_replvec.iov_len; 151 drc_mem_usage -= rp->c_replvec.iov_len;
142 kfree(rp->c_replvec.iov_base); 152 kfree(rp->c_replvec.iov_base);
143 } 153 }
144 list_del(&rp->c_lru); 154 if (rp->c_state != RC_UNUSED) {
145 atomic_dec(&num_drc_entries); 155 list_del(&rp->c_lru);
146 drc_mem_usage -= sizeof(*rp); 156 atomic_dec(&num_drc_entries);
157 drc_mem_usage -= sizeof(*rp);
158 }
147 kmem_cache_free(drc_slab, rp); 159 kmem_cache_free(drc_slab, rp);
148} 160}
149 161
@@ -319,24 +331,23 @@ nfsd_cache_csum(struct svc_rqst *rqstp)
319} 331}
320 332
321static bool 333static bool
322nfsd_cache_match(struct svc_rqst *rqstp, __wsum csum, struct svc_cacherep *rp) 334nfsd_cache_match(const struct svc_cacherep *key, const struct svc_cacherep *rp)
323{ 335{
324 /* Check RPC XID first */ 336 /* Check RPC XID first */
325 if (rqstp->rq_xid != rp->c_xid) 337 if (key->c_xid != rp->c_xid)
326 return false; 338 return false;
327 /* compare checksum of NFS data */ 339 /* compare checksum of NFS data */
328 if (csum != rp->c_csum) { 340 if (key->c_csum != rp->c_csum) {
329 ++payload_misses; 341 ++payload_misses;
330 return false; 342 return false;
331 } 343 }
332 344
333 /* Other discriminators */ 345 /* Other discriminators */
334 if (rqstp->rq_proc != rp->c_proc || 346 if (key->c_proc != rp->c_proc ||
335 rqstp->rq_prot != rp->c_prot || 347 key->c_prot != rp->c_prot ||
336 rqstp->rq_vers != rp->c_vers || 348 key->c_vers != rp->c_vers ||
337 rqstp->rq_arg.len != rp->c_len || 349 key->c_len != rp->c_len ||
338 !rpc_cmp_addr(svc_addr(rqstp), (struct sockaddr *)&rp->c_addr) || 350 memcmp(&key->c_addr, &rp->c_addr, sizeof(key->c_addr)) != 0)
339 rpc_get_port(svc_addr(rqstp)) != rpc_get_port((struct sockaddr *)&rp->c_addr))
340 return false; 351 return false;
341 352
342 return true; 353 return true;
@@ -345,19 +356,18 @@ nfsd_cache_match(struct svc_rqst *rqstp, __wsum csum, struct svc_cacherep *rp)
345/* 356/*
346 * Search the request hash for an entry that matches the given rqstp. 357 * Search the request hash for an entry that matches the given rqstp.
347 * Must be called with cache_lock held. Returns the found entry or 358 * Must be called with cache_lock held. Returns the found entry or
348 * NULL on failure. 359 * inserts an empty key on failure.
349 */ 360 */
350static struct svc_cacherep * 361static struct svc_cacherep *
351nfsd_cache_search(struct nfsd_drc_bucket *b, struct svc_rqst *rqstp, 362nfsd_cache_insert(struct nfsd_drc_bucket *b, struct svc_cacherep *key)
352 __wsum csum)
353{ 363{
354 struct svc_cacherep *rp, *ret = NULL; 364 struct svc_cacherep *rp, *ret = key;
355 struct list_head *rh = &b->lru_head; 365 struct list_head *rh = &b->lru_head;
356 unsigned int entries = 0; 366 unsigned int entries = 0;
357 367
358 list_for_each_entry(rp, rh, c_lru) { 368 list_for_each_entry(rp, rh, c_lru) {
359 ++entries; 369 ++entries;
360 if (nfsd_cache_match(rqstp, csum, rp)) { 370 if (nfsd_cache_match(key, rp)) {
361 ret = rp; 371 ret = rp;
362 break; 372 break;
363 } 373 }
@@ -374,6 +384,7 @@ nfsd_cache_search(struct nfsd_drc_bucket *b, struct svc_rqst *rqstp,
374 atomic_read(&num_drc_entries)); 384 atomic_read(&num_drc_entries));
375 } 385 }
376 386
387 lru_put_end(b, ret);
377 return ret; 388 return ret;
378} 389}
379 390
@@ -389,9 +400,6 @@ nfsd_cache_lookup(struct svc_rqst *rqstp)
389{ 400{
390 struct svc_cacherep *rp, *found; 401 struct svc_cacherep *rp, *found;
391 __be32 xid = rqstp->rq_xid; 402 __be32 xid = rqstp->rq_xid;
392 u32 proto = rqstp->rq_prot,
393 vers = rqstp->rq_vers,
394 proc = rqstp->rq_proc;
395 __wsum csum; 403 __wsum csum;
396 u32 hash = nfsd_cache_hash(xid); 404 u32 hash = nfsd_cache_hash(xid);
397 struct nfsd_drc_bucket *b = &drc_hashtbl[hash]; 405 struct nfsd_drc_bucket *b = &drc_hashtbl[hash];
@@ -410,52 +418,38 @@ nfsd_cache_lookup(struct svc_rqst *rqstp)
410 * Since the common case is a cache miss followed by an insert, 418 * Since the common case is a cache miss followed by an insert,
411 * preallocate an entry. 419 * preallocate an entry.
412 */ 420 */
413 rp = nfsd_reply_cache_alloc(); 421 rp = nfsd_reply_cache_alloc(rqstp, csum);
414 spin_lock(&b->cache_lock); 422 if (!rp) {
415 if (likely(rp)) { 423 dprintk("nfsd: unable to allocate DRC entry!\n");
416 atomic_inc(&num_drc_entries); 424 return rtn;
417 drc_mem_usage += sizeof(*rp);
418 } 425 }
419 426
420 /* go ahead and prune the cache */ 427 spin_lock(&b->cache_lock);
421 prune_bucket(b); 428 found = nfsd_cache_insert(b, rp);
422 429 if (found != rp) {
423 found = nfsd_cache_search(b, rqstp, csum); 430 nfsd_reply_cache_free_locked(rp);
424 if (found) {
425 if (likely(rp))
426 nfsd_reply_cache_free_locked(rp);
427 rp = found; 431 rp = found;
428 goto found_entry; 432 goto found_entry;
429 } 433 }
430 434
431 if (!rp) {
432 dprintk("nfsd: unable to allocate DRC entry!\n");
433 goto out;
434 }
435
436 nfsdstats.rcmisses++; 435 nfsdstats.rcmisses++;
437 rqstp->rq_cacherep = rp; 436 rqstp->rq_cacherep = rp;
438 rp->c_state = RC_INPROG; 437 rp->c_state = RC_INPROG;
439 rp->c_xid = xid;
440 rp->c_proc = proc;
441 rpc_copy_addr((struct sockaddr *)&rp->c_addr, svc_addr(rqstp));
442 rpc_set_port((struct sockaddr *)&rp->c_addr, rpc_get_port(svc_addr(rqstp)));
443 rp->c_prot = proto;
444 rp->c_vers = vers;
445 rp->c_len = rqstp->rq_arg.len;
446 rp->c_csum = csum;
447 438
448 lru_put_end(b, rp); 439 atomic_inc(&num_drc_entries);
440 drc_mem_usage += sizeof(*rp);
441
442 /* go ahead and prune the cache */
443 prune_bucket(b);
449 out: 444 out:
450 spin_unlock(&b->cache_lock); 445 spin_unlock(&b->cache_lock);
451 return rtn; 446 return rtn;
452 447
453found_entry: 448found_entry:
454 nfsdstats.rchits++;
455 /* We found a matching entry which is either in progress or done. */ 449 /* We found a matching entry which is either in progress or done. */
456 lru_put_end(b, rp); 450 nfsdstats.rchits++;
457
458 rtn = RC_DROPIT; 451 rtn = RC_DROPIT;
452
459 /* Request being processed */ 453 /* Request being processed */
460 if (rp->c_state == RC_INPROG) 454 if (rp->c_state == RC_INPROG)
461 goto out; 455 goto out;