162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/mm/swap.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * This file contains the default values for the operation of the
1062306a36Sopenharmony_ci * Linux VM subsystem. Fine-tuning documentation can be found in
1162306a36Sopenharmony_ci * Documentation/admin-guide/sysctl/vm.rst.
1262306a36Sopenharmony_ci * Started 18.12.91
1362306a36Sopenharmony_ci * Swap aging added 23.2.95, Stephen Tweedie.
1462306a36Sopenharmony_ci * Buffermem limits added 12.3.98, Rik van Riel.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/mm.h>
1862306a36Sopenharmony_ci#include <linux/sched.h>
1962306a36Sopenharmony_ci#include <linux/kernel_stat.h>
2062306a36Sopenharmony_ci#include <linux/swap.h>
2162306a36Sopenharmony_ci#include <linux/mman.h>
2262306a36Sopenharmony_ci#include <linux/pagemap.h>
2362306a36Sopenharmony_ci#include <linux/pagevec.h>
2462306a36Sopenharmony_ci#include <linux/init.h>
2562306a36Sopenharmony_ci#include <linux/export.h>
2662306a36Sopenharmony_ci#include <linux/mm_inline.h>
2762306a36Sopenharmony_ci#include <linux/percpu_counter.h>
2862306a36Sopenharmony_ci#include <linux/memremap.h>
2962306a36Sopenharmony_ci#include <linux/percpu.h>
3062306a36Sopenharmony_ci#include <linux/cpu.h>
3162306a36Sopenharmony_ci#include <linux/notifier.h>
3262306a36Sopenharmony_ci#include <linux/backing-dev.h>
3362306a36Sopenharmony_ci#include <linux/memcontrol.h>
3462306a36Sopenharmony_ci#include <linux/gfp.h>
3562306a36Sopenharmony_ci#include <linux/uio.h>
3662306a36Sopenharmony_ci#include <linux/hugetlb.h>
3762306a36Sopenharmony_ci#include <linux/page_idle.h>
3862306a36Sopenharmony_ci#include <linux/local_lock.h>
3962306a36Sopenharmony_ci#include <linux/buffer_head.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include "internal.h"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
4462306a36Sopenharmony_ci#include <trace/events/pagemap.h>
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/* How many pages do we try to swap or page in/out together? As a power of 2 */
4762306a36Sopenharmony_ciint page_cluster;
4862306a36Sopenharmony_ciconst int page_cluster_max = 31;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/* Protecting only lru_rotate.fbatch which requires disabling interrupts */
5162306a36Sopenharmony_cistruct lru_rotate {
5262306a36Sopenharmony_ci	local_lock_t lock;
5362306a36Sopenharmony_ci	struct folio_batch fbatch;
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct lru_rotate, lru_rotate) = {
5662306a36Sopenharmony_ci	.lock = INIT_LOCAL_LOCK(lock),
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/*
6062306a36Sopenharmony_ci * The following folio batches are grouped together because they are protected
6162306a36Sopenharmony_ci * by disabling preemption (and interrupts remain enabled).
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_cistruct cpu_fbatches {
6462306a36Sopenharmony_ci	local_lock_t lock;
6562306a36Sopenharmony_ci	struct folio_batch lru_add;
6662306a36Sopenharmony_ci	struct folio_batch lru_deactivate_file;
6762306a36Sopenharmony_ci	struct folio_batch lru_deactivate;
6862306a36Sopenharmony_ci	struct folio_batch lru_lazyfree;
6962306a36Sopenharmony_ci#ifdef CONFIG_SMP
7062306a36Sopenharmony_ci	struct folio_batch activate;
7162306a36Sopenharmony_ci#endif
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct cpu_fbatches, cpu_fbatches) = {
7462306a36Sopenharmony_ci	.lock = INIT_LOCAL_LOCK(lock),
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci * This path almost never happens for VM activity - pages are normally freed
7962306a36Sopenharmony_ci * in batches.  But it gets used by networking - and for compound pages.
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_cistatic void __page_cache_release(struct folio *folio)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	if (folio_test_lru(folio)) {
8462306a36Sopenharmony_ci		struct lruvec *lruvec;
8562306a36Sopenharmony_ci		unsigned long flags;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		lruvec = folio_lruvec_lock_irqsave(folio, &flags);
8862306a36Sopenharmony_ci		lruvec_del_folio(lruvec, folio);
8962306a36Sopenharmony_ci		__folio_clear_lru_flags(folio);
9062306a36Sopenharmony_ci		unlock_page_lruvec_irqrestore(lruvec, flags);
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci	/* See comment on folio_test_mlocked in release_pages() */
9362306a36Sopenharmony_ci	if (unlikely(folio_test_mlocked(folio))) {
9462306a36Sopenharmony_ci		long nr_pages = folio_nr_pages(folio);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci		__folio_clear_mlocked(folio);
9762306a36Sopenharmony_ci		zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages);
9862306a36Sopenharmony_ci		count_vm_events(UNEVICTABLE_PGCLEARED, nr_pages);
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic void __folio_put_small(struct folio *folio)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	__page_cache_release(folio);
10562306a36Sopenharmony_ci	mem_cgroup_uncharge(folio);
10662306a36Sopenharmony_ci	free_unref_page(&folio->page, 0);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic void __folio_put_large(struct folio *folio)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	/*
11262306a36Sopenharmony_ci	 * __page_cache_release() is supposed to be called for thp, not for
11362306a36Sopenharmony_ci	 * hugetlb. This is because hugetlb page does never have PageLRU set
11462306a36Sopenharmony_ci	 * (it's never listed to any LRU lists) and no memcg routines should
11562306a36Sopenharmony_ci	 * be called for hugetlb (it has a separate hugetlb_cgroup.)
11662306a36Sopenharmony_ci	 */
11762306a36Sopenharmony_ci	if (!folio_test_hugetlb(folio))
11862306a36Sopenharmony_ci		__page_cache_release(folio);
11962306a36Sopenharmony_ci	destroy_large_folio(folio);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_civoid __folio_put(struct folio *folio)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	if (unlikely(folio_is_zone_device(folio)))
12562306a36Sopenharmony_ci		free_zone_device_page(&folio->page);
12662306a36Sopenharmony_ci	else if (unlikely(folio_test_large(folio)))
12762306a36Sopenharmony_ci		__folio_put_large(folio);
12862306a36Sopenharmony_ci	else
12962306a36Sopenharmony_ci		__folio_put_small(folio);
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ciEXPORT_SYMBOL(__folio_put);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/**
13462306a36Sopenharmony_ci * put_pages_list() - release a list of pages
13562306a36Sopenharmony_ci * @pages: list of pages threaded on page->lru
13662306a36Sopenharmony_ci *
13762306a36Sopenharmony_ci * Release a list of pages which are strung together on page.lru.
13862306a36Sopenharmony_ci */
13962306a36Sopenharmony_civoid put_pages_list(struct list_head *pages)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	struct folio *folio, *next;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	list_for_each_entry_safe(folio, next, pages, lru) {
14462306a36Sopenharmony_ci		if (!folio_put_testzero(folio)) {
14562306a36Sopenharmony_ci			list_del(&folio->lru);
14662306a36Sopenharmony_ci			continue;
14762306a36Sopenharmony_ci		}
14862306a36Sopenharmony_ci		if (folio_test_large(folio)) {
14962306a36Sopenharmony_ci			list_del(&folio->lru);
15062306a36Sopenharmony_ci			__folio_put_large(folio);
15162306a36Sopenharmony_ci			continue;
15262306a36Sopenharmony_ci		}
15362306a36Sopenharmony_ci		/* LRU flag must be clear because it's passed using the lru */
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	free_unref_page_list(pages);
15762306a36Sopenharmony_ci	INIT_LIST_HEAD(pages);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ciEXPORT_SYMBOL(put_pages_list);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_citypedef void (*move_fn_t)(struct lruvec *lruvec, struct folio *folio);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic void lru_add_fn(struct lruvec *lruvec, struct folio *folio)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	int was_unevictable = folio_test_clear_unevictable(folio);
16662306a36Sopenharmony_ci	long nr_pages = folio_nr_pages(folio);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	VM_BUG_ON_FOLIO(folio_test_lru(folio), folio);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/*
17162306a36Sopenharmony_ci	 * Is an smp_mb__after_atomic() still required here, before
17262306a36Sopenharmony_ci	 * folio_evictable() tests the mlocked flag, to rule out the possibility
17362306a36Sopenharmony_ci	 * of stranding an evictable folio on an unevictable LRU?  I think
17462306a36Sopenharmony_ci	 * not, because __munlock_folio() only clears the mlocked flag
17562306a36Sopenharmony_ci	 * while the LRU lock is held.
17662306a36Sopenharmony_ci	 *
17762306a36Sopenharmony_ci	 * (That is not true of __page_cache_release(), and not necessarily
17862306a36Sopenharmony_ci	 * true of release_pages(): but those only clear the mlocked flag after
17962306a36Sopenharmony_ci	 * folio_put_testzero() has excluded any other users of the folio.)
18062306a36Sopenharmony_ci	 */
18162306a36Sopenharmony_ci	if (folio_evictable(folio)) {
18262306a36Sopenharmony_ci		if (was_unevictable)
18362306a36Sopenharmony_ci			__count_vm_events(UNEVICTABLE_PGRESCUED, nr_pages);
18462306a36Sopenharmony_ci	} else {
18562306a36Sopenharmony_ci		folio_clear_active(folio);
18662306a36Sopenharmony_ci		folio_set_unevictable(folio);
18762306a36Sopenharmony_ci		/*
18862306a36Sopenharmony_ci		 * folio->mlock_count = !!folio_test_mlocked(folio)?
18962306a36Sopenharmony_ci		 * But that leaves __mlock_folio() in doubt whether another
19062306a36Sopenharmony_ci		 * actor has already counted the mlock or not.  Err on the
19162306a36Sopenharmony_ci		 * safe side, underestimate, let page reclaim fix it, rather
19262306a36Sopenharmony_ci		 * than leaving a page on the unevictable LRU indefinitely.
19362306a36Sopenharmony_ci		 */
19462306a36Sopenharmony_ci		folio->mlock_count = 0;
19562306a36Sopenharmony_ci		if (!was_unevictable)
19662306a36Sopenharmony_ci			__count_vm_events(UNEVICTABLE_PGCULLED, nr_pages);
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	lruvec_add_folio(lruvec, folio);
20062306a36Sopenharmony_ci	trace_mm_lru_insertion(folio);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic void folio_batch_move_lru(struct folio_batch *fbatch, move_fn_t move_fn)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	int i;
20662306a36Sopenharmony_ci	struct lruvec *lruvec = NULL;
20762306a36Sopenharmony_ci	unsigned long flags = 0;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	for (i = 0; i < folio_batch_count(fbatch); i++) {
21062306a36Sopenharmony_ci		struct folio *folio = fbatch->folios[i];
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		/* block memcg migration while the folio moves between lru */
21362306a36Sopenharmony_ci		if (move_fn != lru_add_fn && !folio_test_clear_lru(folio))
21462306a36Sopenharmony_ci			continue;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		lruvec = folio_lruvec_relock_irqsave(folio, lruvec, &flags);
21762306a36Sopenharmony_ci		move_fn(lruvec, folio);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		folio_set_lru(folio);
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (lruvec)
22362306a36Sopenharmony_ci		unlock_page_lruvec_irqrestore(lruvec, flags);
22462306a36Sopenharmony_ci	folios_put(fbatch->folios, folio_batch_count(fbatch));
22562306a36Sopenharmony_ci	folio_batch_reinit(fbatch);
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic void folio_batch_add_and_move(struct folio_batch *fbatch,
22962306a36Sopenharmony_ci		struct folio *folio, move_fn_t move_fn)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	if (folio_batch_add(fbatch, folio) && !folio_test_large(folio) &&
23262306a36Sopenharmony_ci	    !lru_cache_disabled())
23362306a36Sopenharmony_ci		return;
23462306a36Sopenharmony_ci	folio_batch_move_lru(fbatch, move_fn);
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic void lru_move_tail_fn(struct lruvec *lruvec, struct folio *folio)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	if (!folio_test_unevictable(folio)) {
24062306a36Sopenharmony_ci		lruvec_del_folio(lruvec, folio);
24162306a36Sopenharmony_ci		folio_clear_active(folio);
24262306a36Sopenharmony_ci		lruvec_add_folio_tail(lruvec, folio);
24362306a36Sopenharmony_ci		__count_vm_events(PGROTATED, folio_nr_pages(folio));
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci/*
24862306a36Sopenharmony_ci * Writeback is about to end against a folio which has been marked for
24962306a36Sopenharmony_ci * immediate reclaim.  If it still appears to be reclaimable, move it
25062306a36Sopenharmony_ci * to the tail of the inactive list.
25162306a36Sopenharmony_ci *
25262306a36Sopenharmony_ci * folio_rotate_reclaimable() must disable IRQs, to prevent nasty races.
25362306a36Sopenharmony_ci */
25462306a36Sopenharmony_civoid folio_rotate_reclaimable(struct folio *folio)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	if (!folio_test_locked(folio) && !folio_test_dirty(folio) &&
25762306a36Sopenharmony_ci	    !folio_test_unevictable(folio) && folio_test_lru(folio)) {
25862306a36Sopenharmony_ci		struct folio_batch *fbatch;
25962306a36Sopenharmony_ci		unsigned long flags;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		folio_get(folio);
26262306a36Sopenharmony_ci		local_lock_irqsave(&lru_rotate.lock, flags);
26362306a36Sopenharmony_ci		fbatch = this_cpu_ptr(&lru_rotate.fbatch);
26462306a36Sopenharmony_ci		folio_batch_add_and_move(fbatch, folio, lru_move_tail_fn);
26562306a36Sopenharmony_ci		local_unlock_irqrestore(&lru_rotate.lock, flags);
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_civoid lru_note_cost(struct lruvec *lruvec, bool file,
27062306a36Sopenharmony_ci		   unsigned int nr_io, unsigned int nr_rotated)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	unsigned long cost;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/*
27562306a36Sopenharmony_ci	 * Reflect the relative cost of incurring IO and spending CPU
27662306a36Sopenharmony_ci	 * time on rotations. This doesn't attempt to make a precise
27762306a36Sopenharmony_ci	 * comparison, it just says: if reloads are about comparable
27862306a36Sopenharmony_ci	 * between the LRU lists, or rotations are overwhelmingly
27962306a36Sopenharmony_ci	 * different between them, adjust scan balance for CPU work.
28062306a36Sopenharmony_ci	 */
28162306a36Sopenharmony_ci	cost = nr_io * SWAP_CLUSTER_MAX + nr_rotated;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	do {
28462306a36Sopenharmony_ci		unsigned long lrusize;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		/*
28762306a36Sopenharmony_ci		 * Hold lruvec->lru_lock is safe here, since
28862306a36Sopenharmony_ci		 * 1) The pinned lruvec in reclaim, or
28962306a36Sopenharmony_ci		 * 2) From a pre-LRU page during refault (which also holds the
29062306a36Sopenharmony_ci		 *    rcu lock, so would be safe even if the page was on the LRU
29162306a36Sopenharmony_ci		 *    and could move simultaneously to a new lruvec).
29262306a36Sopenharmony_ci		 */
29362306a36Sopenharmony_ci		spin_lock_irq(&lruvec->lru_lock);
29462306a36Sopenharmony_ci		/* Record cost event */
29562306a36Sopenharmony_ci		if (file)
29662306a36Sopenharmony_ci			lruvec->file_cost += cost;
29762306a36Sopenharmony_ci		else
29862306a36Sopenharmony_ci			lruvec->anon_cost += cost;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		/*
30162306a36Sopenharmony_ci		 * Decay previous events
30262306a36Sopenharmony_ci		 *
30362306a36Sopenharmony_ci		 * Because workloads change over time (and to avoid
30462306a36Sopenharmony_ci		 * overflow) we keep these statistics as a floating
30562306a36Sopenharmony_ci		 * average, which ends up weighing recent refaults
30662306a36Sopenharmony_ci		 * more than old ones.
30762306a36Sopenharmony_ci		 */
30862306a36Sopenharmony_ci		lrusize = lruvec_page_state(lruvec, NR_INACTIVE_ANON) +
30962306a36Sopenharmony_ci			  lruvec_page_state(lruvec, NR_ACTIVE_ANON) +
31062306a36Sopenharmony_ci			  lruvec_page_state(lruvec, NR_INACTIVE_FILE) +
31162306a36Sopenharmony_ci			  lruvec_page_state(lruvec, NR_ACTIVE_FILE);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		if (lruvec->file_cost + lruvec->anon_cost > lrusize / 4) {
31462306a36Sopenharmony_ci			lruvec->file_cost /= 2;
31562306a36Sopenharmony_ci			lruvec->anon_cost /= 2;
31662306a36Sopenharmony_ci		}
31762306a36Sopenharmony_ci		spin_unlock_irq(&lruvec->lru_lock);
31862306a36Sopenharmony_ci	} while ((lruvec = parent_lruvec(lruvec)));
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_civoid lru_note_cost_refault(struct folio *folio)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci#ifdef CONFIG_HYPERHOLD_FILE_LRU
32462306a36Sopenharmony_ci	if (page_is_file_lru(folio_page(folio, 0))) {
32562306a36Sopenharmony_ci		lru_note_cost(&(folio_pgdat(folio)->__lruvec), 1, folio_nr_pages(folio), 0);
32662306a36Sopenharmony_ci		return;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci#endif
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	lru_note_cost(folio_lruvec(folio), folio_is_file_lru(folio),
33162306a36Sopenharmony_ci		      folio_nr_pages(folio), 0);
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic void folio_activate_fn(struct lruvec *lruvec, struct folio *folio)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	if (!folio_test_active(folio) && !folio_test_unevictable(folio)) {
33762306a36Sopenharmony_ci		long nr_pages = folio_nr_pages(folio);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		lruvec_del_folio(lruvec, folio);
34062306a36Sopenharmony_ci		folio_set_active(folio);
34162306a36Sopenharmony_ci		lruvec_add_folio(lruvec, folio);
34262306a36Sopenharmony_ci		trace_mm_lru_activate(folio);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci		__count_vm_events(PGACTIVATE, nr_pages);
34562306a36Sopenharmony_ci		__count_memcg_events(lruvec_memcg(lruvec), PGACTIVATE,
34662306a36Sopenharmony_ci				     nr_pages);
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci#ifdef CONFIG_SMP
35162306a36Sopenharmony_cistatic void folio_activate_drain(int cpu)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct folio_batch *fbatch = &per_cpu(cpu_fbatches.activate, cpu);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (folio_batch_count(fbatch))
35662306a36Sopenharmony_ci		folio_batch_move_lru(fbatch, folio_activate_fn);
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_civoid folio_activate(struct folio *folio)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	if (folio_test_lru(folio) && !folio_test_active(folio) &&
36262306a36Sopenharmony_ci	    !folio_test_unevictable(folio)) {
36362306a36Sopenharmony_ci		struct folio_batch *fbatch;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		folio_get(folio);
36662306a36Sopenharmony_ci		local_lock(&cpu_fbatches.lock);
36762306a36Sopenharmony_ci		fbatch = this_cpu_ptr(&cpu_fbatches.activate);
36862306a36Sopenharmony_ci		folio_batch_add_and_move(fbatch, folio, folio_activate_fn);
36962306a36Sopenharmony_ci		local_unlock(&cpu_fbatches.lock);
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci#else
37462306a36Sopenharmony_cistatic inline void folio_activate_drain(int cpu)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_civoid folio_activate(struct folio *folio)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	struct lruvec *lruvec;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if (folio_test_clear_lru(folio)) {
38362306a36Sopenharmony_ci		lruvec = folio_lruvec_lock_irq(folio);
38462306a36Sopenharmony_ci		folio_activate_fn(lruvec, folio);
38562306a36Sopenharmony_ci		unlock_page_lruvec_irq(lruvec);
38662306a36Sopenharmony_ci		folio_set_lru(folio);
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci#endif
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic void __lru_cache_activate_folio(struct folio *folio)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	struct folio_batch *fbatch;
39462306a36Sopenharmony_ci	int i;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	local_lock(&cpu_fbatches.lock);
39762306a36Sopenharmony_ci	fbatch = this_cpu_ptr(&cpu_fbatches.lru_add);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/*
40062306a36Sopenharmony_ci	 * Search backwards on the optimistic assumption that the folio being
40162306a36Sopenharmony_ci	 * activated has just been added to this batch. Note that only
40262306a36Sopenharmony_ci	 * the local batch is examined as a !LRU folio could be in the
40362306a36Sopenharmony_ci	 * process of being released, reclaimed, migrated or on a remote
40462306a36Sopenharmony_ci	 * batch that is currently being drained. Furthermore, marking
40562306a36Sopenharmony_ci	 * a remote batch's folio active potentially hits a race where
40662306a36Sopenharmony_ci	 * a folio is marked active just after it is added to the inactive
40762306a36Sopenharmony_ci	 * list causing accounting errors and BUG_ON checks to trigger.
40862306a36Sopenharmony_ci	 */
40962306a36Sopenharmony_ci	for (i = folio_batch_count(fbatch) - 1; i >= 0; i--) {
41062306a36Sopenharmony_ci		struct folio *batch_folio = fbatch->folios[i];
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		if (batch_folio == folio) {
41362306a36Sopenharmony_ci			folio_set_active(folio);
41462306a36Sopenharmony_ci			break;
41562306a36Sopenharmony_ci		}
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	local_unlock(&cpu_fbatches.lock);
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci#ifdef CONFIG_LRU_GEN
42262306a36Sopenharmony_cistatic void folio_inc_refs(struct folio *folio)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	unsigned long new_flags, old_flags = READ_ONCE(folio->flags);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (folio_test_unevictable(folio))
42762306a36Sopenharmony_ci		return;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (!folio_test_referenced(folio)) {
43062306a36Sopenharmony_ci		folio_set_referenced(folio);
43162306a36Sopenharmony_ci		return;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (!folio_test_workingset(folio)) {
43562306a36Sopenharmony_ci		folio_set_workingset(folio);
43662306a36Sopenharmony_ci		return;
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	/* see the comment on MAX_NR_TIERS */
44062306a36Sopenharmony_ci	do {
44162306a36Sopenharmony_ci		new_flags = old_flags & LRU_REFS_MASK;
44262306a36Sopenharmony_ci		if (new_flags == LRU_REFS_MASK)
44362306a36Sopenharmony_ci			break;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		new_flags += BIT(LRU_REFS_PGOFF);
44662306a36Sopenharmony_ci		new_flags |= old_flags & ~LRU_REFS_MASK;
44762306a36Sopenharmony_ci	} while (!try_cmpxchg(&folio->flags, &old_flags, new_flags));
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci#else
45062306a36Sopenharmony_cistatic void folio_inc_refs(struct folio *folio)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci#endif /* CONFIG_LRU_GEN */
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci/*
45662306a36Sopenharmony_ci * Mark a page as having seen activity.
45762306a36Sopenharmony_ci *
45862306a36Sopenharmony_ci * inactive,unreferenced	->	inactive,referenced
45962306a36Sopenharmony_ci * inactive,referenced		->	active,unreferenced
46062306a36Sopenharmony_ci * active,unreferenced		->	active,referenced
46162306a36Sopenharmony_ci *
46262306a36Sopenharmony_ci * When a newly allocated page is not yet visible, so safe for non-atomic ops,
46362306a36Sopenharmony_ci * __SetPageReferenced(page) may be substituted for mark_page_accessed(page).
46462306a36Sopenharmony_ci */
46562306a36Sopenharmony_civoid folio_mark_accessed(struct folio *folio)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	if (lru_gen_enabled()) {
46862306a36Sopenharmony_ci		folio_inc_refs(folio);
46962306a36Sopenharmony_ci		return;
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (!folio_test_referenced(folio)) {
47362306a36Sopenharmony_ci		folio_set_referenced(folio);
47462306a36Sopenharmony_ci	} else if (folio_test_unevictable(folio)) {
47562306a36Sopenharmony_ci		/*
47662306a36Sopenharmony_ci		 * Unevictable pages are on the "LRU_UNEVICTABLE" list. But,
47762306a36Sopenharmony_ci		 * this list is never rotated or maintained, so marking an
47862306a36Sopenharmony_ci		 * unevictable page accessed has no effect.
47962306a36Sopenharmony_ci		 */
48062306a36Sopenharmony_ci	} else if (!folio_test_active(folio)) {
48162306a36Sopenharmony_ci		/*
48262306a36Sopenharmony_ci		 * If the folio is on the LRU, queue it for activation via
48362306a36Sopenharmony_ci		 * cpu_fbatches.activate. Otherwise, assume the folio is in a
48462306a36Sopenharmony_ci		 * folio_batch, mark it active and it'll be moved to the active
48562306a36Sopenharmony_ci		 * LRU on the next drain.
48662306a36Sopenharmony_ci		 */
48762306a36Sopenharmony_ci		if (folio_test_lru(folio))
48862306a36Sopenharmony_ci			folio_activate(folio);
48962306a36Sopenharmony_ci		else
49062306a36Sopenharmony_ci			__lru_cache_activate_folio(folio);
49162306a36Sopenharmony_ci		folio_clear_referenced(folio);
49262306a36Sopenharmony_ci		workingset_activation(folio);
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci	if (folio_test_idle(folio))
49562306a36Sopenharmony_ci		folio_clear_idle(folio);
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ciEXPORT_SYMBOL(folio_mark_accessed);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/**
50062306a36Sopenharmony_ci * folio_add_lru - Add a folio to an LRU list.
50162306a36Sopenharmony_ci * @folio: The folio to be added to the LRU.
50262306a36Sopenharmony_ci *
50362306a36Sopenharmony_ci * Queue the folio for addition to the LRU. The decision on whether
50462306a36Sopenharmony_ci * to add the page to the [in]active [file|anon] list is deferred until the
50562306a36Sopenharmony_ci * folio_batch is drained. This gives a chance for the caller of folio_add_lru()
50662306a36Sopenharmony_ci * have the folio added to the active list using folio_mark_accessed().
50762306a36Sopenharmony_ci */
50862306a36Sopenharmony_civoid folio_add_lru(struct folio *folio)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct folio_batch *fbatch;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	VM_BUG_ON_FOLIO(folio_test_active(folio) &&
51362306a36Sopenharmony_ci			folio_test_unevictable(folio), folio);
51462306a36Sopenharmony_ci	VM_BUG_ON_FOLIO(folio_test_lru(folio), folio);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/* see the comment in lru_gen_add_folio() */
51762306a36Sopenharmony_ci	if (lru_gen_enabled() && !folio_test_unevictable(folio) &&
51862306a36Sopenharmony_ci	    lru_gen_in_fault() && !(current->flags & PF_MEMALLOC))
51962306a36Sopenharmony_ci		folio_set_active(folio);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	folio_get(folio);
52262306a36Sopenharmony_ci	local_lock(&cpu_fbatches.lock);
52362306a36Sopenharmony_ci	fbatch = this_cpu_ptr(&cpu_fbatches.lru_add);
52462306a36Sopenharmony_ci	folio_batch_add_and_move(fbatch, folio, lru_add_fn);
52562306a36Sopenharmony_ci	local_unlock(&cpu_fbatches.lock);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ciEXPORT_SYMBOL(folio_add_lru);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/**
53062306a36Sopenharmony_ci * folio_add_lru_vma() - Add a folio to the appropate LRU list for this VMA.
53162306a36Sopenharmony_ci * @folio: The folio to be added to the LRU.
53262306a36Sopenharmony_ci * @vma: VMA in which the folio is mapped.
53362306a36Sopenharmony_ci *
53462306a36Sopenharmony_ci * If the VMA is mlocked, @folio is added to the unevictable list.
53562306a36Sopenharmony_ci * Otherwise, it is treated the same way as folio_add_lru().
53662306a36Sopenharmony_ci */
53762306a36Sopenharmony_civoid folio_add_lru_vma(struct folio *folio, struct vm_area_struct *vma)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	VM_BUG_ON_FOLIO(folio_test_lru(folio), folio);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (unlikely((vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) == VM_LOCKED))
54262306a36Sopenharmony_ci		mlock_new_folio(folio);
54362306a36Sopenharmony_ci	else
54462306a36Sopenharmony_ci		folio_add_lru(folio);
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci/*
54862306a36Sopenharmony_ci * If the folio cannot be invalidated, it is moved to the
54962306a36Sopenharmony_ci * inactive list to speed up its reclaim.  It is moved to the
55062306a36Sopenharmony_ci * head of the list, rather than the tail, to give the flusher
55162306a36Sopenharmony_ci * threads some time to write it out, as this is much more
55262306a36Sopenharmony_ci * effective than the single-page writeout from reclaim.
55362306a36Sopenharmony_ci *
55462306a36Sopenharmony_ci * If the folio isn't mapped and dirty/writeback, the folio
55562306a36Sopenharmony_ci * could be reclaimed asap using the reclaim flag.
55662306a36Sopenharmony_ci *
55762306a36Sopenharmony_ci * 1. active, mapped folio -> none
55862306a36Sopenharmony_ci * 2. active, dirty/writeback folio -> inactive, head, reclaim
55962306a36Sopenharmony_ci * 3. inactive, mapped folio -> none
56062306a36Sopenharmony_ci * 4. inactive, dirty/writeback folio -> inactive, head, reclaim
56162306a36Sopenharmony_ci * 5. inactive, clean -> inactive, tail
56262306a36Sopenharmony_ci * 6. Others -> none
56362306a36Sopenharmony_ci *
56462306a36Sopenharmony_ci * In 4, it moves to the head of the inactive list so the folio is
56562306a36Sopenharmony_ci * written out by flusher threads as this is much more efficient
56662306a36Sopenharmony_ci * than the single-page writeout from reclaim.
56762306a36Sopenharmony_ci */
56862306a36Sopenharmony_cistatic void lru_deactivate_file_fn(struct lruvec *lruvec, struct folio *folio)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	bool active = folio_test_active(folio);
57162306a36Sopenharmony_ci	long nr_pages = folio_nr_pages(folio);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (folio_test_unevictable(folio))
57462306a36Sopenharmony_ci		return;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	/* Some processes are using the folio */
57762306a36Sopenharmony_ci	if (folio_mapped(folio))
57862306a36Sopenharmony_ci		return;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	lruvec_del_folio(lruvec, folio);
58162306a36Sopenharmony_ci	folio_clear_active(folio);
58262306a36Sopenharmony_ci	folio_clear_referenced(folio);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (folio_test_writeback(folio) || folio_test_dirty(folio)) {
58562306a36Sopenharmony_ci		/*
58662306a36Sopenharmony_ci		 * Setting the reclaim flag could race with
58762306a36Sopenharmony_ci		 * folio_end_writeback() and confuse readahead.  But the
58862306a36Sopenharmony_ci		 * race window is _really_ small and  it's not a critical
58962306a36Sopenharmony_ci		 * problem.
59062306a36Sopenharmony_ci		 */
59162306a36Sopenharmony_ci		lruvec_add_folio(lruvec, folio);
59262306a36Sopenharmony_ci		folio_set_reclaim(folio);
59362306a36Sopenharmony_ci	} else {
59462306a36Sopenharmony_ci		/*
59562306a36Sopenharmony_ci		 * The folio's writeback ended while it was in the batch.
59662306a36Sopenharmony_ci		 * We move that folio to the tail of the inactive list.
59762306a36Sopenharmony_ci		 */
59862306a36Sopenharmony_ci		lruvec_add_folio_tail(lruvec, folio);
59962306a36Sopenharmony_ci		__count_vm_events(PGROTATED, nr_pages);
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (active) {
60362306a36Sopenharmony_ci		__count_vm_events(PGDEACTIVATE, nr_pages);
60462306a36Sopenharmony_ci		__count_memcg_events(lruvec_memcg(lruvec), PGDEACTIVATE,
60562306a36Sopenharmony_ci				     nr_pages);
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic void lru_deactivate_fn(struct lruvec *lruvec, struct folio *folio)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	if (!folio_test_unevictable(folio) && (folio_test_active(folio) || lru_gen_enabled())) {
61262306a36Sopenharmony_ci		long nr_pages = folio_nr_pages(folio);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci		lruvec_del_folio(lruvec, folio);
61562306a36Sopenharmony_ci		folio_clear_active(folio);
61662306a36Sopenharmony_ci		folio_clear_referenced(folio);
61762306a36Sopenharmony_ci		lruvec_add_folio(lruvec, folio);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		__count_vm_events(PGDEACTIVATE, nr_pages);
62062306a36Sopenharmony_ci		__count_memcg_events(lruvec_memcg(lruvec), PGDEACTIVATE,
62162306a36Sopenharmony_ci				     nr_pages);
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic void lru_lazyfree_fn(struct lruvec *lruvec, struct folio *folio)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	if (folio_test_anon(folio) && folio_test_swapbacked(folio) &&
62862306a36Sopenharmony_ci	    !folio_test_swapcache(folio) && !folio_test_unevictable(folio)) {
62962306a36Sopenharmony_ci		long nr_pages = folio_nr_pages(folio);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci		lruvec_del_folio(lruvec, folio);
63262306a36Sopenharmony_ci		folio_clear_active(folio);
63362306a36Sopenharmony_ci		folio_clear_referenced(folio);
63462306a36Sopenharmony_ci		/*
63562306a36Sopenharmony_ci		 * Lazyfree folios are clean anonymous folios.  They have
63662306a36Sopenharmony_ci		 * the swapbacked flag cleared, to distinguish them from normal
63762306a36Sopenharmony_ci		 * anonymous folios
63862306a36Sopenharmony_ci		 */
63962306a36Sopenharmony_ci		folio_clear_swapbacked(folio);
64062306a36Sopenharmony_ci		lruvec_add_folio(lruvec, folio);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		__count_vm_events(PGLAZYFREE, nr_pages);
64362306a36Sopenharmony_ci		__count_memcg_events(lruvec_memcg(lruvec), PGLAZYFREE,
64462306a36Sopenharmony_ci				     nr_pages);
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci/*
64962306a36Sopenharmony_ci * Drain pages out of the cpu's folio_batch.
65062306a36Sopenharmony_ci * Either "cpu" is the current CPU, and preemption has already been
65162306a36Sopenharmony_ci * disabled; or "cpu" is being hot-unplugged, and is already dead.
65262306a36Sopenharmony_ci */
65362306a36Sopenharmony_civoid lru_add_drain_cpu(int cpu)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct cpu_fbatches *fbatches = &per_cpu(cpu_fbatches, cpu);
65662306a36Sopenharmony_ci	struct folio_batch *fbatch = &fbatches->lru_add;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	if (folio_batch_count(fbatch))
65962306a36Sopenharmony_ci		folio_batch_move_lru(fbatch, lru_add_fn);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	fbatch = &per_cpu(lru_rotate.fbatch, cpu);
66262306a36Sopenharmony_ci	/* Disabling interrupts below acts as a compiler barrier. */
66362306a36Sopenharmony_ci	if (data_race(folio_batch_count(fbatch))) {
66462306a36Sopenharmony_ci		unsigned long flags;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		/* No harm done if a racing interrupt already did this */
66762306a36Sopenharmony_ci		local_lock_irqsave(&lru_rotate.lock, flags);
66862306a36Sopenharmony_ci		folio_batch_move_lru(fbatch, lru_move_tail_fn);
66962306a36Sopenharmony_ci		local_unlock_irqrestore(&lru_rotate.lock, flags);
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	fbatch = &fbatches->lru_deactivate_file;
67362306a36Sopenharmony_ci	if (folio_batch_count(fbatch))
67462306a36Sopenharmony_ci		folio_batch_move_lru(fbatch, lru_deactivate_file_fn);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	fbatch = &fbatches->lru_deactivate;
67762306a36Sopenharmony_ci	if (folio_batch_count(fbatch))
67862306a36Sopenharmony_ci		folio_batch_move_lru(fbatch, lru_deactivate_fn);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	fbatch = &fbatches->lru_lazyfree;
68162306a36Sopenharmony_ci	if (folio_batch_count(fbatch))
68262306a36Sopenharmony_ci		folio_batch_move_lru(fbatch, lru_lazyfree_fn);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	folio_activate_drain(cpu);
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci/**
68862306a36Sopenharmony_ci * deactivate_file_folio() - Deactivate a file folio.
68962306a36Sopenharmony_ci * @folio: Folio to deactivate.
69062306a36Sopenharmony_ci *
69162306a36Sopenharmony_ci * This function hints to the VM that @folio is a good reclaim candidate,
69262306a36Sopenharmony_ci * for example if its invalidation fails due to the folio being dirty
69362306a36Sopenharmony_ci * or under writeback.
69462306a36Sopenharmony_ci *
69562306a36Sopenharmony_ci * Context: Caller holds a reference on the folio.
69662306a36Sopenharmony_ci */
69762306a36Sopenharmony_civoid deactivate_file_folio(struct folio *folio)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct folio_batch *fbatch;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	/* Deactivating an unevictable folio will not accelerate reclaim */
70262306a36Sopenharmony_ci	if (folio_test_unevictable(folio))
70362306a36Sopenharmony_ci		return;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	folio_get(folio);
70662306a36Sopenharmony_ci	local_lock(&cpu_fbatches.lock);
70762306a36Sopenharmony_ci	fbatch = this_cpu_ptr(&cpu_fbatches.lru_deactivate_file);
70862306a36Sopenharmony_ci	folio_batch_add_and_move(fbatch, folio, lru_deactivate_file_fn);
70962306a36Sopenharmony_ci	local_unlock(&cpu_fbatches.lock);
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci/*
71362306a36Sopenharmony_ci * folio_deactivate - deactivate a folio
71462306a36Sopenharmony_ci * @folio: folio to deactivate
71562306a36Sopenharmony_ci *
71662306a36Sopenharmony_ci * folio_deactivate() moves @folio to the inactive list if @folio was on the
71762306a36Sopenharmony_ci * active list and was not unevictable. This is done to accelerate the
71862306a36Sopenharmony_ci * reclaim of @folio.
71962306a36Sopenharmony_ci */
72062306a36Sopenharmony_civoid folio_deactivate(struct folio *folio)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	if (folio_test_lru(folio) && !folio_test_unevictable(folio) &&
72362306a36Sopenharmony_ci	    (folio_test_active(folio) || lru_gen_enabled())) {
72462306a36Sopenharmony_ci		struct folio_batch *fbatch;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci		folio_get(folio);
72762306a36Sopenharmony_ci		local_lock(&cpu_fbatches.lock);
72862306a36Sopenharmony_ci		fbatch = this_cpu_ptr(&cpu_fbatches.lru_deactivate);
72962306a36Sopenharmony_ci		folio_batch_add_and_move(fbatch, folio, lru_deactivate_fn);
73062306a36Sopenharmony_ci		local_unlock(&cpu_fbatches.lock);
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci/**
73562306a36Sopenharmony_ci * folio_mark_lazyfree - make an anon folio lazyfree
73662306a36Sopenharmony_ci * @folio: folio to deactivate
73762306a36Sopenharmony_ci *
73862306a36Sopenharmony_ci * folio_mark_lazyfree() moves @folio to the inactive file list.
73962306a36Sopenharmony_ci * This is done to accelerate the reclaim of @folio.
74062306a36Sopenharmony_ci */
74162306a36Sopenharmony_civoid folio_mark_lazyfree(struct folio *folio)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	if (folio_test_lru(folio) && folio_test_anon(folio) &&
74462306a36Sopenharmony_ci	    folio_test_swapbacked(folio) && !folio_test_swapcache(folio) &&
74562306a36Sopenharmony_ci	    !folio_test_unevictable(folio)) {
74662306a36Sopenharmony_ci		struct folio_batch *fbatch;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci		folio_get(folio);
74962306a36Sopenharmony_ci		local_lock(&cpu_fbatches.lock);
75062306a36Sopenharmony_ci		fbatch = this_cpu_ptr(&cpu_fbatches.lru_lazyfree);
75162306a36Sopenharmony_ci		folio_batch_add_and_move(fbatch, folio, lru_lazyfree_fn);
75262306a36Sopenharmony_ci		local_unlock(&cpu_fbatches.lock);
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_civoid lru_add_drain(void)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	local_lock(&cpu_fbatches.lock);
75962306a36Sopenharmony_ci	lru_add_drain_cpu(smp_processor_id());
76062306a36Sopenharmony_ci	local_unlock(&cpu_fbatches.lock);
76162306a36Sopenharmony_ci	mlock_drain_local();
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci/*
76562306a36Sopenharmony_ci * It's called from per-cpu workqueue context in SMP case so
76662306a36Sopenharmony_ci * lru_add_drain_cpu and invalidate_bh_lrus_cpu should run on
76762306a36Sopenharmony_ci * the same cpu. It shouldn't be a problem in !SMP case since
76862306a36Sopenharmony_ci * the core is only one and the locks will disable preemption.
76962306a36Sopenharmony_ci */
77062306a36Sopenharmony_cistatic void lru_add_and_bh_lrus_drain(void)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	local_lock(&cpu_fbatches.lock);
77362306a36Sopenharmony_ci	lru_add_drain_cpu(smp_processor_id());
77462306a36Sopenharmony_ci	local_unlock(&cpu_fbatches.lock);
77562306a36Sopenharmony_ci	invalidate_bh_lrus_cpu();
77662306a36Sopenharmony_ci	mlock_drain_local();
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_civoid lru_add_drain_cpu_zone(struct zone *zone)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	local_lock(&cpu_fbatches.lock);
78262306a36Sopenharmony_ci	lru_add_drain_cpu(smp_processor_id());
78362306a36Sopenharmony_ci	drain_local_pages(zone);
78462306a36Sopenharmony_ci	local_unlock(&cpu_fbatches.lock);
78562306a36Sopenharmony_ci	mlock_drain_local();
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci#ifdef CONFIG_SMP
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct work_struct, lru_add_drain_work);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic void lru_add_drain_per_cpu(struct work_struct *dummy)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	lru_add_and_bh_lrus_drain();
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic bool cpu_needs_drain(unsigned int cpu)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	struct cpu_fbatches *fbatches = &per_cpu(cpu_fbatches, cpu);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	/* Check these in order of likelihood that they're not zero */
80262306a36Sopenharmony_ci	return folio_batch_count(&fbatches->lru_add) ||
80362306a36Sopenharmony_ci		data_race(folio_batch_count(&per_cpu(lru_rotate.fbatch, cpu))) ||
80462306a36Sopenharmony_ci		folio_batch_count(&fbatches->lru_deactivate_file) ||
80562306a36Sopenharmony_ci		folio_batch_count(&fbatches->lru_deactivate) ||
80662306a36Sopenharmony_ci		folio_batch_count(&fbatches->lru_lazyfree) ||
80762306a36Sopenharmony_ci		folio_batch_count(&fbatches->activate) ||
80862306a36Sopenharmony_ci		need_mlock_drain(cpu) ||
80962306a36Sopenharmony_ci		has_bh_in_lru(cpu, NULL);
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci/*
81362306a36Sopenharmony_ci * Doesn't need any cpu hotplug locking because we do rely on per-cpu
81462306a36Sopenharmony_ci * kworkers being shut down before our page_alloc_cpu_dead callback is
81562306a36Sopenharmony_ci * executed on the offlined cpu.
81662306a36Sopenharmony_ci * Calling this function with cpu hotplug locks held can actually lead
81762306a36Sopenharmony_ci * to obscure indirect dependencies via WQ context.
81862306a36Sopenharmony_ci */
81962306a36Sopenharmony_cistatic inline void __lru_add_drain_all(bool force_all_cpus)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	/*
82262306a36Sopenharmony_ci	 * lru_drain_gen - Global pages generation number
82362306a36Sopenharmony_ci	 *
82462306a36Sopenharmony_ci	 * (A) Definition: global lru_drain_gen = x implies that all generations
82562306a36Sopenharmony_ci	 *     0 < n <= x are already *scheduled* for draining.
82662306a36Sopenharmony_ci	 *
82762306a36Sopenharmony_ci	 * This is an optimization for the highly-contended use case where a
82862306a36Sopenharmony_ci	 * user space workload keeps constantly generating a flow of pages for
82962306a36Sopenharmony_ci	 * each CPU.
83062306a36Sopenharmony_ci	 */
83162306a36Sopenharmony_ci	static unsigned int lru_drain_gen;
83262306a36Sopenharmony_ci	static struct cpumask has_work;
83362306a36Sopenharmony_ci	static DEFINE_MUTEX(lock);
83462306a36Sopenharmony_ci	unsigned cpu, this_gen;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/*
83762306a36Sopenharmony_ci	 * Make sure nobody triggers this path before mm_percpu_wq is fully
83862306a36Sopenharmony_ci	 * initialized.
83962306a36Sopenharmony_ci	 */
84062306a36Sopenharmony_ci	if (WARN_ON(!mm_percpu_wq))
84162306a36Sopenharmony_ci		return;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	/*
84462306a36Sopenharmony_ci	 * Guarantee folio_batch counter stores visible by this CPU
84562306a36Sopenharmony_ci	 * are visible to other CPUs before loading the current drain
84662306a36Sopenharmony_ci	 * generation.
84762306a36Sopenharmony_ci	 */
84862306a36Sopenharmony_ci	smp_mb();
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	/*
85162306a36Sopenharmony_ci	 * (B) Locally cache global LRU draining generation number
85262306a36Sopenharmony_ci	 *
85362306a36Sopenharmony_ci	 * The read barrier ensures that the counter is loaded before the mutex
85462306a36Sopenharmony_ci	 * is taken. It pairs with smp_mb() inside the mutex critical section
85562306a36Sopenharmony_ci	 * at (D).
85662306a36Sopenharmony_ci	 */
85762306a36Sopenharmony_ci	this_gen = smp_load_acquire(&lru_drain_gen);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	mutex_lock(&lock);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	/*
86262306a36Sopenharmony_ci	 * (C) Exit the draining operation if a newer generation, from another
86362306a36Sopenharmony_ci	 * lru_add_drain_all(), was already scheduled for draining. Check (A).
86462306a36Sopenharmony_ci	 */
86562306a36Sopenharmony_ci	if (unlikely(this_gen != lru_drain_gen && !force_all_cpus))
86662306a36Sopenharmony_ci		goto done;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	/*
86962306a36Sopenharmony_ci	 * (D) Increment global generation number
87062306a36Sopenharmony_ci	 *
87162306a36Sopenharmony_ci	 * Pairs with smp_load_acquire() at (B), outside of the critical
87262306a36Sopenharmony_ci	 * section. Use a full memory barrier to guarantee that the
87362306a36Sopenharmony_ci	 * new global drain generation number is stored before loading
87462306a36Sopenharmony_ci	 * folio_batch counters.
87562306a36Sopenharmony_ci	 *
87662306a36Sopenharmony_ci	 * This pairing must be done here, before the for_each_online_cpu loop
87762306a36Sopenharmony_ci	 * below which drains the page vectors.
87862306a36Sopenharmony_ci	 *
87962306a36Sopenharmony_ci	 * Let x, y, and z represent some system CPU numbers, where x < y < z.
88062306a36Sopenharmony_ci	 * Assume CPU #z is in the middle of the for_each_online_cpu loop
88162306a36Sopenharmony_ci	 * below and has already reached CPU #y's per-cpu data. CPU #x comes
88262306a36Sopenharmony_ci	 * along, adds some pages to its per-cpu vectors, then calls
88362306a36Sopenharmony_ci	 * lru_add_drain_all().
88462306a36Sopenharmony_ci	 *
88562306a36Sopenharmony_ci	 * If the paired barrier is done at any later step, e.g. after the
88662306a36Sopenharmony_ci	 * loop, CPU #x will just exit at (C) and miss flushing out all of its
88762306a36Sopenharmony_ci	 * added pages.
88862306a36Sopenharmony_ci	 */
88962306a36Sopenharmony_ci	WRITE_ONCE(lru_drain_gen, lru_drain_gen + 1);
89062306a36Sopenharmony_ci	smp_mb();
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	cpumask_clear(&has_work);
89362306a36Sopenharmony_ci	for_each_online_cpu(cpu) {
89462306a36Sopenharmony_ci		struct work_struct *work = &per_cpu(lru_add_drain_work, cpu);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		if (cpu_needs_drain(cpu)) {
89762306a36Sopenharmony_ci			INIT_WORK(work, lru_add_drain_per_cpu);
89862306a36Sopenharmony_ci			queue_work_on(cpu, mm_percpu_wq, work);
89962306a36Sopenharmony_ci			__cpumask_set_cpu(cpu, &has_work);
90062306a36Sopenharmony_ci		}
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	for_each_cpu(cpu, &has_work)
90462306a36Sopenharmony_ci		flush_work(&per_cpu(lru_add_drain_work, cpu));
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cidone:
90762306a36Sopenharmony_ci	mutex_unlock(&lock);
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_civoid lru_add_drain_all(void)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	__lru_add_drain_all(false);
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci#else
91562306a36Sopenharmony_civoid lru_add_drain_all(void)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	lru_add_drain();
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ci#endif /* CONFIG_SMP */
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ciatomic_t lru_disable_count = ATOMIC_INIT(0);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci/*
92462306a36Sopenharmony_ci * lru_cache_disable() needs to be called before we start compiling
92562306a36Sopenharmony_ci * a list of pages to be migrated using isolate_lru_page().
92662306a36Sopenharmony_ci * It drains pages on LRU cache and then disable on all cpus until
92762306a36Sopenharmony_ci * lru_cache_enable is called.
92862306a36Sopenharmony_ci *
92962306a36Sopenharmony_ci * Must be paired with a call to lru_cache_enable().
93062306a36Sopenharmony_ci */
93162306a36Sopenharmony_civoid lru_cache_disable(void)
93262306a36Sopenharmony_ci{
93362306a36Sopenharmony_ci	atomic_inc(&lru_disable_count);
93462306a36Sopenharmony_ci	/*
93562306a36Sopenharmony_ci	 * Readers of lru_disable_count are protected by either disabling
93662306a36Sopenharmony_ci	 * preemption or rcu_read_lock:
93762306a36Sopenharmony_ci	 *
93862306a36Sopenharmony_ci	 * preempt_disable, local_irq_disable  [bh_lru_lock()]
93962306a36Sopenharmony_ci	 * rcu_read_lock		       [rt_spin_lock CONFIG_PREEMPT_RT]
94062306a36Sopenharmony_ci	 * preempt_disable		       [local_lock !CONFIG_PREEMPT_RT]
94162306a36Sopenharmony_ci	 *
94262306a36Sopenharmony_ci	 * Since v5.1 kernel, synchronize_rcu() is guaranteed to wait on
94362306a36Sopenharmony_ci	 * preempt_disable() regions of code. So any CPU which sees
94462306a36Sopenharmony_ci	 * lru_disable_count = 0 will have exited the critical
94562306a36Sopenharmony_ci	 * section when synchronize_rcu() returns.
94662306a36Sopenharmony_ci	 */
94762306a36Sopenharmony_ci	synchronize_rcu_expedited();
94862306a36Sopenharmony_ci#ifdef CONFIG_SMP
94962306a36Sopenharmony_ci	__lru_add_drain_all(true);
95062306a36Sopenharmony_ci#else
95162306a36Sopenharmony_ci	lru_add_and_bh_lrus_drain();
95262306a36Sopenharmony_ci#endif
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci/**
95662306a36Sopenharmony_ci * release_pages - batched put_page()
95762306a36Sopenharmony_ci * @arg: array of pages to release
95862306a36Sopenharmony_ci * @nr: number of pages
95962306a36Sopenharmony_ci *
96062306a36Sopenharmony_ci * Decrement the reference count on all the pages in @arg.  If it
96162306a36Sopenharmony_ci * fell to zero, remove the page from the LRU and free it.
96262306a36Sopenharmony_ci *
96362306a36Sopenharmony_ci * Note that the argument can be an array of pages, encoded pages,
96462306a36Sopenharmony_ci * or folio pointers. We ignore any encoded bits, and turn any of
96562306a36Sopenharmony_ci * them into just a folio that gets free'd.
96662306a36Sopenharmony_ci */
96762306a36Sopenharmony_civoid release_pages(release_pages_arg arg, int nr)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	int i;
97062306a36Sopenharmony_ci	struct encoded_page **encoded = arg.encoded_pages;
97162306a36Sopenharmony_ci	LIST_HEAD(pages_to_free);
97262306a36Sopenharmony_ci	struct lruvec *lruvec = NULL;
97362306a36Sopenharmony_ci	unsigned long flags = 0;
97462306a36Sopenharmony_ci	unsigned int lock_batch;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
97762306a36Sopenharmony_ci		struct folio *folio;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci		/* Turn any of the argument types into a folio */
98062306a36Sopenharmony_ci		folio = page_folio(encoded_page_ptr(encoded[i]));
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci		/*
98362306a36Sopenharmony_ci		 * Make sure the IRQ-safe lock-holding time does not get
98462306a36Sopenharmony_ci		 * excessive with a continuous string of pages from the
98562306a36Sopenharmony_ci		 * same lruvec. The lock is held only if lruvec != NULL.
98662306a36Sopenharmony_ci		 */
98762306a36Sopenharmony_ci		if (lruvec && ++lock_batch == SWAP_CLUSTER_MAX) {
98862306a36Sopenharmony_ci			unlock_page_lruvec_irqrestore(lruvec, flags);
98962306a36Sopenharmony_ci			lruvec = NULL;
99062306a36Sopenharmony_ci		}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		if (is_huge_zero_page(&folio->page))
99362306a36Sopenharmony_ci			continue;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci		if (folio_is_zone_device(folio)) {
99662306a36Sopenharmony_ci			if (lruvec) {
99762306a36Sopenharmony_ci				unlock_page_lruvec_irqrestore(lruvec, flags);
99862306a36Sopenharmony_ci				lruvec = NULL;
99962306a36Sopenharmony_ci			}
100062306a36Sopenharmony_ci			if (put_devmap_managed_page(&folio->page))
100162306a36Sopenharmony_ci				continue;
100262306a36Sopenharmony_ci			if (folio_put_testzero(folio))
100362306a36Sopenharmony_ci				free_zone_device_page(&folio->page);
100462306a36Sopenharmony_ci			continue;
100562306a36Sopenharmony_ci		}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci		if (!folio_put_testzero(folio))
100862306a36Sopenharmony_ci			continue;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci		if (folio_test_large(folio)) {
101162306a36Sopenharmony_ci			if (lruvec) {
101262306a36Sopenharmony_ci				unlock_page_lruvec_irqrestore(lruvec, flags);
101362306a36Sopenharmony_ci				lruvec = NULL;
101462306a36Sopenharmony_ci			}
101562306a36Sopenharmony_ci			__folio_put_large(folio);
101662306a36Sopenharmony_ci			continue;
101762306a36Sopenharmony_ci		}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci		if (folio_test_lru(folio)) {
102062306a36Sopenharmony_ci			struct lruvec *prev_lruvec = lruvec;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci			lruvec = folio_lruvec_relock_irqsave(folio, lruvec,
102362306a36Sopenharmony_ci									&flags);
102462306a36Sopenharmony_ci			if (prev_lruvec != lruvec)
102562306a36Sopenharmony_ci				lock_batch = 0;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci			lruvec_del_folio(lruvec, folio);
102862306a36Sopenharmony_ci			__folio_clear_lru_flags(folio);
102962306a36Sopenharmony_ci		}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci		/*
103262306a36Sopenharmony_ci		 * In rare cases, when truncation or holepunching raced with
103362306a36Sopenharmony_ci		 * munlock after VM_LOCKED was cleared, Mlocked may still be
103462306a36Sopenharmony_ci		 * found set here.  This does not indicate a problem, unless
103562306a36Sopenharmony_ci		 * "unevictable_pgs_cleared" appears worryingly large.
103662306a36Sopenharmony_ci		 */
103762306a36Sopenharmony_ci		if (unlikely(folio_test_mlocked(folio))) {
103862306a36Sopenharmony_ci			__folio_clear_mlocked(folio);
103962306a36Sopenharmony_ci			zone_stat_sub_folio(folio, NR_MLOCK);
104062306a36Sopenharmony_ci			count_vm_event(UNEVICTABLE_PGCLEARED);
104162306a36Sopenharmony_ci		}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci		list_add(&folio->lru, &pages_to_free);
104462306a36Sopenharmony_ci	}
104562306a36Sopenharmony_ci	if (lruvec)
104662306a36Sopenharmony_ci		unlock_page_lruvec_irqrestore(lruvec, flags);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	mem_cgroup_uncharge_list(&pages_to_free);
104962306a36Sopenharmony_ci	free_unref_page_list(&pages_to_free);
105062306a36Sopenharmony_ci}
105162306a36Sopenharmony_ciEXPORT_SYMBOL(release_pages);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci/*
105462306a36Sopenharmony_ci * The folios which we're about to release may be in the deferred lru-addition
105562306a36Sopenharmony_ci * queues.  That would prevent them from really being freed right now.  That's
105662306a36Sopenharmony_ci * OK from a correctness point of view but is inefficient - those folios may be
105762306a36Sopenharmony_ci * cache-warm and we want to give them back to the page allocator ASAP.
105862306a36Sopenharmony_ci *
105962306a36Sopenharmony_ci * So __folio_batch_release() will drain those queues here.
106062306a36Sopenharmony_ci * folio_batch_move_lru() calls folios_put() directly to avoid
106162306a36Sopenharmony_ci * mutual recursion.
106262306a36Sopenharmony_ci */
106362306a36Sopenharmony_civoid __folio_batch_release(struct folio_batch *fbatch)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	if (!fbatch->percpu_pvec_drained) {
106662306a36Sopenharmony_ci		lru_add_drain();
106762306a36Sopenharmony_ci		fbatch->percpu_pvec_drained = true;
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci	release_pages(fbatch->folios, folio_batch_count(fbatch));
107062306a36Sopenharmony_ci	folio_batch_reinit(fbatch);
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ciEXPORT_SYMBOL(__folio_batch_release);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci/**
107562306a36Sopenharmony_ci * folio_batch_remove_exceptionals() - Prune non-folios from a batch.
107662306a36Sopenharmony_ci * @fbatch: The batch to prune
107762306a36Sopenharmony_ci *
107862306a36Sopenharmony_ci * find_get_entries() fills a batch with both folios and shadow/swap/DAX
107962306a36Sopenharmony_ci * entries.  This function prunes all the non-folio entries from @fbatch
108062306a36Sopenharmony_ci * without leaving holes, so that it can be passed on to folio-only batch
108162306a36Sopenharmony_ci * operations.
108262306a36Sopenharmony_ci */
108362306a36Sopenharmony_civoid folio_batch_remove_exceptionals(struct folio_batch *fbatch)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	unsigned int i, j;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	for (i = 0, j = 0; i < folio_batch_count(fbatch); i++) {
108862306a36Sopenharmony_ci		struct folio *folio = fbatch->folios[i];
108962306a36Sopenharmony_ci		if (!xa_is_value(folio))
109062306a36Sopenharmony_ci			fbatch->folios[j++] = folio;
109162306a36Sopenharmony_ci	}
109262306a36Sopenharmony_ci	fbatch->nr = j;
109362306a36Sopenharmony_ci}
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci/*
109662306a36Sopenharmony_ci * Perform any setup for the swap system
109762306a36Sopenharmony_ci */
109862306a36Sopenharmony_civoid __init swap_setup(void)
109962306a36Sopenharmony_ci{
110062306a36Sopenharmony_ci	unsigned long megs = totalram_pages() >> (20 - PAGE_SHIFT);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	/* Use a smaller cluster for small-memory machines */
110362306a36Sopenharmony_ci	if (megs < 16)
110462306a36Sopenharmony_ci		page_cluster = 2;
110562306a36Sopenharmony_ci	else
110662306a36Sopenharmony_ci		page_cluster = 3;
110762306a36Sopenharmony_ci	/*
110862306a36Sopenharmony_ci	 * Right now other parts of the system means that we
110962306a36Sopenharmony_ci	 * _really_ don't want to cluster much more
111062306a36Sopenharmony_ci	 */
111162306a36Sopenharmony_ci}
1112