Skip to content

Commit 01c0a91

Browse files
author
Rafael Aquini
committed
mm/mglru: reset page lru tier bits when activating
JIRA: https://issues.redhat.com/browse/RHEL-84184 This patch is a backport of the following upstream commit: commit f1001f3 Author: Wei Xu <[email protected]> Date: Thu Oct 17 18:15:28 2024 +0000 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]> Signed-off-by: Rafael Aquini <[email protected]>
1 parent 6cb5f8a commit 01c0a91

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
@@ -399,6 +399,8 @@ enum {
399399
NR_LRU_GEN_CAPS
400400
};
401401

402+
#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset))
403+
402404
#define MIN_LRU_BATCH BITS_PER_LONG
403405
#define MAX_LRU_BATCH (MIN_LRU_BATCH * 64)
404406

mm/vmscan.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2545,8 +2545,6 @@ static bool should_clear_pmd_young(void)
25452545
* shorthand helpers
25462546
******************************************************************************/
25472547

2548-
#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset))
2549-
25502548
#define DEFINE_MAX_SEQ(lruvec) \
25512549
unsigned long max_seq = READ_ONCE((lruvec)->lrugen.max_seq)
25522550

@@ -4041,8 +4039,10 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
40414039
old_gen = folio_lru_gen(folio);
40424040
if (old_gen < 0)
40434041
folio_set_referenced(folio);
4044-
else if (old_gen != new_gen)
4042+
else if (old_gen != new_gen) {
4043+
folio_clear_lru_refs(folio);
40454044
folio_activate(folio);
4045+
}
40464046
}
40474047

40484048
arch_leave_lazy_mmu_mode();
@@ -4303,7 +4303,7 @@ static bool isolate_folio(struct lruvec *lruvec, struct folio *folio, struct sca
43034303

43044304
/* see the comment on MAX_NR_TIERS */
43054305
if (!folio_test_referenced(folio))
4306-
set_mask_bits(&folio->flags, LRU_REFS_MASK | LRU_REFS_FLAGS, 0);
4306+
folio_clear_lru_refs(folio);
43074307

43084308
/* for shrink_folio_list() */
43094309
folio_clear_reclaim(folio);

0 commit comments

Comments
 (0)