Skip to content

Commit 8847ecc

Browse files
chuckleverJ. Bruce Fields
authored andcommitted
NFSD: Optimize DRC bucket pruning
DRC bucket pruning is done by nfsd_cache_lookup(), which is part of every NFSv2 and NFSv3 dispatch (ie, it's done while the client is waiting). I added a trace_printk() in prune_bucket() to see just how long it takes to prune. Here are two ends of the spectrum: prune_bucket: Scanned 1 and freed 0 in 90 ns, 62 entries remaining prune_bucket: Scanned 2 and freed 1 in 716 ns, 63 entries remaining ... prune_bucket: Scanned 75 and freed 74 in 34149 ns, 1 entries remaining Pruning latency is noticeable on fast transports with fast storage. By noticeable, I mean that the latency measured here in the worst case is the same order of magnitude as the round trip time for cached server operations. We could do something like moving expired entries to an expired list and then free them later instead of freeing them right in prune_bucket(). But simply limiting the number of entries that can be pruned by a lookup is simple and retains more entries in the cache, making the DRC somewhat more effective. Comparison with a 70/30 fio 8KB 12 thread direct I/O test: Before: write: IOPS=61.6k, BW=481MiB/s (505MB/s)(14.1GiB/30001msec); 0 zone resets WRITE: 1848726 ops (30%) avg bytes sent per op: 8340 avg bytes received per op: 136 backlog wait: 0.635158 RTT: 0.128525 total execute time: 0.827242 (milliseconds) After: write: IOPS=63.0k, BW=492MiB/s (516MB/s)(14.4GiB/30001msec); 0 zone resets WRITE: 1891144 ops (30%) avg bytes sent per op: 8340 avg bytes received per op: 136 backlog wait: 0.616114 RTT: 0.126842 total execute time: 0.805348 (milliseconds) Signed-off-by: Chuck Lever <[email protected]> Signed-off-by: J. Bruce Fields <[email protected]>
1 parent dc451bb commit 8847ecc

File tree

1 file changed

+11
-6
lines changed

1 file changed

+11
-6
lines changed

fs/nfsd/nfscache.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,8 @@ lru_put_end(struct nfsd_drc_bucket *b, struct svc_cacherep *rp)
241241
list_move_tail(&rp->c_lru, &b->lru_head);
242242
}
243243

244-
static long
245-
prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn)
244+
static long prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn,
245+
unsigned int max)
246246
{
247247
struct svc_cacherep *rp, *tmp;
248248
long freed = 0;
@@ -258,11 +258,17 @@ prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn)
258258
time_before(jiffies, rp->c_timestamp + RC_EXPIRE))
259259
break;
260260
nfsd_reply_cache_free_locked(b, rp, nn);
261-
freed++;
261+
if (max && freed++ > max)
262+
break;
262263
}
263264
return freed;
264265
}
265266

267+
static long nfsd_prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn)
268+
{
269+
return prune_bucket(b, nn, 3);
270+
}
271+
266272
/*
267273
* Walk the LRU list and prune off entries that are older than RC_EXPIRE.
268274
* Also prune the oldest ones when the total exceeds the max number of entries.
@@ -279,7 +285,7 @@ prune_cache_entries(struct nfsd_net *nn)
279285
if (list_empty(&b->lru_head))
280286
continue;
281287
spin_lock(&b->cache_lock);
282-
freed += prune_bucket(b, nn);
288+
freed += prune_bucket(b, nn, 0);
283289
spin_unlock(&b->cache_lock);
284290
}
285291
return freed;
@@ -453,8 +459,7 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp)
453459
atomic_inc(&nn->num_drc_entries);
454460
nfsd_stats_drc_mem_usage_add(nn, sizeof(*rp));
455461

456-
/* go ahead and prune the cache */
457-
prune_bucket(b, nn);
462+
nfsd_prune_bucket(b, nn);
458463

459464
out_unlock:
460465
spin_unlock(&b->cache_lock);

0 commit comments

Comments
 (0)