diff options
-rw-r--r-- | fs/nfsd/nfscache.c | 94 |
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 | ||
123 | static struct svc_cacherep * | 123 | static struct svc_cacherep * |
124 | nfsd_reply_cache_alloc(void) | 124 | nfsd_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 | ||
321 | static bool | 333 | static bool |
322 | nfsd_cache_match(struct svc_rqst *rqstp, __wsum csum, struct svc_cacherep *rp) | 334 | nfsd_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 | */ |
350 | static struct svc_cacherep * | 361 | static struct svc_cacherep * |
351 | nfsd_cache_search(struct nfsd_drc_bucket *b, struct svc_rqst *rqstp, | 362 | nfsd_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 | ||
453 | found_entry: | 448 | found_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; |