From: Baoquan He <baoquan.he@linux.dev>
To: kasong@tencent.com
Cc: linux-mm@kvack.org, Andrew Morton <akpm@linux-foundation.org>,
Johannes Weiner <hannes@cmpxchg.org>,
Muchun Song <muchun.song@linux.dev>,
Qi Zheng <qi.zheng@linux.dev>,
Ying Huang <ying.huang@linux.alibaba.com>,
Chris Li <chrisl@kernel.org>, Nico Pache <nico.pache@linux.dev>,
Usama Arif <usama.arif@linux.dev>,
Michal Hocko <mhocko@kernel.org>,
Roman Gushchin <roman.gushchin@linux.dev>,
Shakeel Butt <shakeel.butt@linux.dev>,
David Hildenbrand <david@kernel.org>,
Lorenzo Stoakes <ljs@kernel.org>, Barry Song <baohua@kernel.org>,
Axel Rasmussen <axelrasmussen@google.com>,
Yuanchu Xie <yuanchu@google.com>, Wei Xu <weixugc@google.com>,
Vlastimil Babka <vbabka@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
Kemeng Shi <shikemeng@huaweicloud.com>,
Nhat Pham <nphamcs@gmail.com>,
Youngjun Park <youngjun.park@lge.com>, Zi Yan <ziy@nvidia.com>,
Gregory Price <gourry@gourry.net>,
"Matthew Wilcox (Oracle)" <willy@infradead.org>,
Baolin Wang <baolin.wang@linux.alibaba.com>,
Ryan Roberts <ryan.roberts@arm.com>, Dev Jain <dev.jain@arm.com>,
Lance Yang <lance.yang@linux.dev>,
Hugh Dickins <hughd@google.com>, SeongJae Park <sj@kernel.org>,
David Rientjes <rientjes@google.com>, Yu Zhao <yuzhao@google.com>,
Vernon Yang <vernon2gm@gmail.com>,
Zicheng Wang <wangzicheng@honor.com>,
Chen Ridong <chenridong@xiaomi.com>,
Tal Zussman <tz2294@columbia.edu>, Kairui Song <ryncsn@gmail.com>,
linux-kernel@vger.kernel.org, cgroups@vger.kernel.org
Subject: Re: [PATCH RFC 09/15] mm/mglru: frequency guided workingset promotion (MGLRU-FG)
Date: Tue, 18 Aug 2026 15:12:03 +0800 [thread overview]
Message-ID: <aoQFw_SWJBAdO8w-@MiWiFi-R3L-srv> (raw)
In-Reply-To: <20260804-mglru-fg-v1-9-4d8dad39dad6@tencent.com>
On 08/04/26 at 03:47am, Kairui Song via B4 Relay wrote:
...snip...
> +int folio_inc_lru_refs(struct folio *folio, bool is_fault, bool is_exec)
> +{
> + int max_gen, min_gen;
> + int type, refs, gen, new_gen;
> + unsigned long new_flags, old_flags, max_seq;
> + struct lru_gen_folio *lrugen;
> + struct lruvec *lruvec;
> +
> + type = folio_is_file_lru(folio);
> + lruvec = folio_lruvec_live_get(folio);
> + lrugen = &lruvec->lrugen;
> +
> + old_flags = READ_ONCE(*folio_flags(folio, 0));
> + do {
> + new_flags = old_flags;
> + gen = lru_gen_from_flags(old_flags);
> + refs = lru_refs_from_flags(old_flags) + 1;
> + new_gen = gen;
> + if (!(old_flags & BIT(PG_lru)) || gen < 0)
> + goto out;
> +
> + max_seq = READ_ONCE(lrugen->max_seq);
> + max_gen = lru_gen_from_seq(max_seq);
> + min_gen = lru_gen_from_seq(READ_ONCE(lrugen->min_seq[type]));
> + if (gen == max_gen)
> + goto out;
> +
I am a little confused about the new mechanism. In the current mglru, it
does have the issue both mm walk and fd read set PG_referenced at the
1st access, this is a obvious drawback. Now with the change, the ref
count is clearer, while the mm walk and fd read accessing is still mixed.
Imagine the cases below:
- one fd read; then mm walk; directly move to max_gen;
- one mm walk; then several times fd read; promote to next gen;
Can I understand the final effect as:
1) explicti ref count;
2) more drastically promote mm walk based on the mixing ref counting;
- compared with the old behaviour: move to next gen when 2nd mm walk
I can only see one benefit and one significant change. Do I understand
it correctly, and is it worth?
Thanks
Baoquan
> + if (is_fault || is_exec) {
> + /* Promote second page table access or executable */
> + if (refs > LRU_REFS_REFERENCED || is_exec)
> + new_gen = max_gen;
> + else
> + new_gen = (gen + 1UL) % MAX_NR_GENS;
> + refs = min(refs, LRU_REFS_PROTECTED);
> + } else if (refs > LRU_REFS_MAX) {
> + /* LRU refs counting overflow, bump the gen */
> + new_gen = (gen + 1UL) % MAX_NR_GENS;
> + refs = LRU_REFS_PROTECTED;
> + } else if (gen == min_gen && refs >= LRU_REFS_WORKINGSET) {
> + /* Defer eviction of just accessed workingset */
> + new_gen = (gen + 1UL) % MAX_NR_GENS;
> + refs = min(refs, LRU_REFS_PROTECTED);
> }
> +out:
> + refs = min(refs, LRU_REFS_MAX);
> + lru_refs_set_flags(&new_flags, refs);
> + if (new_gen >= 0)
> + lru_gen_set_flags(&new_flags, new_gen);
> + } while (!try_cmpxchg(folio_flags(folio, 0), &old_flags, new_flags));
>
> - folio_set_lru_refs(folio, 1);
> - return false;
> + if (new_gen != gen) {
> + /*
> + * Gen can only go forward, so concurrent aging is
> + * usually fine, except when multiple aging increase
> + * max_seq multiple times, new_gen may have go beyond
> + * the new max_seq's current gen border and causes
> + * hotness inversion. In that very unlikely case,
> + * just activate the folio.
> + */
> + lru_gen_update_size(lruvec, folio, gen, new_gen);
> + if (unlikely(READ_ONCE(lrugen->max_seq) - max_seq > MIN_NR_GENS))
> + folio_activate(folio);
> }
>
> - /* Promote on second access */
> - if (folio_lru_refs(folio) > 1) {
> - folio_set_lru_refs(folio, 0);
> - folio_set_workingset(folio);
> - } else {
> - folio_mark_accessed(folio);
> - }
> - return true;
> + folio_lruvec_live_put(lruvec);
> + return refs;
> +}
> +
> +/*
> + * Update the folio's lru refs indicator during a page table walk.
> + * max_seq is stable since this runs inside the aging process.
> + *
> + * Returns the old generation and stores the new generation in @new_gen when
> + * the folio is promoted (to max_gen) or advanced by one generation.
> + * Returns -1 if no gen change occurred.
> + */
> +static int folio_inc_lru_refs_walk(struct folio *folio, struct lruvec *lruvec,
> + const vma_flags_t *vma_flags, int *new_gen)
> +{
> + unsigned long new_flags, old_flags = READ_ONCE(*folio_flags(folio, 0));
> + unsigned long max_seq = READ_ONCE(lruvec->lrugen.max_seq);
> + int refs, gen, max_gen, ret;
> +
> + max_gen = lru_gen_from_seq(max_seq);
> +
> + do {
> + gen = lru_gen_from_flags(old_flags);
> + refs = lru_refs_from_flags(old_flags) + 1;
> + new_flags = old_flags;
> +
> + if (gen >= 0 && gen != max_gen) {
> + ret = gen;
> + /* Promote second page table access or executable */
> + if (refs > LRU_REFS_REFERENCED || is_exec_file_folio(folio, vma_flags))
> + *new_gen = max_gen;
> + else
> + *new_gen = (gen + 1) % MAX_NR_GENS;
> + lru_gen_set_flags(&new_flags, *new_gen);
> + lru_refs_set_flags(&new_flags, min(refs, LRU_REFS_PROTECTED));
> + } else {
> + ret = -1;
> + lru_refs_set_flags(&new_flags, min(refs, LRU_REFS_MAX));
> + }
> + } while (!try_cmpxchg(folio_flags(folio, 0), &old_flags, new_flags));
> +
> + return ret;
> +}
> +
> +/*
> + * Update the folio's lru refs indicator while the folio is isolated.
> + * Only used on mapped folios upon the final eviction, when the folio is
> + * off the LRU list (isolated).
> + *
> + * Increments the refs count (capped at LRU_REFS_PROTECTED). Returns true
> + * if the caller should activate the folio (second access or
> + * executable), false to keep it in the eviction list.
> + */
> +static bool folio_inc_lru_refs_isolated(struct folio *folio, const vma_flags_t *vma_flags)
> +{
> + unsigned long new_flags, old_flags = READ_ONCE(*folio_flags(folio, 0));
> + int refs;
> +
> + do {
> + new_flags = old_flags;
> + refs = lru_refs_from_flags(old_flags) + 1;
> + lru_refs_set_flags(&new_flags, min(refs, LRU_REFS_PROTECTED));
> + } while (!try_cmpxchg(folio_flags(folio, 0), &old_flags, new_flags));
> +
> + /* Promote second page table access or executable */
> + return refs > LRU_REFS_REFERENCED || is_exec_file_folio(folio, vma_flags);
> }
> #else
> -static bool lru_gen_set_refs(struct folio *folio, const vma_flags_t *vma_flags)
> +static bool folio_inc_lru_refs_isolated(struct folio *folio, const vma_flags_t *vma_flags)
> {
> return false;
> }
> @@ -896,7 +1035,8 @@ static enum folio_references folio_check_references(struct folio *folio,
> if (!referenced_ptes)
> return FOLIOREF_RECLAIM;
>
> - return lru_gen_set_refs(folio, &vma_flags) ? FOLIOREF_ACTIVATE : FOLIOREF_KEEP;
> + return folio_inc_lru_refs_isolated(folio, &vma_flags) ?
> + FOLIOREF_ACTIVATE : FOLIOREF_KEEP;
> }
>
> referenced_folio = folio_test_clear_referenced(folio);
> @@ -3262,59 +3402,31 @@ static bool positive_ctrl_err(struct ctrl_pos *sp, struct ctrl_pos *pv)
> * the aging
> ******************************************************************************/
>
> -/* promote pages accessed through page tables */
> -static int folio_update_gen(struct folio *folio, int new_gen, const vma_flags_t *vma_flags)
> -{
> - unsigned long new_flags, old_flags = READ_ONCE(*folio_flags(folio, 0));
> - int old_gen;
> -
> - /*
> - * See the comment on LRU_REFS_FLAGS, and activate file-backed
> - * executable folios after first usage to avoid typical IO
> - * thrashing from reclaiming.
> - */
> - if (!folio_test_referenced(folio) && !folio_test_workingset(folio) &&
> - !is_exec_file_folio(folio, vma_flags)) {
> - folio_set_lru_refs(folio, 1);
> - return -1;
> - }
> -
> - do {
> - old_gen = lru_gen_from_flags(old_flags);
> - new_flags = old_flags;
> -
> - /* lru_gen_del_folio() has isolated this page? */
> - if (old_gen < 0)
> - break;
> -
> - lru_gen_set_flags(&new_flags, new_gen);
> - lru_refs_set_flags(&new_flags, 0);
> - new_flags |= BIT(PG_workingset);
> - } while (!try_cmpxchg(folio_flags(folio, 0), &old_flags, new_flags));
> -
> - return old_gen;
> -}
> -
> -/* protect pages accessed multiple times through file descriptors */
> +/*
> + * Force bump a folio's generation. Used for PID protection or defer the
> + * eviction of temporarily unevictable folio.
> + */
> static int folio_inc_gen(struct lruvec *lruvec, struct folio *folio)
> {
> + int refs;
> int type = folio_is_file_lru(folio);
> struct lru_gen_folio *lrugen = &lruvec->lrugen;
> int old_gen, new_gen, min_gen = lru_gen_from_seq(lrugen->min_seq[type]);
> unsigned long new_flags, old_flags = READ_ONCE(*folio_flags(folio, 0));
>
> do {
> + new_flags = old_flags;
> + refs = lru_refs_from_flags(old_flags);
> old_gen = lru_gen_from_flags(old_flags);
> VM_WARN_ON_ONCE_FOLIO(old_gen < 0, folio);
>
> - /* folio_update_gen() has promoted this page? */
> + /* folio has been promoted? */
> if (old_gen >= 0 && old_gen != min_gen)
> return old_gen;
>
> - new_flags = old_flags;
> new_gen = (old_gen + 1) % MAX_NR_GENS;
> lru_gen_set_flags(&new_flags, new_gen);
> - lru_refs_set_flags(&new_flags, 0);
> + lru_refs_set_flags(&new_flags, min(refs, LRU_REFS_WORKINGSET));
> } while (!try_cmpxchg(folio_flags(folio, 0), &old_flags, new_flags));
>
> lru_gen_update_size(lruvec, folio, old_gen, new_gen);
> @@ -3518,21 +3630,17 @@ static void walk_update_folio(struct lru_gen_mm_walk *walk, struct vm_area_struc
> if (!folio)
> return;
>
> - new_gen = lru_gen_from_seq(READ_ONCE(lruvec->lrugen.max_seq));
> -
> if (dirty && !folio_test_dirty(folio) &&
> !(folio_test_anon(folio) && folio_test_swapbacked(folio) &&
> !folio_test_swapcache(folio)))
> folio_mark_dirty(folio);
>
> if (walk) {
> - old_gen = folio_update_gen(folio, new_gen, &vma->flags);
> - if (old_gen >= 0 && old_gen != new_gen)
> + old_gen = folio_inc_lru_refs_walk(folio, lruvec, &vma->flags, &new_gen);
> + if (old_gen >= 0)
> update_batch_size(walk, folio, old_gen, new_gen);
> - } else if (lru_gen_set_refs(folio, &vma->flags)) {
> - old_gen = folio_lru_gen(folio);
> - if (old_gen >= 0 && old_gen != new_gen)
> - folio_activate(folio);
> + } else {
> + folio_inc_lru_refs(folio, true, is_exec_file_folio(folio, &vma->flags));
> }
> }
>
> @@ -3917,7 +4025,8 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, int swappiness)
> while (!list_empty(head)) {
> struct folio *folio = lru_to_folio(head);
> int refs = folio_lru_refs(folio);
> - bool workingset = folio_test_workingset(folio);
> + int delta = folio_nr_pages(folio);
> + int tier = lru_tier_from_refs(refs);
>
> VM_WARN_ON_ONCE_FOLIO(folio_test_unevictable(folio), folio);
> VM_WARN_ON_ONCE_FOLIO(folio_test_active(folio), folio);
> @@ -3927,14 +4036,8 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, int swappiness)
> new_gen = folio_inc_gen(lruvec, folio);
> list_move_tail(&folio->lru, &lrugen->folios[new_gen][type][zone]);
>
> - /* don't count the workingset being lazily promoted */
> - if (refs + workingset != BIT(LRU_REFS_WIDTH) + 1) {
> - int tier = lru_tier_from_refs(refs, workingset);
> - int delta = folio_nr_pages(folio);
> -
> - WRITE_ONCE(lrugen->protected[hist][type][tier],
> - lrugen->protected[hist][type][tier] + delta);
> - }
> + WRITE_ONCE(lrugen->protected[hist][type][tier],
> + lrugen->protected[hist][type][tier] + delta);
>
> if (!--remaining)
> return false;
> @@ -4649,8 +4752,7 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_c
> int zone = folio_zonenum(folio);
> int delta = folio_nr_pages(folio);
> int refs = folio_lru_refs(folio);
> - bool workingset = folio_test_workingset(folio);
> - int tier = lru_tier_from_refs(refs, workingset);
> + int tier = lru_tier_from_refs(refs);
> struct lru_gen_folio *lrugen = &lruvec->lrugen;
>
> VM_WARN_ON_ONCE_FOLIO(gen >= MAX_NR_GENS, folio);
> @@ -4672,17 +4774,15 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, struct scan_c
> }
>
> /* protected */
> - if (tier > tier_idx || refs + workingset == BIT(LRU_REFS_WIDTH) + 1) {
> + if (tier > tier_idx) {
> + int hist = lru_hist_from_seq(lrugen->min_seq[type]);
> +
> gen = folio_inc_gen(lruvec, folio);
> list_move(&folio->lru, &lrugen->folios[gen][type][zone]);
>
> - /* don't count the workingset being lazily promoted */
> - if (refs + workingset != BIT(LRU_REFS_WIDTH) + 1) {
> - int hist = lru_hist_from_seq(lrugen->min_seq[type]);
> + WRITE_ONCE(lrugen->protected[hist][type][tier],
> + lrugen->protected[hist][type][tier] + delta);
>
> - WRITE_ONCE(lrugen->protected[hist][type][tier],
> - lrugen->protected[hist][type][tier] + delta);
> - }
> return true;
> }
>
> @@ -4710,10 +4810,6 @@ static bool isolate_folio(struct lruvec *lruvec, struct folio *folio, struct sca
> return false;
> }
>
> - /* see the comment on LRU_REFS_FLAGS */
> - if (!folio_test_referenced(folio))
> - folio_set_lru_refs(folio, 0);
> -
> success = lru_gen_del_folio(lruvec, folio, true);
> VM_WARN_ON_ONCE_FOLIO(!success, folio);
>
> @@ -4801,13 +4897,13 @@ static int get_tier_idx(struct lruvec *lruvec, int type)
> struct ctrl_pos sp, pv = {};
>
> /*
> - * To leave a margin for fluctuations, use a larger gain factor (2:3).
> + * To leave a margin for fluctuations, use a larger gain factor (1:2).
> * This value is chosen because any other tier would have at least twice
> * as many refaults as the first tier.
> */
> - read_ctrl_pos(lruvec, type, 0, 1, 2, &sp);
> for (tier = 1; tier < MAX_NR_TIERS; tier++) {
> - read_ctrl_pos(lruvec, type, tier, tier + 1, 3, &pv);
> + read_ctrl_pos(lruvec, type, 0, tier, 1, &sp);
> + read_ctrl_pos(lruvec, type, tier, tier + 1, 2, &pv);
> if (!positive_ctrl_err(&sp, &pv))
> break;
> }
> @@ -4930,10 +5026,8 @@ static int evict_folios(unsigned long nr_to_scan, struct lruvec *lruvec,
> }
>
> /* don't add rejected folios to the oldest generation */
> - if (lru_gen_folio_seq(lruvec, folio, false) == min_seq[type]) {
> - folio_set_lru_refs(folio, 0);
> + if (lru_gen_folio_seq(lruvec, folio, false) == min_seq[type])
> folio_set_active(folio);
> - }
> }
>
> move_folios_to_lru(&list);
> diff --git a/mm/workingset.c b/mm/workingset.c
> index 5438e9390011..452fe8554990 100644
> --- a/mm/workingset.c
> +++ b/mm/workingset.c
> @@ -189,6 +189,13 @@
> #define EVICTION_MASK (~0UL >> EVICTION_SHIFT)
> #define EVICTION_MASK_ANON (~0UL >> EVICTION_SHIFT_ANON)
>
> +/*
> + * LRU refs uses LRU_REFS_WIDTH + 2 bits, the 2 bits are PG_workingset and
> + * PG_referenced. But here we record PG_workingset separately (to reuse
> + * pack_shadow).
> + */
> +#define LRU_REFS_BITS ((LRU_REFS_WIDTH + 2) - 1)
> +
> /*
> * Eviction timestamps need to be able to cover the full range of
> * actionable refaults. However, bits are tight in the xarray
> @@ -242,13 +249,12 @@ static void *lru_gen_eviction(struct folio *folio)
> int type = folio_is_file_lru(folio);
> int delta = folio_nr_pages(folio);
> int refs = folio_lru_refs(folio);
> - bool workingset = folio_test_workingset(folio);
> - int tier = lru_tier_from_refs(refs, workingset);
> + int tier = lru_tier_from_refs(refs);
> struct mem_cgroup *memcg;
> struct pglist_data *pgdat = folio_pgdat(folio);
> unsigned short memcg_id;
>
> - BUILD_BUG_ON(LRU_GEN_WIDTH + LRU_REFS_WIDTH >
> + BUILD_BUG_ON(LRU_GEN_WIDTH + LRU_REFS_BITS >
> BITS_PER_LONG - max(EVICTION_SHIFT, EVICTION_SHIFT_ANON));
>
> rcu_read_lock();
> @@ -256,14 +262,14 @@ static void *lru_gen_eviction(struct folio *folio)
> lruvec = mem_cgroup_lruvec(memcg, pgdat);
> lrugen = &lruvec->lrugen;
> min_seq = READ_ONCE(lrugen->min_seq[type]);
> - token = (min_seq << LRU_REFS_WIDTH) | max(refs - 1, 0);
> + token = (min_seq << LRU_REFS_BITS) | refs >> 1;
>
> hist = lru_hist_from_seq(min_seq);
> atomic_long_add(delta, &lrugen->evicted[hist][type][tier]);
> memcg_id = mem_cgroup_private_id(memcg);
> rcu_read_unlock();
>
> - return pack_shadow(memcg_id, pgdat, token, workingset, type);
> + return pack_shadow(memcg_id, pgdat, token, refs & 1, type);
> }
>
> /*
> @@ -284,11 +290,24 @@ static bool lru_gen_test_recent(void *shadow, struct lruvec **lruvec,
> *lruvec = mem_cgroup_lruvec(memcg, pgdat);
>
> max_seq = READ_ONCE((*lruvec)->lrugen.max_seq);
> - max_seq &= (file ? EVICTION_MASK : EVICTION_MASK_ANON) >> LRU_REFS_WIDTH;
> + max_seq &= (file ? EVICTION_MASK : EVICTION_MASK_ANON) >> LRU_REFS_BITS;
>
> - return abs_diff(max_seq, *token >> LRU_REFS_WIDTH) < MAX_NR_GENS;
> + return abs_diff(max_seq, *token >> LRU_REFS_BITS) < MAX_NR_GENS;
> }
>
> +/*
> + * Restore the refs of a refaulted folio from its shadow entry.
> + *
> + * Any folio that was accessed at least once before eviction (refs >=
> + * LRU_REFS_REFERENCED) is activated on a fault-driven refault, giving it a
> + * strong gen placement. Non-fault refaults (e.g. readahead) are not
> + * activated regardless of refs.
> + *
> + * The restored refs is capped at LRU_REFS_PROTECTED to prevent stale
> + * high-tier history from carrying over across eviction cycles. The
> + * WORKINGSET_RESTORE stat is bumped only for refs >= LRU_REFS_WORKINGSET
> + * to track genuine workingset restoration.
> + */
> static void lru_gen_refault(struct folio *folio, void *shadow)
> {
> bool recent;
> @@ -314,21 +333,29 @@ static void lru_gen_refault(struct folio *folio, void *shadow)
> lrugen = &lruvec->lrugen;
>
> hist = lru_hist_from_seq(READ_ONCE(lrugen->min_seq[type]));
> - refs = (token & (BIT(LRU_REFS_WIDTH) - 1)) + 1;
> - tier = lru_tier_from_refs(refs, workingset);
> + refs = ((token & (BIT(LRU_REFS_BITS) - 1)) << 1) + workingset;
> + tier = lru_tier_from_refs(refs);
>
> atomic_long_add(delta, &lrugen->refaulted[hist][type][tier]);
>
> - if (workingset) {
> - /* Send refaulted workingset folios to active generations. */
> + /*
> + * Activate a fault-driven refault: the folio was accessed at
> + * least once before eviction and would have been promoted had
> + * it stayed in memory.
> + */
> + if (refs >= LRU_REFS_REFERENCED) {
> if (lru_gen_in_fault()) {
> folio_set_active(folio);
> mod_lruvec_state(lruvec, WORKINGSET_ACTIVATE_BASE + type, delta);
> }
> - folio_set_workingset(folio);
> + /* Cap restored refs to prevent stale high-tier carry-over */
> + folio_set_lru_refs(folio, min(refs, LRU_REFS_PROTECTED));
> + }
> +
> + /* WORKINGSET_RESTORE tracks genuine workingset-level refaults */
> + if (refs >= LRU_REFS_WORKINGSET)
> mod_lruvec_state(lruvec, WORKINGSET_RESTORE_BASE + type, delta);
> - } else
> - set_mask_bits(&folio->flags.f, LRU_REFS_MASK, (refs - 1UL) << LRU_REFS_PGOFF);
> +
> unlock:
> rcu_read_unlock();
> }
>
> --
> 2.55.0
>
>
next prev parent reply other threads:[~2026-08-18 7:12 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-03 19:46 [PATCH RFC 00/15] mm/mglru: frequency guided promotion (MGLRU-FG) and flag cleanup Kairui Song via B4 Relay
2026-08-03 19:46 ` [PATCH RFC 01/15] mm/memcontrol: make lru_zone_size atomic and simplify sanity check Kairui Song via B4 Relay
2026-08-03 19:46 ` [PATCH RFC 02/15] mm/memcontrol: allow update of LRU statistic without holding LRU lock Kairui Song via B4 Relay
2026-08-03 19:46 ` [PATCH RFC 03/15] mm/mglru: introduce and always use helpers for manipulating page flags Kairui Song via B4 Relay
2026-08-03 19:47 ` [PATCH RFC 04/15] mm/mglru: make generation page counters atomic Kairui Song via B4 Relay
2026-08-18 2:40 ` Baoquan He
2026-08-03 19:47 ` [PATCH RFC 05/15] mm/mglru: move max_seq read into walk_update_folio Kairui Song via B4 Relay
2026-08-18 2:23 ` Baoquan He
2026-08-03 19:47 ` [PATCH RFC 06/15] mm/mglru: use explicit tier range in read_ctrl_pos() Kairui Song via B4 Relay
2026-08-14 5:25 ` Barry Song
2026-08-15 10:36 ` Kairui Song
2026-08-18 2:52 ` Baoquan He
2026-08-03 19:47 ` [PATCH RFC 07/15] mm/mglru: move refault workingset activation into lru_gen_refault Kairui Song via B4 Relay
2026-08-18 3:20 ` Baoquan He
2026-08-03 19:47 ` [PATCH RFC 08/15] mm/memcg: add folio-based lruvec live helper Kairui Song via B4 Relay
2026-08-03 19:47 ` [PATCH RFC 09/15] mm/mglru: frequency guided workingset promotion (MGLRU-FG) Kairui Song via B4 Relay
2026-08-04 3:07 ` Kairui Song
2026-08-14 7:19 ` Barry Song
2026-08-14 18:05 ` Kairui Song
2026-08-15 0:13 ` Barry Song
2026-08-15 9:20 ` Kairui Song
2026-08-18 7:12 ` Baoquan He [this message]
2026-08-18 7:40 ` Kairui Song
2026-08-03 19:47 ` [PATCH RFC 10/15] mm/mglru: make folio lru referenced times count a generic API Kairui Song via B4 Relay
2026-08-18 7:19 ` Baoquan He
2026-08-03 19:47 ` [PATCH RFC 11/15] mm/mglru: replace folio workinset check and update with new helper Kairui Song via B4 Relay
2026-08-03 19:47 ` [PATCH RFC 12/15] mm/smap: report workingset folios as referenced Kairui Song via B4 Relay
2026-08-04 1:21 ` Johannes Weiner
2026-08-04 2:11 ` Kairui Song
2026-08-03 19:47 ` [PATCH RFC 13/15] mm/huge_memory: mark file folio as accessed more accurately on split Kairui Song via B4 Relay
2026-08-03 19:47 ` [PATCH RFC 14/15] mm/khugepaged: consider workingset folios as referenced Kairui Song via B4 Relay
2026-08-03 19:47 ` [PATCH RFC 15/15] mm/madvise: convert to new lru refs API and better support for MGLRU Kairui Song via B4 Relay
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aoQFw_SWJBAdO8w-@MiWiFi-R3L-srv \
--to=baoquan.he@linux.dev \
--cc=akpm@linux-foundation.org \
--cc=axelrasmussen@google.com \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=cgroups@vger.kernel.org \
--cc=chenridong@xiaomi.com \
--cc=chrisl@kernel.org \
--cc=david@kernel.org \
--cc=dev.jain@arm.com \
--cc=gourry@gourry.net \
--cc=hannes@cmpxchg.org \
--cc=hughd@google.com \
--cc=kasong@tencent.com \
--cc=lance.yang@linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=mhocko@kernel.org \
--cc=muchun.song@linux.dev \
--cc=nico.pache@linux.dev \
--cc=nphamcs@gmail.com \
--cc=qi.zheng@linux.dev \
--cc=rientjes@google.com \
--cc=roman.gushchin@linux.dev \
--cc=ryan.roberts@arm.com \
--cc=ryncsn@gmail.com \
--cc=shakeel.butt@linux.dev \
--cc=shikemeng@huaweicloud.com \
--cc=sj@kernel.org \
--cc=surenb@google.com \
--cc=tz2294@columbia.edu \
--cc=usama.arif@linux.dev \
--cc=vbabka@kernel.org \
--cc=vernon2gm@gmail.com \
--cc=wangzicheng@honor.com \
--cc=weixugc@google.com \
--cc=willy@infradead.org \
--cc=ying.huang@linux.alibaba.com \
--cc=youngjun.park@lge.com \
--cc=yuanchu@google.com \
--cc=yuzhao@google.com \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox