1157 lines · 32.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* *  linux/mm/folio.c * *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds */ /* * Folio LRU helpers: add/remove folios from LRU lists, batching, * activation/deactivation, and page cache release paths. */ #include <linux/mm.h>#include <linux/sched.h>#include <linux/kernel_stat.h>#include <linux/swap.h>#include <linux/mman.h>#include <linux/pagemap.h>#include <linux/folio_batch.h>#include <linux/init.h>#include <linux/export.h>#include <linux/mm_inline.h>#include <linux/percpu_counter.h>#include <linux/memremap.h>#include <linux/percpu.h>#include <linux/cpu.h>#include <linux/notifier.h>#include <linux/backing-dev.h>#include <linux/memcontrol.h>#include <linux/gfp.h>#include <linux/uio.h>#include <linux/hugetlb.h>#include <linux/page_idle.h>#include <linux/local_lock.h>#include <linux/buffer_head.h> #include "internal.h"#include "page_alloc.h" #define CREATE_TRACE_POINTS#include <trace/events/pagemap.h> struct cpu_fbatches {	/*	 * The following folio batches are grouped together because they are protected	 * by disabling preemption (and interrupts remain enabled).	 */	local_lock_t lock;	struct folio_batch lru_add;	struct folio_batch lru_deactivate_file;	struct folio_batch lru_deactivate;	struct folio_batch lru_lazyfree;#ifdef CONFIG_SMP	struct folio_batch lru_activate;#endif	/* Protecting the following batches which require disabling interrupts */	local_lock_t lock_irq;	struct folio_batch lru_move_tail;}; static DEFINE_PER_CPU(struct cpu_fbatches, cpu_fbatches) = {	.lock = INIT_LOCAL_LOCK(lock),	.lock_irq = INIT_LOCAL_LOCK(lock_irq),}; static void __page_cache_release(struct folio *folio, struct lruvec **lruvecp,		unsigned long *flagsp){	if (folio_test_lru(folio)) {		folio_lruvec_relock_irqsave(folio, lruvecp, flagsp);		lruvec_del_folio(*lruvecp, folio);		__folio_clear_lru_flags(folio);	}} /* * This path almost never happens for VM activity - pages are normally freed * in batches.  But it gets used by networking - and for compound pages. */static void page_cache_release(struct folio *folio){	struct lruvec *lruvec = NULL;	unsigned long flags; 	__page_cache_release(folio, &lruvec, &flags);	if (lruvec)		lruvec_unlock_irqrestore(lruvec, flags);} void __folio_put(struct folio *folio){	if (unlikely(folio_is_zone_device(folio))) {		free_zone_device_folio(folio);		return;	} 	if (folio_test_hugetlb(folio)) {		free_huge_folio(folio);		return;	} 	page_cache_release(folio);	folio_unqueue_deferred_split(folio);	mem_cgroup_uncharge(folio);	free_frozen_pages(&folio->page, folio_order(folio));}EXPORT_SYMBOL(__folio_put); typedef void (*move_fn_t)(struct lruvec *lruvec, struct folio *folio); static void lru_add(struct lruvec *lruvec, struct folio *folio){	int was_unevictable = folio_test_clear_unevictable(folio);	long nr_pages = folio_nr_pages(folio); 	VM_BUG_ON_FOLIO(folio_test_lru(folio), folio); 	/*	 * Is an smp_mb__after_atomic() still required here, before	 * folio_evictable() tests the mlocked flag, to rule out the possibility	 * of stranding an evictable folio on an unevictable LRU?  I think	 * not, because __munlock_folio() only clears the mlocked flag	 * while the LRU lock is held.	 *	 * (That is not true of __page_cache_release(), and not necessarily	 * true of folios_put(): but those only clear the mlocked flag after	 * folio_put_testzero() has excluded any other users of the folio.)	 */	if (folio_evictable(folio)) {		if (was_unevictable)			__count_vm_events(UNEVICTABLE_PGRESCUED, nr_pages);	} else {		folio_clear_active(folio);		folio_set_unevictable(folio);		/*		 * folio->mlock_count = !!folio_test_mlocked(folio)?		 * But that leaves __mlock_folio() in doubt whether another		 * actor has already counted the mlock or not.  Err on the		 * safe side, underestimate, let page reclaim fix it, rather		 * than leaving a page on the unevictable LRU indefinitely.		 */		folio->mlock_count = 0;		if (!was_unevictable)			__count_vm_events(UNEVICTABLE_PGCULLED, nr_pages);	} 	lruvec_add_folio(lruvec, folio);	trace_mm_lru_insertion(folio);} static void folio_batch_move_lru(struct folio_batch *fbatch, move_fn_t move_fn){	int i;	struct lruvec *lruvec = NULL;	unsigned long flags = 0;	struct folio_batch free_fbatch;	bool is_lru_add = (move_fn == lru_add); 	/*	 * If we're adding to the LRU, preemptively filter dead folios. Use	 * this dedicated folio batch for temp storage and deferred cleanup.	 */	if (is_lru_add)		folio_batch_init(&free_fbatch); 	for (i = 0; i < folio_batch_count(fbatch); i++) {		struct folio *folio = fbatch->folios[i]; 		/* block memcg migration while the folio moves between lru */		if (!is_lru_add && !folio_test_clear_lru(folio))			continue; 		/*		 * Filter dead folios by moving them from the add batch to the temp		 * batch for freeing after this loop.		 *		 * We're bypassing normal cleanup. Clear flags that are not		 * applicable to dead folios.		 *		 * Since the folio may be part of a huge page, unqueue from		 * deferred split list to avoid a dangling list entry.		 */		if (is_lru_add && folio_ref_freeze(folio, 1)) {			__folio_clear_active(folio);			__folio_clear_unevictable(folio);			folio_unqueue_deferred_split(folio);			fbatch->folios[i] = NULL;			folio_batch_add(&free_fbatch, folio);			continue;		} 		folio_lruvec_relock_irqsave(folio, &lruvec, &flags);		move_fn(lruvec, folio); 		folio_set_lru(folio);	} 	if (lruvec)		lruvec_unlock_irqrestore(lruvec, flags); 	/* Cleanup filtered dead folios. */	if (is_lru_add) {		mem_cgroup_uncharge_folios(&free_fbatch);		free_unref_folios(&free_fbatch);	} 	folios_put(fbatch);} static void __folio_batch_add_and_move(struct folio_batch __percpu *fbatch,		struct folio *folio, move_fn_t move_fn, bool disable_irq){	unsigned long flags; 	folio_get(folio); 	if (disable_irq)		local_lock_irqsave(&cpu_fbatches.lock_irq, flags);	else		local_lock(&cpu_fbatches.lock); 	if (!folio_batch_add(this_cpu_ptr(fbatch), folio) ||			!folio_may_be_lru_cached(folio) || lru_cache_disabled())		folio_batch_move_lru(this_cpu_ptr(fbatch), move_fn); 	if (disable_irq)		local_unlock_irqrestore(&cpu_fbatches.lock_irq, flags);	else		local_unlock(&cpu_fbatches.lock);} #define folio_batch_add_and_move(folio, op)		\	__folio_batch_add_and_move(			\		&cpu_fbatches.op,			\		folio,					\		op,					\		offsetof(struct cpu_fbatches, op) >=	\		offsetof(struct cpu_fbatches, lock_irq)	\	) static void lru_move_tail(struct lruvec *lruvec, struct folio *folio){	if (folio_test_unevictable(folio))		return; 	lruvec_del_folio(lruvec, folio);	folio_clear_active(folio);	lruvec_add_folio_tail(lruvec, folio);	__count_vm_events(PGROTATED, folio_nr_pages(folio));} /* * Writeback is about to end against a folio which has been marked for * immediate reclaim.  If it still appears to be reclaimable, move it * to the tail of the inactive list. * * folio_rotate_reclaimable() must disable IRQs, to prevent nasty races. */void folio_rotate_reclaimable(struct folio *folio){	if (folio_test_locked(folio) || folio_test_dirty(folio) ||	    folio_test_unevictable(folio) || !folio_test_lru(folio))		return; 	folio_batch_add_and_move(folio, lru_move_tail);} static void lru_activate(struct lruvec *lruvec, struct folio *folio){	long nr_pages = folio_nr_pages(folio); 	if (folio_test_active(folio) || folio_test_unevictable(folio))		return;  	lruvec_del_folio(lruvec, folio);	folio_set_active(folio);	lruvec_add_folio(lruvec, folio);	trace_mm_lru_activate(folio); 	__count_vm_events(PGACTIVATE, nr_pages);	count_memcg_events(lruvec_memcg(lruvec), PGACTIVATE, nr_pages);} #ifdef CONFIG_SMPstatic void folio_activate_drain(int cpu){	struct folio_batch *fbatch = &per_cpu(cpu_fbatches.lru_activate, cpu); 	if (folio_batch_count(fbatch))		folio_batch_move_lru(fbatch, lru_activate);} void folio_activate(struct folio *folio){	if (folio_test_active(folio) || folio_test_unevictable(folio) ||	    !folio_test_lru(folio))		return; 	folio_batch_add_and_move(folio, lru_activate);} #elsestatic inline void folio_activate_drain(int cpu){} void folio_activate(struct folio *folio){	struct lruvec *lruvec; 	if (!folio_test_clear_lru(folio))		return; 	lruvec = folio_lruvec_lock_irq(folio);	lru_activate(lruvec, folio);	lruvec_unlock_irq(lruvec);	folio_set_lru(folio);}#endif static void __lru_cache_activate_folio(struct folio *folio){	struct folio_batch *fbatch;	int i; 	local_lock(&cpu_fbatches.lock);	fbatch = this_cpu_ptr(&cpu_fbatches.lru_add); 	/*	 * Search backwards on the optimistic assumption that the folio being	 * activated has just been added to this batch. Note that only	 * the local batch is examined as a !LRU folio could be in the	 * process of being released, reclaimed, migrated or on a remote	 * batch that is currently being drained. Furthermore, marking	 * a remote batch's folio active potentially hits a race where	 * a folio is marked active just after it is added to the inactive	 * list causing accounting errors and BUG_ON checks to trigger.	 */	for (i = folio_batch_count(fbatch) - 1; i >= 0; i--) {		struct folio *batch_folio = fbatch->folios[i]; 		if (batch_folio == folio) {			folio_set_active(folio);			break;		}	} 	local_unlock(&cpu_fbatches.lock);} #ifdef CONFIG_LRU_GEN static void lru_gen_inc_refs(struct folio *folio){	unsigned long new_flags, old_flags = READ_ONCE(folio->flags.f); 	if (folio_test_unevictable(folio))		return; 	/* see the comment on LRU_REFS_FLAGS */	if (!folio_test_referenced(folio)) {		set_mask_bits(&folio->flags.f, LRU_REFS_MASK, BIT(PG_referenced));		return;	} 	do {		if ((old_flags & LRU_REFS_MASK) == LRU_REFS_MASK) {			if (!folio_test_workingset(folio))				folio_set_workingset(folio);			return;		} 		new_flags = old_flags + BIT(LRU_REFS_PGOFF);	} while (!try_cmpxchg(&folio->flags.f, &old_flags, new_flags));} static bool lru_gen_clear_refs(struct folio *folio){	int gen = folio_lru_gen(folio);	int type = folio_is_file_lru(folio);	unsigned long seq; 	if (gen < 0)		return true; 	set_mask_bits(&folio->flags.f, LRU_REFS_FLAGS | BIT(PG_workingset), 0); 	rcu_read_lock();	seq = READ_ONCE(folio_lruvec(folio)->lrugen.min_seq[type]);	rcu_read_unlock();	/* whether can do without shuffling under the LRU lock */	return gen == lru_gen_from_seq(seq);} #else /* !CONFIG_LRU_GEN */ static void lru_gen_inc_refs(struct folio *folio){} static bool lru_gen_clear_refs(struct folio *folio){	return false;} #endif /* CONFIG_LRU_GEN */ /** * folio_mark_accessed - Mark a folio as having seen activity. * @folio: The folio to mark. * * This function will perform one of the following transitions: * * * inactive,unreferenced	->	inactive,referenced * * inactive,referenced	->	active,unreferenced * * active,unreferenced	->	active,referenced * * When a newly allocated folio is not yet visible, so safe for non-atomic ops, * __folio_set_referenced() may be substituted for folio_mark_accessed(). */void folio_mark_accessed(struct folio *folio){	if (folio_test_dropbehind(folio))		return;	if (lru_gen_enabled()) {		lru_gen_inc_refs(folio);		return;	} 	if (!folio_test_referenced(folio)) {		folio_set_referenced(folio);	} else if (folio_test_unevictable(folio)) {		/*		 * Unevictable pages are on the "LRU_UNEVICTABLE" list. But,		 * this list is never rotated or maintained, so marking an		 * unevictable page accessed has no effect.		 */	} else if (!folio_test_active(folio)) {		/*		 * If the folio is on the LRU, queue it for activation via		 * cpu_fbatches.lru_activate. Otherwise, assume the folio is in a		 * folio_batch, mark it active and it'll be moved to the active		 * LRU on the next drain.		 */		if (folio_test_lru(folio))			folio_activate(folio);		else			__lru_cache_activate_folio(folio);		folio_clear_referenced(folio);		workingset_activation(folio);	}	if (folio_test_idle(folio))		folio_clear_idle(folio);}EXPORT_SYMBOL(folio_mark_accessed); /** * folio_add_lru - Add a folio to an LRU list. * @folio: The folio to be added to the LRU. * * Queue the folio for addition to the LRU. The decision on whether * to add the page to the [in]active [file|anon] list is deferred until the * folio_batch is drained. This gives a chance for the caller of folio_add_lru() * have the folio added to the active list using folio_mark_accessed(). */void folio_add_lru(struct folio *folio){	VM_BUG_ON_FOLIO(folio_test_active(folio) &&			folio_test_unevictable(folio), folio);	VM_BUG_ON_FOLIO(folio_test_lru(folio), folio); 	/*	 * For refaulted workingset folios, set PG_active so they	 * can be added to active generations.	 * For prefaulted file folios, folio_mark_accessed() sets	 * PG_referenced so lru_gen_folio_seq() places them into	 * the second oldest generation.	 */	if (lru_gen_enabled() && !folio_test_unevictable(folio) &&	    lru_gen_in_fault() && !(current->flags & PF_MEMALLOC)) {		if (folio_test_workingset(folio))			folio_set_active(folio);		else if (!folio_test_referenced(folio))			folio_mark_accessed(folio);	} 	folio_batch_add_and_move(folio, lru_add);}EXPORT_SYMBOL(folio_add_lru); /** * folio_add_lru_vma() - Add a folio to the appropriate LRU list for this VMA. * @folio: The folio to be added to the LRU. * @vma: VMA in which the folio is mapped. * * If the VMA is mlocked, @folio is added to the unevictable list. * Otherwise, it is treated the same way as folio_add_lru(). */void folio_add_lru_vma(struct folio *folio, struct vm_area_struct *vma)

Lines 1–500 of 1157.