Re: [PATCH v4 3/3] mm: mglru: promote mapped executable folios after first usage

From: Baolin Wang

Date: Wed Jul 22 2026 - 22:28:05 EST




On 7/21/26 4:31 PM, Barry Song wrote:
On Mon, Jul 20, 2026 at 7:12 PM Baolin Wang
<baolin.wang@xxxxxxxxxxxxxxxxx> wrote:

Classical LRU protects mapped executable file folios through commit
8cab4754d24a0 ("vmscan: make mapped executable pages the first class
citizen") and commit c909e99364c8 ("vmscan: activate executable pages
after first usage"), giving executable code a better chance to stay in
memory, avoiding IO thrashing and improving workload performance.

However, MGLRU's protection of mapped executable file folios is less
reliable. Although shrink_folio_list() checks references, the access flag
of mapped executable file folios may have already been checked and
cleared by lru_gen_look_around() or walk_mm(). Additionally,
folio_update_gen() or lru_gen_set_refs() only sets the 'PG_referenced'
flag for mapped executable file folios, which causes shrink_folio_list()
to ignore the first usage of these mapped executable file folios and
reclaim them easily.

Follow the classical LRU's logic, promoting mapped executable file folios
after their first usage in folio_update_gen() and lru_gen_set_refs(),
giving executable code a better chance to stay in memory.

On my 32-core Arm machine, with the memcg limit set to 2G, running
'make -j32' to build kernel showed some improvement in sys time.

base patched
9248.543s 7861.579s

Signed-off-by: Baolin Wang <baolin.wang@xxxxxxxxxxxxxxxxx>
Acked-by: Johannes Weiner <hannes@xxxxxxxxxxx>
Reviewed-by: Axel Rasmussen <axelrasmussen@xxxxxxxxxx>
---
mm/vmscan.c | 43 +++++++++++++++++++++++++++----------------
1 file changed, 27 insertions(+), 16 deletions(-)

diff --git a/mm/vmscan.c b/mm/vmscan.c
index 8f0c31a4848e..b1ec65fb8947 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -841,10 +841,16 @@ enum folio_references {
* with PG_active set. In contrast, the aging (page table walk) path uses
* folio_update_gen().
*/
-static bool lru_gen_set_refs(struct folio *folio)
+static bool lru_gen_set_refs(struct folio *folio, const vma_flags_t *vma_flags)
{
/* see the comment on LRU_REFS_FLAGS */
if (!folio_test_referenced(folio) && !folio_test_workingset(folio)) {
+ /* Activate file-backed executable folios after first usage. */
+ if (is_exec_file_folio(folio, vma_flags)) {
+ set_mask_bits(&folio->flags.f, LRU_REFS_FLAGS, BIT(PG_workingset));
+ return true;
+ }
+

Hi Baolin,

Do you see any performance difference if you change the code to
something like the following?

-static bool lru_gen_set_refs(struct folio *folio)
+static bool lru_gen_set_refs(struct folio *folio, const vma_flags_t *vma_flags)
{
+ /* Activate file-backed executable folios after first usage. */
+ if (is_exec_file_folio(folio, vma_flags)) {
+ set_mask_bits(&folio->flags.f, LRU_REFS_FLAGS,
BIT(PG_workingset));
+ return true;
+ }

I tried that, and there was no obvious difference. I think the original logic also promotes the exec folio when it is accessed again, so I prefer to keep the same logic as folio_update_gen().

As I mentioned earlier[1], lru_gen_set_refs() needs some rework, and I'll think about how to optimize this function later.

[1] https://lore.kernel.org/all/eb395442-0aad-428a-a5ac-9072d2d89060@xxxxxxxxxxxxxxxxx/