generic: 6.1: manually refresh mglru patch with new kernel version
Refresh mglru patch for new kernel version due to very fun backport changing name from folio to pages. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
		| @@ -58,9 +58,9 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  | ||||
| --- a/include/linux/mm_inline.h | ||||
| +++ b/include/linux/mm_inline.h | ||||
| @@ -333,4 +333,13 @@ static __always_inline void del_page_fro | ||||
|  	update_lru_size(lruvec, page_lru(page), page_zonenum(page), | ||||
|  			-thp_nr_pages(page)); | ||||
| @@ -606,5 +606,13 @@ static __always_inline void del_page_fro | ||||
|  			   make_pte_marker(PTE_MARKER_UFFD_WP)); | ||||
|  #endif | ||||
|  } | ||||
| + | ||||
| +static inline bool vma_has_recency(struct vm_area_struct *vma) | ||||
| @@ -70,18 +70,10 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| + | ||||
| +	return true; | ||||
| +} | ||||
| + | ||||
|   | ||||
|  #endif | ||||
| --- a/mm/memory.c | ||||
| +++ b/mm/memory.c | ||||
| @@ -41,6 +41,7 @@ | ||||
|   | ||||
|  #include <linux/kernel_stat.h> | ||||
|  #include <linux/mm.h> | ||||
| +#include <linux/mm_inline.h> | ||||
|  #include <linux/sched/mm.h> | ||||
|  #include <linux/sched/coredump.h> | ||||
|  #include <linux/sched/numa_balancing.h> | ||||
| @@ -1353,8 +1354,7 @@ again: | ||||
|  					force_flush = 1; | ||||
|  					set_page_dirty(page); | ||||
| @@ -121,10 +113,10 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| -				/* | ||||
| -				 * Don't treat a reference through | ||||
| -				 * a sequentially read mapping as such. | ||||
| -				 * If the page has been used in another mapping, | ||||
| -				 * If the folio has been used in another mapping, | ||||
| -				 * we will catch it; if this other mapping is | ||||
| -				 * already gone, the unmap path will have set | ||||
| -				 * PG_referenced or activated the page. | ||||
| -				 * the referenced flag or activated the folio. | ||||
| -				 */ | ||||
| -				if (likely(!(vma->vm_flags & VM_SEQ_READ))) | ||||
| -					referenced++; | ||||
| @@ -157,10 +149,10 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|   | ||||
|  	return false; | ||||
| @@ -876,6 +878,7 @@ int page_referenced(struct page *page, | ||||
|  		.rmap_one = page_referenced_one, | ||||
|  		.arg = (void *)&pra, | ||||
|  		.anon_lock = page_lock_anon_vma_read, | ||||
| +		.invalid_vma = invalid_page_referenced_vma, | ||||
|  		.anon_lock = folio_lock_anon_vma_read, | ||||
|  		.try_lock = true, | ||||
| +		.invalid_vma = invalid_folio_referenced_vma, | ||||
|  	}; | ||||
|   | ||||
|  	*vm_flags = 0; | ||||
| @@ -174,10 +166,10 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| -	 * cgroups | ||||
| -	 */ | ||||
| -	if (memcg) { | ||||
| -		rwc.invalid_vma = invalid_page_referenced_vma; | ||||
| -		rwc.invalid_vma = invalid_folio_referenced_vma; | ||||
| -	} | ||||
| - | ||||
|  	rmap_walk(page, &rwc); | ||||
|  	rmap_walk(folio, &rwc); | ||||
|  	*vm_flags = pra.vm_flags; | ||||
|   | ||||
| --- a/mm/vmscan.c | ||||
|   | ||||
| @@ -2,7 +2,7 @@ From 348fdbada9fb3f0bf1a53651be46319105af187f Mon Sep 17 00:00:00 2001 | ||||
| From: Yu Zhao <yuzhao@google.com> | ||||
| Date: Wed, 21 Dec 2022 21:18:59 -0700 | ||||
| Subject: [PATCH 21/29] mm: multi-gen LRU: rename lru_gen_struct to | ||||
|  lru_gen_page | ||||
|  lru_gen_folio | ||||
|  | ||||
| Patch series "mm: multi-gen LRU: memcg LRU", v3. | ||||
|  | ||||
| @@ -10,7 +10,7 @@ Overview | ||||
| ======== | ||||
|  | ||||
| An memcg LRU is a per-node LRU of memcgs.  It is also an LRU of LRUs, | ||||
| since each node and memcg combination has an LRU of pages (see | ||||
| since each node and memcg combination has an LRU of folios (see | ||||
| mem_cgroup_lruvec()). | ||||
|  | ||||
| Its goal is to improve the scalability of global reclaim, which is | ||||
| @@ -24,7 +24,7 @@ the worst-case complexity O(n).  Therefore, on average, it has a sublinear | ||||
| complexity in contrast to the current linear complexity. | ||||
|  | ||||
| The basic structure of an memcg LRU can be understood by an analogy to | ||||
| the active/inactive LRU (of pages): | ||||
| the active/inactive LRU (of folios): | ||||
| 1. It has the young and the old (generations), i.e., the counterparts | ||||
|    to the active and the inactive; | ||||
| 2. The increment of max_seq triggers promotion, i.e., the counterpart | ||||
| @@ -101,7 +101,7 @@ The following is a simple test to quickly verify its effectiveness. | ||||
|  | ||||
| This patch (of 8): | ||||
|  | ||||
| The new name lru_gen_page will be more distinct from the coming | ||||
| The new name lru_gen_folio will be more distinct from the coming | ||||
| lru_gen_memcg. | ||||
|  | ||||
| Link: https://lkml.kernel.org/r/20221222041905.2431096-1-yuzhao@google.com | ||||
| @@ -125,31 +125,31 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| --- a/include/linux/mm_inline.h | ||||
| +++ b/include/linux/mm_inline.h | ||||
| @@ -168,7 +168,7 @@ static inline void lru_gen_update_size(s | ||||
|  	int zone = page_zonenum(page); | ||||
|  	int delta = thp_nr_pages(page); | ||||
|  	int zone = folio_zonenum(folio); | ||||
|  	int delta = thp_nr_folios(folio); | ||||
|  	enum lru_list lru = type * LRU_INACTIVE_FILE; | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|   | ||||
|  	VM_WARN_ON_ONCE(old_gen != -1 && old_gen >= MAX_NR_GENS); | ||||
|  	VM_WARN_ON_ONCE(new_gen != -1 && new_gen >= MAX_NR_GENS); | ||||
| @@ -214,7 +214,7 @@ static inline bool lru_gen_add_page(stru | ||||
|  	int gen = page_lru_gen(page); | ||||
|  	int type = page_is_file_lru(page); | ||||
|  	int zone = page_zonenum(page); | ||||
| @@ -214,7 +214,7 @@ static inline bool lru_gen_add_folio(stru | ||||
|  	int gen = folio_lru_gen(folio); | ||||
|  	int type = folio_is_file_lru(folio); | ||||
|  	int zone = folio_zonenum(folio); | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|   | ||||
|  	VM_WARN_ON_ONCE_PAGE(gen != -1, page); | ||||
|  	VM_WARN_ON_ONCE_FOLIO(gen != -1, folio); | ||||
|   | ||||
| --- a/include/linux/mmzone.h | ||||
| +++ b/include/linux/mmzone.h | ||||
| @@ -394,7 +394,7 @@ enum { | ||||
|   * The number of pages in each generation is eventually consistent and therefore | ||||
|   * The number of folios in each generation is eventually consistent and therefore | ||||
|   * can be transiently negative when reset_batch_size() is pending. | ||||
|   */ | ||||
| -struct lru_gen_struct { | ||||
| +struct lru_gen_page { | ||||
| +struct lru_gen_folio { | ||||
|  	/* the aging increments the youngest generation number */ | ||||
|  	unsigned long max_seq; | ||||
|  	/* the eviction increments the oldest generation numbers */ | ||||
| @@ -158,7 +158,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	/* the lruvec under reclaim */ | ||||
|  	struct lruvec *lruvec; | ||||
| -	/* unstable max_seq from lru_gen_struct */ | ||||
| +	/* unstable max_seq from lru_gen_page */ | ||||
| +	/* unstable max_seq from lru_gen_folio */ | ||||
|  	unsigned long max_seq; | ||||
|  	/* the next address within an mm to scan */ | ||||
|  	unsigned long next_addr; | ||||
| @@ -167,7 +167,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  #ifdef CONFIG_LRU_GEN | ||||
|  	/* evictable pages divided into generations */ | ||||
| -	struct lru_gen_struct		lrugen; | ||||
| +	struct lru_gen_page		lrugen; | ||||
| +	struct lru_gen_folio		lrugen; | ||||
|  	/* to concurrently iterate lru_gen_mm_list */ | ||||
|  	struct lru_gen_mm_state		mm_state; | ||||
|  #endif | ||||
| @@ -178,7 +178,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) | ||||
|  { | ||||
| -	/* see the comment on lru_gen_struct */ | ||||
| +	/* see the comment on lru_gen_page */ | ||||
| +	/* see the comment on lru_gen_folio */ | ||||
|  	return get_nr_gens(lruvec, LRU_GEN_FILE) >= MIN_NR_GENS && | ||||
|  	       get_nr_gens(lruvec, LRU_GEN_FILE) <= get_nr_gens(lruvec, LRU_GEN_ANON) && | ||||
|  	       get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; | ||||
| @@ -187,7 +187,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  			  struct ctrl_pos *pos) | ||||
|  { | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|  	int hist = lru_hist_from_seq(lrugen->min_seq[type]); | ||||
|   | ||||
|  	pos->refaulted = lrugen->avg_refaulted[type][tier] + | ||||
| @@ -196,25 +196,25 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  { | ||||
|  	int hist, tier; | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|  	bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; | ||||
|  	unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; | ||||
|   | ||||
| @@ -3408,7 +3408,7 @@ static int page_update_gen(struct page * | ||||
|  static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) | ||||
| @@ -3408,7 +3408,7 @@ static int folio_update_gen(struct folio * | ||||
|  static int folio_inc_gen(struct lruvec *lruvec, struct folio *folio, bool reclaiming) | ||||
|  { | ||||
|  	int type = page_is_file_lru(page); | ||||
|  	int type = folio_is_file_lru(folio); | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|  	int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); | ||||
|  	unsigned long new_flags, old_flags = READ_ONCE(page->flags); | ||||
|  	unsigned long new_flags, old_flags = READ_ONCE(folio->flags); | ||||
|   | ||||
| @@ -3453,7 +3453,7 @@ static void update_batch_size(struct lru | ||||
|  static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) | ||||
|  { | ||||
|  	int gen, type, zone; | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|   | ||||
|  	walk->batched = 0; | ||||
|   | ||||
| @@ -223,7 +223,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	int zone; | ||||
|  	int remaining = MAX_LRU_BATCH; | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|  	int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); | ||||
|   | ||||
|  	if (type == LRU_GEN_ANON && !can_swap) | ||||
| @@ -232,7 +232,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	int gen, type, zone; | ||||
|  	bool success = false; | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|  	DEFINE_MIN_SEQ(lruvec); | ||||
|   | ||||
|  	VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); | ||||
| @@ -241,7 +241,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	} | ||||
|   | ||||
| -	/* see the comment on lru_gen_struct */ | ||||
| +	/* see the comment on lru_gen_page */ | ||||
| +	/* see the comment on lru_gen_folio */ | ||||
|  	if (can_swap) { | ||||
|  		min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); | ||||
|  		min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); | ||||
| @@ -250,7 +250,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	int prev, next; | ||||
|  	int type, zone; | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|   | ||||
|  	spin_lock_irq(&lruvec->lru_lock); | ||||
|   | ||||
| @@ -259,7 +259,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	struct lru_gen_mm_walk *walk; | ||||
|  	struct mm_struct *mm = NULL; | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|   | ||||
|  	VM_WARN_ON_ONCE(max_seq > READ_ONCE(lrugen->max_seq)); | ||||
|   | ||||
| @@ -268,25 +268,25 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	unsigned long young = 0; | ||||
|  	unsigned long total = 0; | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|  	struct mem_cgroup *memcg = lruvec_memcg(lruvec); | ||||
|   | ||||
|  	for (type = !can_swap; type < ANON_AND_FILE; type++) { | ||||
| @@ -4466,7 +4466,7 @@ static bool sort_page(struct lruvec *lru | ||||
|  	int delta = thp_nr_pages(page); | ||||
|  	int refs = page_lru_refs(page); | ||||
| @@ -4466,7 +4466,7 @@ static bool sort_folio(struct lruvec *lru | ||||
|  	int delta = thp_nr_folios(folio); | ||||
|  	int refs = folio_lru_refs(folio); | ||||
|  	int tier = lru_tier_from_refs(refs); | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|   | ||||
|  	VM_WARN_ON_ONCE_PAGE(gen >= MAX_NR_GENS, page); | ||||
|  	VM_WARN_ON_ONCE_folio(gen >= MAX_NR_GENS, folio); | ||||
|   | ||||
| @@ -4566,7 +4566,7 @@ static int scan_pages(struct lruvec *lru | ||||
| @@ -4566,7 +4566,7 @@ static int scan_folios(struct lruvec *lru | ||||
|  	int scanned = 0; | ||||
|  	int isolated = 0; | ||||
|  	int remaining = MAX_LRU_BATCH; | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|  	struct mem_cgroup *memcg = lruvec_memcg(lruvec); | ||||
|   | ||||
|  	VM_WARN_ON_ONCE(!list_empty(list)); | ||||
| @@ -295,7 +295,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  static bool __maybe_unused state_is_valid(struct lruvec *lruvec) | ||||
|  { | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|   | ||||
|  	if (lrugen->enabled) { | ||||
|  		enum lru_list lru; | ||||
| @@ -304,7 +304,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	int type, tier; | ||||
|  	int hist = lru_hist_from_seq(seq); | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|   | ||||
|  	for (tier = 0; tier < MAX_NR_TIERS; tier++) { | ||||
|  		seq_printf(m, "            %10d", tier); | ||||
| @@ -313,7 +313,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	bool full = !debugfs_real_fops(m->file)->write; | ||||
|  	struct lruvec *lruvec = v; | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|  	int nid = lruvec_pgdat(lruvec)->node_id; | ||||
|  	struct mem_cgroup *memcg = lruvec_memcg(lruvec); | ||||
|  	DEFINE_MAX_SEQ(lruvec); | ||||
| @@ -322,7 +322,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	int i; | ||||
|  	int gen, type, zone; | ||||
| -	struct lru_gen_struct *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|   | ||||
|  	lrugen->max_seq = MIN_NR_GENS + 1; | ||||
|  	lrugen->enabled = lru_gen_enabled(); | ||||
| @@ -333,16 +333,16 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	unsigned long min_seq; | ||||
|  	struct lruvec *lruvec; | ||||
| -	struct lru_gen_struct *lrugen; | ||||
| +	struct lru_gen_page *lrugen; | ||||
|  	int type = page_is_file_lru(page); | ||||
|  	int delta = thp_nr_pages(page); | ||||
|  	int refs = page_lru_refs(page); | ||||
| @@ -252,7 +252,7 @@ static void lru_gen_refault(struct page | ||||
| +	struct lru_gen_folio *lrugen; | ||||
|  	int type = folio_is_file_lru(folio); | ||||
|  	int delta = thp_nr_folios(folio); | ||||
|  	int refs = folio_lru_refs(folio); | ||||
| @@ -252,7 +252,7 @@ static void lru_gen_refault(struct folio | ||||
|  	unsigned long token; | ||||
|  	unsigned long min_seq; | ||||
|  	struct lruvec *lruvec; | ||||
| -	struct lru_gen_struct *lrugen; | ||||
| +	struct lru_gen_page *lrugen; | ||||
| +	struct lru_gen_folio *lrugen; | ||||
|  	struct mem_cgroup *memcg; | ||||
|  	struct pglist_data *pgdat; | ||||
|  	int type = page_is_file_lru(page); | ||||
|  	int type = folio_is_file_lru(folio); | ||||
|   | ||||
| @@ -2,9 +2,9 @@ From afd37e73db04c7e6b47411120ac5f6a7eca51fec Mon Sep 17 00:00:00 2001 | ||||
| From: Yu Zhao <yuzhao@google.com> | ||||
| Date: Wed, 21 Dec 2022 21:19:00 -0700 | ||||
| Subject: [PATCH 22/29] mm: multi-gen LRU: rename lrugen->lists[] to | ||||
|  lrugen->pages[] | ||||
|  lrugen->folios[] | ||||
|  | ||||
| lru_gen_page will be chained into per-node lists by the coming | ||||
| lru_gen_folio will be chained into per-node lists by the coming | ||||
| lrugen->list. | ||||
|  | ||||
| Link: https://lkml.kernel.org/r/20221222041905.2431096-3-yuzhao@google.com | ||||
| @@ -25,15 +25,15 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  | ||||
| --- a/include/linux/mm_inline.h | ||||
| +++ b/include/linux/mm_inline.h | ||||
| @@ -246,9 +246,9 @@ static inline bool lru_gen_add_page(stru | ||||
|  	lru_gen_update_size(lruvec, page, -1, gen); | ||||
|  	/* for rotate_reclaimable_page() */ | ||||
| @@ -246,9 +246,9 @@ static inline bool lru_gen_add_folio(stru | ||||
|  	lru_gen_update_size(lruvec, folio, -1, gen); | ||||
|  	/* for rotate_reclaimable_folio() */ | ||||
|  	if (reclaiming) | ||||
| -		list_add_tail(&page->lru, &lrugen->lists[gen][type][zone]); | ||||
| +		list_add_tail(&page->lru, &lrugen->pages[gen][type][zone]); | ||||
| -		list_add_tail(&folio->lru, &lrugen->lists[gen][type][zone]); | ||||
| +		list_add_tail(&folio->lru, &lrugen->folios[gen][type][zone]); | ||||
|  	else | ||||
| -		list_add(&page->lru, &lrugen->lists[gen][type][zone]); | ||||
| +		list_add(&page->lru, &lrugen->pages[gen][type][zone]); | ||||
| -		list_add(&folio->lru, &lrugen->lists[gen][type][zone]); | ||||
| +		list_add(&folio->lru, &lrugen->folios[gen][type][zone]); | ||||
|   | ||||
|  	return true; | ||||
|  } | ||||
| @@ -42,31 +42,31 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| @@ -302,7 +302,7 @@ enum lruvec_flags { | ||||
|   * They form a sliding window of a variable size [MIN_NR_GENS, MAX_NR_GENS]. An | ||||
|   * offset within MAX_NR_GENS, i.e., gen, indexes the LRU list of the | ||||
|   * corresponding generation. The gen counter in page->flags stores gen+1 while | ||||
|   * corresponding generation. The gen counter in folio->flags stores gen+1 while | ||||
| - * a page is on one of lrugen->lists[]. Otherwise it stores 0. | ||||
| + * a page is on one of lrugen->pages[]. Otherwise it stores 0. | ||||
| + * a page is on one of lrugen->folios[]. Otherwise it stores 0. | ||||
|   * | ||||
|   * A page is added to the youngest generation on faulting. The aging needs to | ||||
|   * check the accessed bit at least twice before handing this page over to the | ||||
|   * A folio is added to the youngest generation on faulting. The aging needs to | ||||
|   * check the accessed bit at least twice before handing this folio over to the | ||||
| @@ -314,8 +314,8 @@ enum lruvec_flags { | ||||
|   * rest of generations, if they exist, are considered inactive. See | ||||
|   * lru_gen_is_active(). | ||||
|   * | ||||
| - * PG_active is always cleared while a page is on one of lrugen->lists[] so that | ||||
| - * the aging needs not to worry about it. And it's set again when a page | ||||
| + * PG_active is always cleared while a page is on one of lrugen->pages[] so | ||||
| + * PG_active is always cleared while a page is on one of lrugen->folios[] so | ||||
| + * that the aging needs not to worry about it. And it's set again when a page | ||||
|   * considered active is isolated for non-reclaiming purposes, e.g., migration. | ||||
|   * See lru_gen_add_page() and lru_gen_del_page(). | ||||
|   * See lru_gen_add_folio() and lru_gen_del_folio(). | ||||
|   * | ||||
| @@ -402,7 +402,7 @@ struct lru_gen_page { | ||||
| @@ -402,7 +402,7 @@ struct lru_gen_folio { | ||||
|  	/* the birth time of each generation in jiffies */ | ||||
|  	unsigned long timestamps[MAX_NR_GENS]; | ||||
|  	/* the multi-gen LRU lists, lazily sorted on eviction */ | ||||
| -	struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; | ||||
| +	struct list_head pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; | ||||
| +	struct list_head folios[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; | ||||
|  	/* the multi-gen LRU sizes, eventually consistent */ | ||||
|  	long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; | ||||
|  	long nr_folios[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; | ||||
|  	/* the exponential moving average of refaulted */ | ||||
| --- a/mm/vmscan.c | ||||
| +++ b/mm/vmscan.c | ||||
| @@ -75,16 +75,16 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	/* prevent cold/hot inversion if force_scan is true */ | ||||
|  	for (zone = 0; zone < MAX_NR_ZONES; zone++) { | ||||
| -		struct list_head *head = &lrugen->lists[old_gen][type][zone]; | ||||
| +		struct list_head *head = &lrugen->pages[old_gen][type][zone]; | ||||
| +		struct list_head *head = &lrugen->folios[old_gen][type][zone]; | ||||
|   | ||||
|  		while (!list_empty(head)) { | ||||
|  			struct page *page = lru_to_page(head); | ||||
|  			struct folio *folio = lru_to_folio(head); | ||||
| @@ -3998,7 +3998,7 @@ static bool inc_min_seq(struct lruvec *l | ||||
|  			VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); | ||||
|  			VM_WARN_ON_ONCE_folio(folio_zonenum(folio) != zone, folio); | ||||
|   | ||||
|  			new_gen = page_inc_gen(lruvec, page, false); | ||||
| -			list_move_tail(&page->lru, &lrugen->lists[new_gen][type][zone]); | ||||
| +			list_move_tail(&page->lru, &lrugen->pages[new_gen][type][zone]); | ||||
|  			new_gen = folio_inc_gen(lruvec, folio, false); | ||||
| -			list_move_tail(&folio->lru, &lrugen->lists[new_gen][type][zone]); | ||||
| +			list_move_tail(&folio->lru, &lrugen->folios[new_gen][type][zone]); | ||||
|   | ||||
|  			if (!--remaining) | ||||
|  				return false; | ||||
| @@ -93,52 +93,52 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|   | ||||
|  			for (zone = 0; zone < MAX_NR_ZONES; zone++) { | ||||
| -				if (!list_empty(&lrugen->lists[gen][type][zone])) | ||||
| +				if (!list_empty(&lrugen->pages[gen][type][zone])) | ||||
| +				if (!list_empty(&lrugen->folios[gen][type][zone])) | ||||
|  					goto next; | ||||
|  			} | ||||
|   | ||||
| @@ -4491,7 +4491,7 @@ static bool sort_page(struct lruvec *lru | ||||
| @@ -4491,7 +4491,7 @@ static bool sort_folio(struct lruvec *lru | ||||
|   | ||||
|  	/* promoted */ | ||||
|  	if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { | ||||
| -		list_move(&page->lru, &lrugen->lists[gen][type][zone]); | ||||
| +		list_move(&page->lru, &lrugen->pages[gen][type][zone]); | ||||
| -		list_move(&folio->lru, &lrugen->lists[gen][type][zone]); | ||||
| +		list_move(&folio->lru, &lrugen->folios[gen][type][zone]); | ||||
|  		return true; | ||||
|  	} | ||||
|   | ||||
| @@ -4500,7 +4500,7 @@ static bool sort_page(struct lruvec *lru | ||||
| @@ -4500,7 +4500,7 @@ static bool sort_folio(struct lruvec *lru | ||||
|  		int hist = lru_hist_from_seq(lrugen->min_seq[type]); | ||||
|   | ||||
|  		gen = page_inc_gen(lruvec, page, false); | ||||
| -		list_move_tail(&page->lru, &lrugen->lists[gen][type][zone]); | ||||
| +		list_move_tail(&page->lru, &lrugen->pages[gen][type][zone]); | ||||
|  		gen = folio_inc_gen(lruvec, folio, false); | ||||
| -		list_move_tail(&folio->lru, &lrugen->lists[gen][type][zone]); | ||||
| +		list_move_tail(&folio->lru, &lrugen->folios[gen][type][zone]); | ||||
|   | ||||
|  		WRITE_ONCE(lrugen->protected[hist][type][tier - 1], | ||||
|  			   lrugen->protected[hist][type][tier - 1] + delta); | ||||
| @@ -4512,7 +4512,7 @@ static bool sort_page(struct lruvec *lru | ||||
|  	if (PageLocked(page) || PageWriteback(page) || | ||||
|  	    (type == LRU_GEN_FILE && PageDirty(page))) { | ||||
|  		gen = page_inc_gen(lruvec, page, true); | ||||
| -		list_move(&page->lru, &lrugen->lists[gen][type][zone]); | ||||
| +		list_move(&page->lru, &lrugen->pages[gen][type][zone]); | ||||
| @@ -4512,7 +4512,7 @@ static bool sort_folio(struct lruvec *lru | ||||
|  	if (folioLocked(folio) || folioWriteback(folio) || | ||||
|  	    (type == LRU_GEN_FILE && folioDirty(folio))) { | ||||
|  		gen = folio_inc_gen(lruvec, folio, true); | ||||
| -		list_move(&folio->lru, &lrugen->lists[gen][type][zone]); | ||||
| +		list_move(&folio->lru, &lrugen->folios[gen][type][zone]); | ||||
|  		return true; | ||||
|  	} | ||||
|   | ||||
| @@ -4579,7 +4579,7 @@ static int scan_pages(struct lruvec *lru | ||||
| @@ -4579,7 +4579,7 @@ static int scan_folios(struct lruvec *lru | ||||
|  	for (zone = sc->reclaim_idx; zone >= 0; zone--) { | ||||
|  		LIST_HEAD(moved); | ||||
|  		int skipped = 0; | ||||
| -		struct list_head *head = &lrugen->lists[gen][type][zone]; | ||||
| +		struct list_head *head = &lrugen->pages[gen][type][zone]; | ||||
| +		struct list_head *head = &lrugen->folios[gen][type][zone]; | ||||
|   | ||||
|  		while (!list_empty(head)) { | ||||
|  			struct page *page = lru_to_page(head); | ||||
|  			struct folio *folio = lru_to_folio(head); | ||||
| @@ -4980,7 +4980,7 @@ static bool __maybe_unused state_is_vali | ||||
|  		int gen, type, zone; | ||||
|   | ||||
|  		for_each_gen_type_zone(gen, type, zone) { | ||||
| -			if (!list_empty(&lrugen->lists[gen][type][zone])) | ||||
| +			if (!list_empty(&lrugen->pages[gen][type][zone])) | ||||
| +			if (!list_empty(&lrugen->folios[gen][type][zone])) | ||||
|  				return false; | ||||
|  		} | ||||
|  	} | ||||
| @@ -147,7 +147,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|   | ||||
|  	for_each_gen_type_zone(gen, type, zone) { | ||||
| -		struct list_head *head = &lruvec->lrugen.lists[gen][type][zone]; | ||||
| +		struct list_head *head = &lruvec->lrugen.pages[gen][type][zone]; | ||||
| +		struct list_head *head = &lruvec->lrugen.folios[gen][type][zone]; | ||||
|   | ||||
|  		while (!list_empty(head)) { | ||||
|  			bool success; | ||||
| @@ -156,7 +156,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|   | ||||
|  	for_each_gen_type_zone(gen, type, zone) | ||||
| -		INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); | ||||
| +		INIT_LIST_HEAD(&lrugen->pages[gen][type][zone]); | ||||
| +		INIT_LIST_HEAD(&lrugen->folios[gen][type][zone]); | ||||
|   | ||||
|  	lruvec->mm_state.seq = MIN_NR_GENS; | ||||
|  	init_waitqueue_head(&lruvec->mm_state.wait); | ||||
|   | ||||
| @@ -4,7 +4,7 @@ Date: Wed, 21 Dec 2022 21:19:01 -0700 | ||||
| Subject: [PATCH 23/29] mm: multi-gen LRU: remove eviction fairness safeguard | ||||
|  | ||||
| Recall that the eviction consumes the oldest generation: first it | ||||
| bucket-sorts pages whose gen counters were updated by the aging and | ||||
| bucket-sorts folios whose gen counters were updated by the aging and | ||||
| reclaims the rest; then it increments lrugen->min_seq. | ||||
|  | ||||
| The current eviction fairness safeguard for global reclaim has a | ||||
| @@ -61,13 +61,13 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  static bool writeback_throttling_sane(struct scan_control *sc) | ||||
|  { | ||||
|  	return true; | ||||
| @@ -4722,8 +4732,7 @@ static int isolate_pages(struct lruvec * | ||||
| @@ -4722,8 +4732,7 @@ static int isolate_folios(struct lruvec * | ||||
|  	return scanned; | ||||
|  } | ||||
|   | ||||
| -static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, | ||||
| -static int evict_folios(struct lruvec *lruvec, struct scan_control *sc, int swappiness, | ||||
| -			bool *need_swapping) | ||||
| +static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness) | ||||
| +static int evict_folios(struct lruvec *lruvec, struct scan_control *sc, int swappiness) | ||||
|  { | ||||
|  	int type; | ||||
|  	int scanned; | ||||
| @@ -81,7 +81,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	return scanned; | ||||
|  } | ||||
|   | ||||
| @@ -4853,68 +4859,26 @@ done: | ||||
| @@ -4853,67 +4859,26 @@ done: | ||||
|  	return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; | ||||
|  } | ||||
|   | ||||
| @@ -93,7 +93,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| -	DEFINE_MAX_SEQ(lruvec); | ||||
| - | ||||
| -	if (!current_is_kswapd()) { | ||||
| -		/* age each memcg once to ensure fairness */ | ||||
| -		/* age each memcg at most once to ensure fairness */ | ||||
| -		if (max_seq - seq > 1) | ||||
| -			return true; | ||||
| - | ||||
| @@ -118,10 +118,9 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| - | ||||
| -	/* | ||||
| -	 * A minimum amount of work was done under global memory pressure. For | ||||
| -	 * kswapd, it may be overshooting. For direct reclaim, the target isn't | ||||
| -	 * met, and yet the allocation may still succeed, since kswapd may have | ||||
| -	 * caught up. In either case, it's better to stop now, and restart if | ||||
| -	 * necessary. | ||||
| -	 * kswapd, it may be overshooting. For direct reclaim, the allocation | ||||
| -	 * may succeed if all suitable zones are somewhat safe. In either case, | ||||
| -	 * it's better to stop now, and restart later if necessary. | ||||
| -	 */ | ||||
| -	for (i = 0; i <= sc->reclaim_idx; i++) { | ||||
| -		unsigned long wmark; | ||||
| @@ -163,8 +162,8 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  		if (!nr_to_scan) | ||||
|  			goto done; | ||||
|   | ||||
| -		delta = evict_pages(lruvec, sc, swappiness, &need_swapping); | ||||
| +		delta = evict_pages(lruvec, sc, swappiness); | ||||
| -		delta = evict_folios(lruvec, sc, swappiness, &need_swapping); | ||||
| +		delta = evict_folios(lruvec, sc, swappiness); | ||||
|  		if (!delta) | ||||
|  			goto done; | ||||
|   | ||||
| @@ -181,8 +180,8 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  		if (sc->nr_reclaimed >= nr_to_reclaim) | ||||
|  			return 0; | ||||
|   | ||||
| -		if (!evict_pages(lruvec, sc, swappiness, NULL)) | ||||
| +		if (!evict_pages(lruvec, sc, swappiness)) | ||||
| -		if (!evict_folios(lruvec, sc, swappiness, NULL)) | ||||
| +		if (!evict_folios(lruvec, sc, swappiness)) | ||||
|  			return 0; | ||||
|   | ||||
|  		cond_resched(); | ||||
|   | ||||
| @@ -4,13 +4,13 @@ Date: Wed, 21 Dec 2022 21:19:02 -0700 | ||||
| Subject: [PATCH 24/29] mm: multi-gen LRU: remove aging fairness safeguard | ||||
|  | ||||
| Recall that the aging produces the youngest generation: first it scans | ||||
| for accessed pages and updates their gen counters; then it increments | ||||
| for accessed folios and updates their gen counters; then it increments | ||||
| lrugen->max_seq. | ||||
|  | ||||
| The current aging fairness safeguard for kswapd uses two passes to | ||||
| ensure the fairness to multiple eligible memcgs. On the first pass, | ||||
| which is shared with the eviction, it checks whether all eligible | ||||
| memcgs are low on cold pages. If so, it requires a second pass, on | ||||
| memcgs are low on cold folios. If so, it requires a second pass, on | ||||
| which it ages all those memcgs at the same time. | ||||
|  | ||||
| With memcg LRU, the aging, while ensuring eventual fairness, will run | ||||
| @@ -56,11 +56,11 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	int gen, type, zone; | ||||
| @@ -4193,6 +4192,13 @@ static bool should_run_aging(struct lruv | ||||
|  	unsigned long total = 0; | ||||
|  	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
|  	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|  	struct mem_cgroup *memcg = lruvec_memcg(lruvec); | ||||
| +	DEFINE_MIN_SEQ(lruvec); | ||||
| + | ||||
| +	/* whether this lruvec is completely out of cold pages */ | ||||
| +	/* whether this lruvec is completely out of cold folios */ | ||||
| +	if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { | ||||
| +		*nr_to_scan = 0; | ||||
| +		return true; | ||||
| @@ -90,7 +90,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| +	int gen, type, zone; | ||||
| +	unsigned long total = 0; | ||||
| +	bool can_swap = get_swappiness(lruvec, sc); | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
|  	struct mem_cgroup *memcg = lruvec_memcg(lruvec); | ||||
|  	DEFINE_MAX_SEQ(lruvec); | ||||
|  	DEFINE_MIN_SEQ(lruvec); | ||||
| @@ -134,7 +134,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| -		if (!nr_to_scan && sc->priority != DEF_PRIORITY) | ||||
| -			return false; | ||||
| -	} | ||||
| +	/* see the comment on lru_gen_page */ | ||||
| +	/* see the comment on lru_gen_folio */ | ||||
| +	gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); | ||||
| +	birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); | ||||
|   | ||||
| @@ -242,7 +242,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| -		return nr_to_scan; | ||||
| -done: | ||||
| -	return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; | ||||
| +	/* skip this lruvec as it's low on cold pages */ | ||||
| +	/* skip this lruvec as it's low on cold folios */ | ||||
| +	return 0; | ||||
|  } | ||||
|   | ||||
| @@ -267,7 +267,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| -			goto done; | ||||
| +			break; | ||||
|   | ||||
|  		delta = evict_pages(lruvec, sc, swappiness); | ||||
|  		delta = evict_folios(lruvec, sc, swappiness); | ||||
|  		if (!delta) | ||||
| -			goto done; | ||||
| +			break; | ||||
|   | ||||
| @@ -32,11 +32,11 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| -	unsigned long old = 0; | ||||
| -	unsigned long young = 0; | ||||
| -	unsigned long total = 0; | ||||
| -	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| -	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
| -	struct mem_cgroup *memcg = lruvec_memcg(lruvec); | ||||
| -	DEFINE_MIN_SEQ(lruvec); | ||||
| - | ||||
| -	/* whether this lruvec is completely out of cold pages */ | ||||
| -	/* whether this lruvec is completely out of cold folios */ | ||||
| -	if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { | ||||
| -		*nr_to_scan = 0; | ||||
| -		return true; | ||||
| @@ -101,11 +101,11 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| +	unsigned long old = 0; | ||||
| +	unsigned long young = 0; | ||||
| +	unsigned long total = 0; | ||||
| +	struct lru_gen_page *lrugen = &lruvec->lrugen; | ||||
| +	struct lru_gen_folio *lrugen = &lruvec->lrugen; | ||||
| +	struct mem_cgroup *memcg = lruvec_memcg(lruvec); | ||||
| +	DEFINE_MIN_SEQ(lruvec); | ||||
| + | ||||
| +	/* whether this lruvec is completely out of cold pages */ | ||||
| +	/* whether this lruvec is completely out of cold folios */ | ||||
| +	if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { | ||||
| +		*nr_to_scan = 0; | ||||
| +		return true; | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| From fa6363828d314e837c5f79e97ea5e8c0d2f7f062 Mon Sep 17 00:00:00 2001 | ||||
| From: Yu Zhao <yuzhao@google.com> | ||||
| Date: Wed, 21 Dec 2022 21:19:04 -0700 | ||||
| Subject: [PATCH 26/29] mm: multi-gen LRU: per-node lru_gen_page lists | ||||
| Subject: [PATCH 26/29] mm: multi-gen LRU: per-node lru_gen_folio lists | ||||
|  | ||||
| For each node, memcgs are divided into two generations: the old and | ||||
| the young. For each generation, memcgs are randomly sharded into | ||||
| @@ -63,7 +63,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  include/linux/mm_inline.h  |  17 ++ | ||||
|  include/linux/mmzone.h     | 117 +++++++++++- | ||||
|  mm/memcontrol.c            |  16 ++ | ||||
|  mm/page_alloc.c            |   1 + | ||||
|  mm/folio_alloc.c            |   1 + | ||||
|  mm/vmscan.c                | 373 +++++++++++++++++++++++++++++++++---- | ||||
|  6 files changed, 499 insertions(+), 35 deletions(-) | ||||
|  | ||||
| @@ -123,7 +123,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
|  static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) | ||||
|  static inline bool lru_gen_add_folio(struct lruvec *lruvec, struct folio *folio, bool reclaiming) | ||||
|  { | ||||
|  	return false; | ||||
| --- a/include/linux/mmzone.h | ||||
| @@ -136,7 +136,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  #include <linux/wait.h> | ||||
|  #include <linux/bitops.h> | ||||
|  #include <linux/cache.h> | ||||
| @@ -357,6 +358,15 @@ struct page_vma_mapped_walk; | ||||
| @@ -357,6 +358,15 @@ struct folio_vma_mapped_walk; | ||||
|  #define LRU_GEN_MASK		((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) | ||||
|  #define LRU_REFS_MASK		((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) | ||||
|   | ||||
| @@ -152,16 +152,16 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  #ifdef CONFIG_LRU_GEN | ||||
|   | ||||
|  enum { | ||||
| @@ -416,6 +426,14 @@ struct lru_gen_page { | ||||
| @@ -416,6 +426,14 @@ struct lru_gen_folio { | ||||
|  	atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; | ||||
|  	/* whether the multi-gen LRU is enabled */ | ||||
|  	bool enabled; | ||||
| +#ifdef CONFIG_MEMCG | ||||
| +	/* the memcg generation this lru_gen_page belongs to */ | ||||
| +	/* the memcg generation this lru_gen_folio belongs to */ | ||||
| +	u8 gen; | ||||
| +	/* the list segment this lru_gen_page belongs to */ | ||||
| +	/* the list segment this lru_gen_folio belongs to */ | ||||
| +	u8 seg; | ||||
| +	/* per-node lru_gen_page list for global reclaim */ | ||||
| +	/* per-node lru_gen_folio list for global reclaim */ | ||||
| +	struct hlist_nulls_node list; | ||||
| +#endif | ||||
|  }; | ||||
| @@ -216,9 +216,9 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| +struct lru_gen_memcg { | ||||
| +	/* the per-node memcg generation counter */ | ||||
| +	unsigned long seq; | ||||
| +	/* each memcg has one lru_gen_page per node */ | ||||
| +	/* each memcg has one lru_gen_folio per node */ | ||||
| +	unsigned long nr_memcgs[MEMCG_NR_GENS]; | ||||
| +	/* per-node lru_gen_page list for global reclaim */ | ||||
| +	/* per-node lru_gen_folio list for global reclaim */ | ||||
| +	struct hlist_nulls_head	fifo[MEMCG_NR_GENS][MEMCG_NR_BINS]; | ||||
| +	/* protects the above */ | ||||
| +	spinlock_t lock; | ||||
| @@ -294,7 +294,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  #ifdef CONFIG_LRU_GEN | ||||
|  	/* kswap mm walk data */ | ||||
|  	struct lru_gen_mm_walk	mm_walk; | ||||
| +	/* lru_gen_page list */ | ||||
| +	/* lru_gen_folio list */ | ||||
| +	struct lru_gen_memcg memcg_lru; | ||||
|  #endif | ||||
|   | ||||
| @@ -306,7 +306,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	struct mem_cgroup_tree_per_node *mctz; | ||||
|   | ||||
| +	if (lru_gen_enabled()) { | ||||
| +		struct lruvec *lruvec = &mem_cgroup_page_nodeinfo(memcg, page)->lruvec; | ||||
| +		struct lruvec *lruvec = &memcg->nodeinfo[nid]->lruvec; | ||||
| + | ||||
| +		/* see the comment on MEMCG_NR_GENS */ | ||||
| +		if (soft_limit_excess(memcg) && lru_gen_memcg_seg(lruvec) != MEMCG_LRU_HEAD) | ||||
| @@ -315,7 +315,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| +		return; | ||||
| +	} | ||||
| + | ||||
|  	mctz = soft_limit_tree_from_page(page); | ||||
|  	mctz = soft_limit_tree.rb_tree_per_node[nid]; | ||||
|  	if (!mctz) | ||||
|  		return; | ||||
| @@ -3433,6 +3443,9 @@ unsigned long mem_cgroup_soft_limit_recl | ||||
| @@ -430,7 +430,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|   | ||||
| -	try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false); | ||||
| - | ||||
|  	/* skip this lruvec as it's low on cold pages */ | ||||
|  	/* skip this lruvec as it's low on cold folios */ | ||||
| -	return 0; | ||||
| +	return try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false) ? -1 : 0; | ||||
|  } | ||||
| @@ -476,7 +476,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| +		if (nr_to_scan <= 0) | ||||
|  			break; | ||||
|   | ||||
|  		delta = evict_pages(lruvec, sc, swappiness); | ||||
|  		delta = evict_folios(lruvec, sc, swappiness); | ||||
| @@ -4912,10 +4895,250 @@ static void lru_gen_shrink_lruvec(struct | ||||
|  		cond_resched(); | ||||
|  	} | ||||
| @@ -532,7 +532,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| +	int bin; | ||||
| +	int first_bin; | ||||
| +	struct lruvec *lruvec; | ||||
| +	struct lru_gen_page *lrugen; | ||||
| +	struct lru_gen_folio *lrugen; | ||||
| +	const struct hlist_nulls_node *pos; | ||||
| +	int op = 0; | ||||
| +	struct mem_cgroup *memcg = NULL; | ||||
|   | ||||
| @@ -10,10 +10,10 @@ Among the flags in scan_control: | ||||
|    opportunistically skip the aging path, since it is considered less | ||||
|    latency sensitive. | ||||
| 3. !(sc->gfp_mask & __GFP_IO), which indicates IO constraint, lowers | ||||
|    swappiness to prioritize file LRU, since clean file pages are more | ||||
|    swappiness to prioritize file LRU, since clean file folios are more | ||||
|    likely to exist. | ||||
| 4. sc->may_writepage and sc->may_unmap, which indicates opportunistic | ||||
|    reclaim, are rejected, since unmapped clean pages are already | ||||
| 4. sc->may_writefolio and sc->may_unmap, which indicates opportunistic | ||||
|    reclaim, are rejected, since unmapped clean folios are already | ||||
|    prioritized. Scanning for more of them is likely futile and can | ||||
|    cause high reclaim latency when there is a large number of memcgs. | ||||
|  | ||||
| @@ -43,7 +43,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
| +		return 0; | ||||
| + | ||||
|  	if (!can_demote(pgdat->node_id, sc) && | ||||
|  	    mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) | ||||
|  	    mem_cgroup_get_nr_swap_folios(memcg) < MIN_LRU_BATCH) | ||||
|  		return 0; | ||||
| @@ -3952,7 +3955,7 @@ static void walk_mm(struct lruvec *lruve | ||||
|  	} while (err == -EAGAIN); | ||||
| @@ -78,24 +78,24 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|   | ||||
| -	VM_WARN_ON_ONCE(sc->memcg_low_reclaim); | ||||
| - | ||||
|  	/* see the comment on lru_gen_page */ | ||||
|  	/* see the comment on lru_gen_folio */ | ||||
|  	gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); | ||||
|  	birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); | ||||
| @@ -4472,12 +4473,8 @@ static bool isolate_page(struct lruvec * | ||||
| @@ -4472,12 +4473,8 @@ static bool isolate_folio(struct lruvec * | ||||
|  { | ||||
|  	bool success; | ||||
|   | ||||
| -	/* unmapping inhibited */ | ||||
| -	if (!sc->may_unmap && page_mapped(page)) | ||||
| -	if (!sc->may_unmap && folio_mapped(folio)) | ||||
| -		return false; | ||||
| - | ||||
|  	/* swapping inhibited */ | ||||
| -	if (!(sc->may_writepage && (sc->gfp_mask & __GFP_IO)) && | ||||
| +	if (!(sc->gfp_mask & __GFP_IO) && | ||||
|  	    (PageDirty(page) || | ||||
|  	     (PageAnon(page) && !PageSwapCache(page)))) | ||||
|  	    (folio_test_dirty(folio) || | ||||
|  	     (folio_test_anon(folio) && !folio_test_swapcache(folio)))) | ||||
|  		return false; | ||||
| @@ -4574,9 +4571,8 @@ static int scan_pages(struct lruvec *lru | ||||
| @@ -4574,9 +4571,8 @@ static int scan_folios(struct lruvec *lru | ||||
|  	__count_vm_events(PGSCAN_ANON + type, isolated); | ||||
|   | ||||
|  	/* | ||||
| @@ -123,7 +123,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); | ||||
| +	int swappiness = get_swappiness(lruvec, sc); | ||||
| + | ||||
| +	/* clean file pages are more likely to exist */ | ||||
| +	/* clean file folios are more likely to exist */ | ||||
| +	if (swappiness && !(sc->gfp_mask & __GFP_IO)) | ||||
| +		swappiness = 1; | ||||
|   | ||||
| @@ -151,7 +151,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	blk_start_plug(&plug); | ||||
|   | ||||
| -	set_mm_walk(lruvec_pgdat(lruvec)); | ||||
| +	set_mm_walk(NULL, false); | ||||
| +	set_mm_walk(NULL, sc->proactive); | ||||
|   | ||||
|  	if (try_to_shrink_lruvec(lruvec, sc)) | ||||
|  		lru_gen_rotate_memcg(lruvec, MEMCG_LRU_YOUNG); | ||||
| @@ -160,7 +160,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	VM_WARN_ON_ONCE(!global_reclaim(sc)); | ||||
|   | ||||
| +	/* | ||||
| +	 * Unmapped clean pages are already prioritized. Scanning for more of | ||||
| +	 * Unmapped clean folios are already prioritized. Scanning for more of | ||||
| +	 * them is likely futile and can cause high reclaim latency when there | ||||
| +	 * is a large number of memcgs. | ||||
| +	 */ | ||||
| @@ -172,7 +172,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	blk_start_plug(&plug); | ||||
|   | ||||
| -	set_mm_walk(pgdat); | ||||
| +	set_mm_walk(pgdat, false); | ||||
| +	set_mm_walk(NULL, sc->proactive); | ||||
|   | ||||
|  	set_initial_priority(pgdat, sc); | ||||
|   | ||||
|   | ||||
| @@ -34,7 +34,7 @@ Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||||
|  	int bin; | ||||
|  	int first_bin; | ||||
|  	struct lruvec *lruvec; | ||||
|  	struct lru_gen_page *lrugen; | ||||
|  	struct lru_gen_folio *lrugen; | ||||
| +	struct mem_cgroup *memcg; | ||||
|  	const struct hlist_nulls_node *pos; | ||||
| -	int op = 0; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Christian Marangi
					Christian Marangi