aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trondmy@gmail.com>2018-10-01 10:41:57 -0400
committerJ. Bruce Fields <bfields@redhat.com>2018-10-29 16:58:04 -0400
commit736c6625de666f3fd0b47428f10568154033151a (patch)
treee31ce544fa5a48126213abf0834e064a5c642435
parented00c2f65267f3a5a8727ac74a90d32470f91679 (diff)
knfsd: Improve lookup performance in the duplicate reply cache using an rbtree
Use an rbtree to ensure the lookup/insert of an entry in a DRC bucket is O(log(N)). Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/cache.h1
-rw-r--r--fs/nfsd/nfscache.c37
2 files changed, 27 insertions, 11 deletions
diff --git a/fs/nfsd/cache.h b/fs/nfsd/cache.h
index 745c861237ca..4a98537efb0f 100644
--- a/fs/nfsd/cache.h
+++ b/fs/nfsd/cache.h
@@ -30,6 +30,7 @@ struct svc_cacherep {
30 struct sockaddr_in6 k_addr; 30 struct sockaddr_in6 k_addr;
31 } c_key; 31 } c_key;
32 32
33 struct rb_node c_node;
33 struct list_head c_lru; 34 struct list_head c_lru;
34 unsigned char c_state, /* unused, inprog, done */ 35 unsigned char c_state, /* unused, inprog, done */
35 c_type, /* status, buffer */ 36 c_type, /* status, buffer */
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 230cc83921ad..e2fe0e9ce0df 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -30,6 +30,7 @@
30#define TARGET_BUCKET_SIZE 64 30#define TARGET_BUCKET_SIZE 64
31 31
32struct nfsd_drc_bucket { 32struct nfsd_drc_bucket {
33 struct rb_root rb_head;
33 struct list_head lru_head; 34 struct list_head lru_head;
34 spinlock_t cache_lock; 35 spinlock_t cache_lock;
35}; 36};
@@ -129,6 +130,7 @@ nfsd_reply_cache_alloc(struct svc_rqst *rqstp, __wsum csum)
129 if (rp) { 130 if (rp) {
130 rp->c_state = RC_UNUSED; 131 rp->c_state = RC_UNUSED;
131 rp->c_type = RC_NOCACHE; 132 rp->c_type = RC_NOCACHE;
133 RB_CLEAR_NODE(&rp->c_node);
132 INIT_LIST_HEAD(&rp->c_lru); 134 INIT_LIST_HEAD(&rp->c_lru);
133 135
134 memset(&rp->c_key, 0, sizeof(rp->c_key)); 136 memset(&rp->c_key, 0, sizeof(rp->c_key));
@@ -145,13 +147,14 @@ nfsd_reply_cache_alloc(struct svc_rqst *rqstp, __wsum csum)
145} 147}
146 148
147static void 149static void
148nfsd_reply_cache_free_locked(struct svc_cacherep *rp) 150nfsd_reply_cache_free_locked(struct nfsd_drc_bucket *b, struct svc_cacherep *rp)
149{ 151{
150 if (rp->c_type == RC_REPLBUFF && rp->c_replvec.iov_base) { 152 if (rp->c_type == RC_REPLBUFF && rp->c_replvec.iov_base) {
151 drc_mem_usage -= rp->c_replvec.iov_len; 153 drc_mem_usage -= rp->c_replvec.iov_len;
152 kfree(rp->c_replvec.iov_base); 154 kfree(rp->c_replvec.iov_base);
153 } 155 }
154 if (rp->c_state != RC_UNUSED) { 156 if (rp->c_state != RC_UNUSED) {
157 rb_erase(&rp->c_node, &b->rb_head);
155 list_del(&rp->c_lru); 158 list_del(&rp->c_lru);
156 atomic_dec(&num_drc_entries); 159 atomic_dec(&num_drc_entries);
157 drc_mem_usage -= sizeof(*rp); 160 drc_mem_usage -= sizeof(*rp);
@@ -163,7 +166,7 @@ static void
163nfsd_reply_cache_free(struct nfsd_drc_bucket *b, struct svc_cacherep *rp) 166nfsd_reply_cache_free(struct nfsd_drc_bucket *b, struct svc_cacherep *rp)
164{ 167{
165 spin_lock(&b->cache_lock); 168 spin_lock(&b->cache_lock);
166 nfsd_reply_cache_free_locked(rp); 169 nfsd_reply_cache_free_locked(b, rp);
167 spin_unlock(&b->cache_lock); 170 spin_unlock(&b->cache_lock);
168} 171}
169 172
@@ -219,7 +222,7 @@ void nfsd_reply_cache_shutdown(void)
219 struct list_head *head = &drc_hashtbl[i].lru_head; 222 struct list_head *head = &drc_hashtbl[i].lru_head;
220 while (!list_empty(head)) { 223 while (!list_empty(head)) {
221 rp = list_first_entry(head, struct svc_cacherep, c_lru); 224 rp = list_first_entry(head, struct svc_cacherep, c_lru);
222 nfsd_reply_cache_free_locked(rp); 225 nfsd_reply_cache_free_locked(&drc_hashtbl[i], rp);
223 } 226 }
224 } 227 }
225 228
@@ -258,7 +261,7 @@ prune_bucket(struct nfsd_drc_bucket *b)
258 if (atomic_read(&num_drc_entries) <= max_drc_entries && 261 if (atomic_read(&num_drc_entries) <= max_drc_entries &&
259 time_before(jiffies, rp->c_timestamp + RC_EXPIRE)) 262 time_before(jiffies, rp->c_timestamp + RC_EXPIRE))
260 break; 263 break;
261 nfsd_reply_cache_free_locked(rp); 264 nfsd_reply_cache_free_locked(b, rp);
262 freed++; 265 freed++;
263 } 266 }
264 return freed; 267 return freed;
@@ -349,17 +352,29 @@ static struct svc_cacherep *
349nfsd_cache_insert(struct nfsd_drc_bucket *b, struct svc_cacherep *key) 352nfsd_cache_insert(struct nfsd_drc_bucket *b, struct svc_cacherep *key)
350{ 353{
351 struct svc_cacherep *rp, *ret = key; 354 struct svc_cacherep *rp, *ret = key;
352 struct list_head *rh = &b->lru_head; 355 struct rb_node **p = &b->rb_head.rb_node,
356 *parent = NULL;
353 unsigned int entries = 0; 357 unsigned int entries = 0;
358 int cmp;
354 359
355 list_for_each_entry(rp, rh, c_lru) { 360 while (*p != NULL) {
356 ++entries; 361 ++entries;
357 if (nfsd_cache_key_cmp(key, rp) == 0) { 362 parent = *p;
363 rp = rb_entry(parent, struct svc_cacherep, c_node);
364
365 cmp = nfsd_cache_key_cmp(key, rp);
366 if (cmp < 0)
367 p = &parent->rb_left;
368 else if (cmp > 0)
369 p = &parent->rb_right;
370 else {
358 ret = rp; 371 ret = rp;
359 break; 372 goto out;
360 } 373 }
361 } 374 }
362 375 rb_link_node(&key->c_node, parent, p);
376 rb_insert_color(&key->c_node, &b->rb_head);
377out:
363 /* tally hash chain length stats */ 378 /* tally hash chain length stats */
364 if (entries > longest_chain) { 379 if (entries > longest_chain) {
365 longest_chain = entries; 380 longest_chain = entries;
@@ -414,7 +429,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp)
414 spin_lock(&b->cache_lock); 429 spin_lock(&b->cache_lock);
415 found = nfsd_cache_insert(b, rp); 430 found = nfsd_cache_insert(b, rp);
416 if (found != rp) { 431 if (found != rp) {
417 nfsd_reply_cache_free_locked(rp); 432 nfsd_reply_cache_free_locked(NULL, rp);
418 rp = found; 433 rp = found;
419 goto found_entry; 434 goto found_entry;
420 } 435 }
@@ -462,7 +477,7 @@ found_entry:
462 break; 477 break;
463 default: 478 default:
464 printk(KERN_WARNING "nfsd: bad repcache type %d\n", rp->c_type); 479 printk(KERN_WARNING "nfsd: bad repcache type %d\n", rp->c_type);
465 nfsd_reply_cache_free_locked(rp); 480 nfsd_reply_cache_free_locked(b, rp);
466 } 481 }
467 482
468 goto out; 483 goto out;