aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfscache.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2013-03-27 10:15:39 -0400
committerJ. Bruce Fields <bfields@redhat.com>2013-04-03 11:47:25 -0400
commit0733c7ba1ef0d7e29a11c52f4d1356fc394de334 (patch)
tree41fa9ac7a46d1f9d02286fffca90e333020997e3 /fs/nfsd/nfscache.c
parent98d821bda189ba2bfcb3877ea3064da3403698ae (diff)
nfsd: scale up the number of DRC hash buckets with cache size
We've now increased the size of the duplicate reply cache by quite a bit, but the number of hash buckets has not changed. So, we've gone from an average hash chain length of 16 in the old code to 4096 when the cache is its largest. Change the code to scale out the number of buckets with the max size of the cache. At the same time, we also need to fix the hash function since the existing one isn't really suitable when there are more than 256 buckets. Move instead to use the stock hash_32 function for this. Testing on a machine that had 2048 buckets showed that this gave a smaller longest:average ratio than the existing hash function: The formula here is longest hash bucket searched divided by average number of entries per bucket at the time that we saw that longest bucket: old hash: 68/(39258/2048) == 3.547404 hash_32: 45/(33773/2048) == 2.728807 Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfscache.c')
-rw-r--r--fs/nfsd/nfscache.c44
1 files changed, 29 insertions, 15 deletions
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 17cb0d6b9944..eb2587745a64 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -11,6 +11,8 @@
11#include <linux/slab.h> 11#include <linux/slab.h>
12#include <linux/sunrpc/addr.h> 12#include <linux/sunrpc/addr.h>
13#include <linux/highmem.h> 13#include <linux/highmem.h>
14#include <linux/log2.h>
15#include <linux/hash.h>
14#include <net/checksum.h> 16#include <net/checksum.h>
15 17
16#include "nfsd.h" 18#include "nfsd.h"
@@ -18,7 +20,12 @@
18 20
19#define NFSDDBG_FACILITY NFSDDBG_REPCACHE 21#define NFSDDBG_FACILITY NFSDDBG_REPCACHE
20 22
21#define HASHSIZE 64 23/*
24 * We use this value to determine the number of hash buckets from the max
25 * cache size, the idea being that when the cache is at its maximum number
26 * of entries, then this should be the average number of entries per bucket.
27 */
28#define TARGET_BUCKET_SIZE 64
22 29
23static struct hlist_head * cache_hash; 30static struct hlist_head * cache_hash;
24static struct list_head lru_head; 31static struct list_head lru_head;
@@ -27,6 +34,9 @@ static struct kmem_cache *drc_slab;
27/* max number of entries allowed in the cache */ 34/* max number of entries allowed in the cache */
28static unsigned int max_drc_entries; 35static unsigned int max_drc_entries;
29 36
37/* number of significant bits in the hash value */
38static unsigned int maskbits;
39
30/* 40/*
31 * Stats and other tracking of on the duplicate reply cache. All of these and 41 * Stats and other tracking of on the duplicate reply cache. All of these and
32 * the "rc" fields in nfsdstats are protected by the cache_lock 42 * the "rc" fields in nfsdstats are protected by the cache_lock
@@ -47,16 +57,6 @@ static unsigned int longest_chain;
47/* size of cache when we saw the longest hash chain */ 57/* size of cache when we saw the longest hash chain */
48static unsigned int longest_chain_cachesize; 58static unsigned int longest_chain_cachesize;
49 59
50/*
51 * Calculate the hash index from an XID.
52 */
53static inline u32 request_hash(u32 xid)
54{
55 u32 h = xid;
56 h ^= (xid >> 24);
57 return h & (HASHSIZE-1);
58}
59
60static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); 60static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
61static void cache_cleaner_func(struct work_struct *unused); 61static void cache_cleaner_func(struct work_struct *unused);
62static int nfsd_reply_cache_shrink(struct shrinker *shrink, 62static int nfsd_reply_cache_shrink(struct shrinker *shrink,
@@ -103,6 +103,16 @@ nfsd_cache_size_limit(void)
103 return min_t(unsigned int, limit, 256*1024); 103 return min_t(unsigned int, limit, 256*1024);
104} 104}
105 105
106/*
107 * Compute the number of hash buckets we need. Divide the max cachesize by
108 * the "target" max bucket size, and round up to next power of two.
109 */
110static unsigned int
111nfsd_hashsize(unsigned int limit)
112{
113 return roundup_pow_of_two(limit / TARGET_BUCKET_SIZE);
114}
115
106static struct svc_cacherep * 116static struct svc_cacherep *
107nfsd_reply_cache_alloc(void) 117nfsd_reply_cache_alloc(void)
108{ 118{
@@ -143,9 +153,13 @@ nfsd_reply_cache_free(struct svc_cacherep *rp)
143 153
144int nfsd_reply_cache_init(void) 154int nfsd_reply_cache_init(void)
145{ 155{
156 unsigned int hashsize;
157
146 INIT_LIST_HEAD(&lru_head); 158 INIT_LIST_HEAD(&lru_head);
147 max_drc_entries = nfsd_cache_size_limit(); 159 max_drc_entries = nfsd_cache_size_limit();
148 num_drc_entries = 0; 160 num_drc_entries = 0;
161 hashsize = nfsd_hashsize(max_drc_entries);
162 maskbits = ilog2(hashsize);
149 163
150 register_shrinker(&nfsd_reply_cache_shrinker); 164 register_shrinker(&nfsd_reply_cache_shrinker);
151 drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep), 165 drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep),
@@ -153,7 +167,7 @@ int nfsd_reply_cache_init(void)
153 if (!drc_slab) 167 if (!drc_slab)
154 goto out_nomem; 168 goto out_nomem;
155 169
156 cache_hash = kcalloc(HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); 170 cache_hash = kcalloc(hashsize, sizeof(struct hlist_head), GFP_KERNEL);
157 if (!cache_hash) 171 if (!cache_hash)
158 goto out_nomem; 172 goto out_nomem;
159 173
@@ -204,7 +218,7 @@ static void
204hash_refile(struct svc_cacherep *rp) 218hash_refile(struct svc_cacherep *rp)
205{ 219{
206 hlist_del_init(&rp->c_hash); 220 hlist_del_init(&rp->c_hash);
207 hlist_add_head(&rp->c_hash, cache_hash + request_hash(rp->c_xid)); 221 hlist_add_head(&rp->c_hash, cache_hash + hash_32(rp->c_xid, maskbits));
208} 222}
209 223
210static inline bool 224static inline bool
@@ -329,7 +343,7 @@ nfsd_cache_search(struct svc_rqst *rqstp, __wsum csum)
329 struct hlist_head *rh; 343 struct hlist_head *rh;
330 unsigned int entries = 0; 344 unsigned int entries = 0;
331 345
332 rh = &cache_hash[request_hash(rqstp->rq_xid)]; 346 rh = &cache_hash[hash_32(rqstp->rq_xid, maskbits)];
333 hlist_for_each_entry(rp, rh, c_hash) { 347 hlist_for_each_entry(rp, rh, c_hash) {
334 ++entries; 348 ++entries;
335 if (nfsd_cache_match(rqstp, csum, rp)) { 349 if (nfsd_cache_match(rqstp, csum, rp)) {
@@ -588,7 +602,7 @@ static int nfsd_reply_cache_stats_show(struct seq_file *m, void *v)
588 spin_lock(&cache_lock); 602 spin_lock(&cache_lock);
589 seq_printf(m, "max entries: %u\n", max_drc_entries); 603 seq_printf(m, "max entries: %u\n", max_drc_entries);
590 seq_printf(m, "num entries: %u\n", num_drc_entries); 604 seq_printf(m, "num entries: %u\n", num_drc_entries);
591 seq_printf(m, "hash buckets: %u\n", HASHSIZE); 605 seq_printf(m, "hash buckets: %u\n", 1 << maskbits);
592 seq_printf(m, "mem usage: %u\n", drc_mem_usage); 606 seq_printf(m, "mem usage: %u\n", drc_mem_usage);
593 seq_printf(m, "cache hits: %u\n", nfsdstats.rchits); 607 seq_printf(m, "cache hits: %u\n", nfsdstats.rchits);
594 seq_printf(m, "cache misses: %u\n", nfsdstats.rcmisses); 608 seq_printf(m, "cache misses: %u\n", nfsdstats.rcmisses);