Skip to content

Commit f1001f3

Browse files
weixugcakpm00
authored andcommitted
mm/mglru: reset page lru tier bits when activating
When a folio is activated, lru_gen_add_folio() moves the folio to the youngest generation. But unlike folio_update_gen()/folio_inc_gen(), lru_gen_add_folio() doesn't reset the folio lru tier bits (LRU_REFS_MASK | LRU_REFS_FLAGS). This inconsistency can affect how pages are aged via folio_mark_accessed() (e.g. fd accesses), though no user visible impact related to this has been detected yet. Note that lru_gen_add_folio() cannot clear PG_workingset if the activation is due to workingset refault, otherwise PSI accounting will be skipped. So fix lru_gen_add_folio() to clear the lru tier bits other than PG_workingset when activating a folio, and also clear all the lru tier bits when a folio is activated via folio_activate() in lru_gen_look_around(). Link: https://lkml.kernel.org/r/[email protected] Fixes: 018ee47 ("mm: multi-gen LRU: exploit locality in rmap") Signed-off-by: Wei Xu <[email protected]> Cc: Axel Rasmussen <[email protected]> Cc: Brian Geffon <[email protected]> Cc: Jan Alexander Steffens <[email protected]> Cc: Suleiman Souhlal <[email protected]> Cc: Yu Zhao <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent d3ea85c commit f1001f3

File tree

3 files changed

+20
-5
lines changed

3 files changed

+20
-5
lines changed

include/linux/mm_inline.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@ static inline int folio_lru_refs(struct folio *folio)
155155
return ((flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF) + workingset;
156156
}
157157

158+
static inline void folio_clear_lru_refs(struct folio *folio)
159+
{
160+
set_mask_bits(&folio->flags, LRU_REFS_MASK | LRU_REFS_FLAGS, 0);
161+
}
162+
158163
static inline int folio_lru_gen(struct folio *folio)
159164
{
160165
unsigned long flags = READ_ONCE(folio->flags);
@@ -222,6 +227,7 @@ static inline bool lru_gen_add_folio(struct lruvec *lruvec, struct folio *folio,
222227
{
223228
unsigned long seq;
224229
unsigned long flags;
230+
unsigned long mask;
225231
int gen = folio_lru_gen(folio);
226232
int type = folio_is_file_lru(folio);
227233
int zone = folio_zonenum(folio);
@@ -257,7 +263,14 @@ static inline bool lru_gen_add_folio(struct lruvec *lruvec, struct folio *folio,
257263
gen = lru_gen_from_seq(seq);
258264
flags = (gen + 1UL) << LRU_GEN_PGOFF;
259265
/* see the comment on MIN_NR_GENS about PG_active */
260-
set_mask_bits(&folio->flags, LRU_GEN_MASK | BIT(PG_active), flags);
266+
mask = LRU_GEN_MASK;
267+
/*
268+
* Don't clear PG_workingset here because it can affect PSI accounting
269+
* if the activation is due to workingset refault.
270+
*/
271+
if (folio_test_active(folio))
272+
mask |= LRU_REFS_MASK | BIT(PG_referenced) | BIT(PG_active);
273+
set_mask_bits(&folio->flags, mask, flags);
261274

262275
lru_gen_update_size(lruvec, folio, -1, gen);
263276
/* for folio_rotate_reclaimable() */

include/linux/mmzone.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,8 @@ enum {
403403
NR_LRU_GEN_CAPS
404404
};
405405

406+
#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset))
407+
406408
#define MIN_LRU_BATCH BITS_PER_LONG
407409
#define MAX_LRU_BATCH (MIN_LRU_BATCH * 64)
408410

mm/vmscan.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2603,8 +2603,6 @@ static bool should_clear_pmd_young(void)
26032603
* shorthand helpers
26042604
******************************************************************************/
26052605

2606-
#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset))
2607-
26082606
#define DEFINE_MAX_SEQ(lruvec) \
26092607
unsigned long max_seq = READ_ONCE((lruvec)->lrugen.max_seq)
26102608

@@ -4142,8 +4140,10 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
41424140
old_gen = folio_lru_gen(folio);
41434141
if (old_gen < 0)
41444142
folio_set_referenced(folio);
4145-
else if (old_gen != new_gen)
4143+
else if (old_gen != new_gen) {
4144+
folio_clear_lru_refs(folio);
41464145
folio_activate(folio);
4146+
}
41474147
}
41484148

41494149
arch_leave_lazy_mmu_mode();
@@ -4376,7 +4376,7 @@ static bool isolate_folio(struct lruvec *lruvec, struct folio *folio, struct sca
43764376

43774377
/* see the comment on MAX_NR_TIERS */
43784378
if (!folio_test_referenced(folio))
4379-
set_mask_bits(&folio->flags, LRU_REFS_MASK | LRU_REFS_FLAGS, 0);
4379+
folio_clear_lru_refs(folio);
43804380

43814381
/* for shrink_folio_list() */
43824382
folio_clear_reclaim(folio);

0 commit comments

Comments
 (0)