Skip to content

Commit 6491212

Browse files
neilbrownchucklever
authored andcommitted
nfsd: filecache: introduce NFSD_FILE_RECENT
The filecache lru is walked in 2 circumstances for 2 different reasons. 1/ When called from the shrinker we want to discard the first few entries on the list, ignoring any with NFSD_FILE_REFERENCED set because they should really be at the end of the LRU as they have been referenced recently. So those ones are ROTATED. 2/ When called from the nfsd_file_gc() timer function we want to discard anything that hasn't been used since before the previous call, and mark everything else as unused at this point in time. Using the same flag for both of these can result in some unexpected outcomes. If the shrinker callback clears NFSD_FILE_REFERENCED then nfsd_file_gc() will think the file hasn't been used in a while, while really it has. I think it is easier to reason about the behaviour if we instead have two flags. NFSD_FILE_REFERENCED means "this should be at the end of the LRU, please put it there when convenient" NFSD_FILE_RECENT means "this has been used recently - since the last run of nfsd_file_gc() When either caller finds an NFSD_FILE_REFERENCED entry, that entry should be moved to the end of the LRU and the flag cleared. This can safely happen at any time. The actual order on the lru might not be strictly least-recently-used, but that is normal for linux lrus. The shrinker callback can ignore the "recent" flag. If it ends up freeing something that is "recent" that simply means that memory pressure is sufficient to limit the acceptable cache age to less than the nfsd_file_gc frequency. The gc callback should primarily focus on NFSD_FILE_RECENT. It should free everything that doesn't have this flag set, and should clear the flag on everything else. When it clears the flag it is convenient to clear the "REFERENCED" flag and move to the end of the LRU too. With this, calls from the shrinker do not prematurely age files. It will focus only on freeing those that are least recently used. Signed-off-by: NeilBrown <neilb@suse.de> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 8017afd commit 6491212

File tree

3 files changed

+24
-2
lines changed

3 files changed

+24
-2
lines changed

fs/nfsd/filecache.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,10 +319,10 @@ nfsd_file_check_writeback(struct nfsd_file *nf)
319319
mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK);
320320
}
321321

322-
323322
static bool nfsd_file_lru_add(struct nfsd_file *nf)
324323
{
325324
set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
325+
set_bit(NFSD_FILE_RECENT, &nf->nf_flags);
326326
if (list_lru_add_obj(&nfsd_file_lru, &nf->nf_lru)) {
327327
trace_nfsd_file_lru_add(nf);
328328
return true;
@@ -534,6 +534,24 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
534534
return LRU_REMOVED;
535535
}
536536

537+
static enum lru_status
538+
nfsd_file_gc_cb(struct list_head *item, struct list_lru_one *lru,
539+
void *arg)
540+
{
541+
struct nfsd_file *nf = list_entry(item, struct nfsd_file, nf_lru);
542+
543+
if (test_and_clear_bit(NFSD_FILE_RECENT, &nf->nf_flags)) {
544+
/*
545+
* "REFERENCED" really means "should be at the end of the
546+
* LRU. As we are putting it there we can clear the flag.
547+
*/
548+
clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
549+
trace_nfsd_file_gc_aged(nf);
550+
return LRU_ROTATE;
551+
}
552+
return nfsd_file_lru_cb(item, lru, arg);
553+
}
554+
537555
static void
538556
nfsd_file_gc(void)
539557
{
@@ -544,7 +562,7 @@ nfsd_file_gc(void)
544562
for_each_node_state(nid, N_NORMAL_MEMORY) {
545563
unsigned long nr = list_lru_count_node(&nfsd_file_lru, nid);
546564

547-
ret += list_lru_walk_node(&nfsd_file_lru, nid, nfsd_file_lru_cb,
565+
ret += list_lru_walk_node(&nfsd_file_lru, nid, nfsd_file_gc_cb,
548566
&dispose, &nr);
549567
}
550568
trace_nfsd_file_gc_removed(ret, list_lru_count(&nfsd_file_lru));

fs/nfsd/filecache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct nfsd_file {
3838
#define NFSD_FILE_PENDING (1)
3939
#define NFSD_FILE_REFERENCED (2)
4040
#define NFSD_FILE_GC (3)
41+
#define NFSD_FILE_RECENT (4)
4142
unsigned long nf_flags;
4243
refcount_t nf_ref;
4344
unsigned char nf_may;

fs/nfsd/trace.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,7 @@ DEFINE_CLID_EVENT(confirmed_r);
10501050
{ 1 << NFSD_FILE_HASHED, "HASHED" }, \
10511051
{ 1 << NFSD_FILE_PENDING, "PENDING" }, \
10521052
{ 1 << NFSD_FILE_REFERENCED, "REFERENCED" }, \
1053+
{ 1 << NFSD_FILE_RECENT, "RECENT" }, \
10531054
{ 1 << NFSD_FILE_GC, "GC" })
10541055

10551056
DECLARE_EVENT_CLASS(nfsd_file_class,
@@ -1328,6 +1329,7 @@ DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del_disposed);
13281329
DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_in_use);
13291330
DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_writeback);
13301331
DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_referenced);
1332+
DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_aged);
13311333
DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_disposed);
13321334

13331335
DECLARE_EVENT_CLASS(nfsd_file_lruwalk_class,
@@ -1357,6 +1359,7 @@ DEFINE_EVENT(nfsd_file_lruwalk_class, name, \
13571359
TP_ARGS(removed, remaining))
13581360

13591361
DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_gc_removed);
1362+
DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_gc_recent);
13601363
DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_shrinker_removed);
13611364

13621365
TRACE_EVENT(nfsd_file_close,

0 commit comments

Comments
 (0)