Skip to content

Commit 736c662

Browse files
trondmyJ. Bruce Fields
authored andcommitted
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>
1 parent ed00c2f commit 736c662

File tree

2 files changed

+27
-11
lines changed

2 files changed

+27
-11
lines changed

fs/nfsd/cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct svc_cacherep {
3030
struct sockaddr_in6 k_addr;
3131
} c_key;
3232

33+
struct rb_node c_node;
3334
struct list_head c_lru;
3435
unsigned char c_state, /* unused, inprog, done */
3536
c_type, /* status, buffer */

fs/nfsd/nfscache.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#define TARGET_BUCKET_SIZE 64
3131

3232
struct nfsd_drc_bucket {
33+
struct rb_root rb_head;
3334
struct list_head lru_head;
3435
spinlock_t cache_lock;
3536
};
@@ -129,6 +130,7 @@ nfsd_reply_cache_alloc(struct svc_rqst *rqstp, __wsum csum)
129130
if (rp) {
130131
rp->c_state = RC_UNUSED;
131132
rp->c_type = RC_NOCACHE;
133+
RB_CLEAR_NODE(&rp->c_node);
132134
INIT_LIST_HEAD(&rp->c_lru);
133135

134136
memset(&rp->c_key, 0, sizeof(rp->c_key));
@@ -145,13 +147,14 @@ nfsd_reply_cache_alloc(struct svc_rqst *rqstp, __wsum csum)
145147
}
146148

147149
static void
148-
nfsd_reply_cache_free_locked(struct svc_cacherep *rp)
150+
nfsd_reply_cache_free_locked(struct nfsd_drc_bucket *b, struct svc_cacherep *rp)
149151
{
150152
if (rp->c_type == RC_REPLBUFF && rp->c_replvec.iov_base) {
151153
drc_mem_usage -= rp->c_replvec.iov_len;
152154
kfree(rp->c_replvec.iov_base);
153155
}
154156
if (rp->c_state != RC_UNUSED) {
157+
rb_erase(&rp->c_node, &b->rb_head);
155158
list_del(&rp->c_lru);
156159
atomic_dec(&num_drc_entries);
157160
drc_mem_usage -= sizeof(*rp);
@@ -163,7 +166,7 @@ static void
163166
nfsd_reply_cache_free(struct nfsd_drc_bucket *b, struct svc_cacherep *rp)
164167
{
165168
spin_lock(&b->cache_lock);
166-
nfsd_reply_cache_free_locked(rp);
169+
nfsd_reply_cache_free_locked(b, rp);
167170
spin_unlock(&b->cache_lock);
168171
}
169172

@@ -219,7 +222,7 @@ void nfsd_reply_cache_shutdown(void)
219222
struct list_head *head = &drc_hashtbl[i].lru_head;
220223
while (!list_empty(head)) {
221224
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);
223226
}
224227
}
225228

@@ -258,7 +261,7 @@ prune_bucket(struct nfsd_drc_bucket *b)
258261
if (atomic_read(&num_drc_entries) <= max_drc_entries &&
259262
time_before(jiffies, rp->c_timestamp + RC_EXPIRE))
260263
break;
261-
nfsd_reply_cache_free_locked(rp);
264+
nfsd_reply_cache_free_locked(b, rp);
262265
freed++;
263266
}
264267
return freed;
@@ -349,17 +352,29 @@ static struct svc_cacherep *
349352
nfsd_cache_insert(struct nfsd_drc_bucket *b, struct svc_cacherep *key)
350353
{
351354
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;
353357
unsigned int entries = 0;
358+
int cmp;
354359

355-
list_for_each_entry(rp, rh, c_lru) {
360+
while (*p != NULL) {
356361
++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 {
358371
ret = rp;
359-
break;
372+
goto out;
360373
}
361374
}
362-
375+
rb_link_node(&key->c_node, parent, p);
376+
rb_insert_color(&key->c_node, &b->rb_head);
377+
out:
363378
/* tally hash chain length stats */
364379
if (entries > longest_chain) {
365380
longest_chain = entries;
@@ -414,7 +429,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp)
414429
spin_lock(&b->cache_lock);
415430
found = nfsd_cache_insert(b, rp);
416431
if (found != rp) {
417-
nfsd_reply_cache_free_locked(rp);
432+
nfsd_reply_cache_free_locked(NULL, rp);
418433
rp = found;
419434
goto found_entry;
420435
}
@@ -462,7 +477,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp)
462477
break;
463478
default:
464479
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);
466481
}
467482

468483
goto out;

0 commit comments

Comments
 (0)