1657 lines · 50.2 KB · C
RawDownload
/* SPDX-License-Identifier: GPL-2.0-or-later *//* internal.h: mm/ internal definitions * * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) */#ifndef __MM_INTERNAL_H#define __MM_INTERNAL_H #include <linux/fs.h>#include <linux/khugepaged.h>#include <linux/mm.h>#include <linux/mm_inline.h>#include <linux/mmu_notifier.h>#include <linux/pagemap.h>#include <linux/pagewalk.h>#include <linux/rmap.h>#include <linux/swap.h>#include <linux/leafops.h>#include <linux/tracepoint-defs.h> /* Internal core VMA manipulation functions. */#include "vma.h" struct folio_batch;struct hstate; struct huge_bootmem_page {	struct list_head list;	struct hstate *hstate;	unsigned long flags;}; /* mm/workingset.c */bool workingset_test_recent(void *shadow, bool file, bool *workingset,			    bool flush);void workingset_age_nonresident(struct lruvec *lruvec, unsigned long nr_pages);void *workingset_eviction(struct folio *folio,			  struct mem_cgroup *target_memcg);void workingset_refault(struct folio *folio, void *shadow);void workingset_activation(struct folio *folio); /* mm/folio.c */void folio_add_lru_vma(struct folio *folio, struct vm_area_struct *vma); static inline bool folio_may_be_lru_cached(const struct folio *folio){	/*	 * Holding PMD-sized folios in per-CPU LRU cache unbalances accounting.	 * Holding small numbers of low-order mTHP folios in per-CPU LRU cache	 * will be sensible, but nobody has implemented and tested that yet.	 */	return !folio_test_large(folio);} static inline void lru_cache_enable(void){	atomic_dec(&lru_disable_count);} void lru_cache_disable(void);void lru_add_drain(void);void lru_add_drain_cpu(int cpu);void lru_add_drain_cpu_zone(struct zone *zone);void folio_deactivate(struct folio *folio);void folio_mark_lazyfree(struct folio *folio); /* mm/vmscan.c */unsigned long zone_reclaimable_pages(struct zone *zone);unsigned long try_to_free_pages(struct zonelist *zonelist, int order,				gfp_t gfp_mask, const nodemask_t *mask);unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru,			      int zone_idx); #define MEMCG_RECLAIM_MAY_SWAP (1 << 1)#define MEMCG_RECLAIM_PROACTIVE (1 << 2)#define MIN_SWAPPINESS 0#define MAX_SWAPPINESS 200 /* Just reclaim from anon folios in proactive memory reclaim */#define SWAPPINESS_ANON_ONLY (MAX_SWAPPINESS + 1) unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,					   unsigned long nr_pages,					   gfp_t gfp_mask,					   unsigned int reclaim_options,					   int *swappiness);unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,				     gfp_t gfp_mask, bool noswap,				     pg_data_t *pgdat,				     unsigned long *nr_scanned); #ifdef CONFIG_NUMAextern int sysctl_min_unmapped_ratio;extern int sysctl_min_slab_ratio;#endif /* * Maintains state across a page table move. The operation assumes both source * and destination VMAs already exist and are specified by the user. * * Partial moves are permitted, but the old and new ranges must both reside * within a VMA. * * mmap lock must be held in write and VMA write locks must be held on any VMA * that is visible. * * Use the PAGETABLE_MOVE() macro to initialise this struct. * * The old_addr and new_addr fields are updated as the page table move is * executed. * * NOTE: The page table move is affected by reading from [old_addr, old_end), * and old_addr may be updated for better page table alignment, so len_in * represents the length of the range being copied as specified by the user. */struct pagetable_move_control {	struct vm_area_struct *old; /* Source VMA. */	struct vm_area_struct *new; /* Destination VMA. */	unsigned long old_addr; /* Address from which the move begins. */	unsigned long old_end; /* Exclusive address at which old range ends. */	unsigned long new_addr; /* Address to move page tables to. */	unsigned long len_in; /* Bytes to remap specified by user. */ 	bool need_rmap_locks; /* Do rmap locks need to be taken? */	bool for_stack; /* Is this an early temp stack being moved? */}; #define PAGETABLE_MOVE(name, old_, new_, old_addr_, new_addr_, len_)	\	struct pagetable_move_control name = {				\		.old = old_,						\		.new = new_,						\		.old_addr = old_addr_,					\		.old_end = (old_addr_) + (len_),			\		.new_addr = new_addr_,					\		.len_in = len_,						\	} /* * The set of flags that only affect watermark checking and reclaim * behaviour. This is used by the MM to obey the caller constraints * about IO, FS and watermark checking while ignoring placement * hints such as HIGHMEM usage. */#define GFP_RECLAIM_MASK (__GFP_RECLAIM|__GFP_HIGH|__GFP_IO|__GFP_FS|\			__GFP_NOWARN|__GFP_RETRY_MAYFAIL|__GFP_NOFAIL|\			__GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC|\			__GFP_NOLOCKDEP) /* The GFP flags allowed during early boot */#define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_RECLAIM|__GFP_IO|__GFP_FS)) /* Control allocation cpuset and node placement constraints */#define GFP_CONSTRAINT_MASK (__GFP_HARDWALL|__GFP_THISNODE) /* Do not use these with a slab allocator */#define GFP_SLAB_BUG_MASK (__GFP_DMA32|__GFP_HIGHMEM|~__GFP_BITS_MASK) /* * Different from WARN_ON_ONCE(), no warning will be issued * when we specify __GFP_NOWARN. */#define WARN_ON_ONCE_GFP(cond, gfp)	({				\	static bool __section(".data..once") __warned;			\	int __ret_warn_once = !!(cond);					\									\	if (unlikely(!(gfp & __GFP_NOWARN) && __ret_warn_once && !__warned)) { \		__warned = true;					\		WARN_ON(1);						\	}								\	unlikely(__ret_warn_once);					\}) void page_writeback_init(void); /* * If a 16GB hugetlb folio were mapped by PTEs of all of its 4kB pages, * its nr_pages_mapped would be 0x400000: choose the ENTIRELY_MAPPED bit * above that range, instead of 2*(PMD_SIZE/PAGE_SIZE).  Hugetlb currently * leaves nr_pages_mapped at 0, but avoid surprise if it participates later. */#define ENTIRELY_MAPPED		0x800000#define FOLIO_PAGES_MAPPED	(ENTIRELY_MAPPED - 1) /* * Flags passed to __show_mem() and show_free_areas() to suppress output in * various contexts. */#define SHOW_MEM_FILTER_NODES		(0x0001u)	/* disallowed nodes */ /* * How many individual pages have an elevated _mapcount.  Excludes * the folio's entire_mapcount. * * Don't use this function outside of debugging code. */static inline int folio_nr_pages_mapped(const struct folio *folio){	if (IS_ENABLED(CONFIG_NO_PAGE_MAPCOUNT))		return -1;	return atomic_read(&folio->_nr_pages_mapped) & FOLIO_PAGES_MAPPED;} /* * Retrieve the first entry of a folio based on a provided entry within the * folio. We cannot rely on folio->swap as there is no guarantee that it has * been initialized. Used for calling arch_swap_restore() */static inline swp_entry_t folio_swap(swp_entry_t entry,		const struct folio *folio){	swp_entry_t swap = {		.val = ALIGN_DOWN(entry.val, folio_nr_pages(folio)),	}; 	return swap;} static inline void *folio_raw_mapping(const struct folio *folio){	unsigned long mapping = (unsigned long)folio->mapping; 	return (void *)(mapping & ~FOLIO_MAPPING_FLAGS);} /* * This is a file-backed mapping, and is about to be memory mapped - invoke its * mmap hook and safely handle error conditions. On error, VMA hooks will be * mutated. * * @file: File which backs the mapping. * @vma:  VMA which we are mapping. * * Returns: 0 if success, error otherwise. */static inline int mmap_file(struct file *file, struct vm_area_struct *vma){	int err = vfs_mmap(file, vma); 	if (likely(!err))		return 0; 	/*	 * OK, we tried to call the file hook for mmap(), but an error	 * arose. The mapping is in an inconsistent state and we must not invoke	 * any further hooks on it.	 */	vma->vm_ops = &vma_dummy_vm_ops; 	return err;} /* * If the VMA has a close hook then close it, and since closing it might leave * it in an inconsistent state which makes the use of any hooks suspect, clear * them down by installing dummy empty hooks. */static inline void vma_close(struct vm_area_struct *vma){	if (vma->vm_ops && vma->vm_ops->close) {		vma->vm_ops->close(vma); 		/*		 * The mapping is in an inconsistent state, and no further hooks		 * may be invoked upon it.		 */		vma->vm_ops = &vma_dummy_vm_ops;	}} /* unmap_vmas is in mm/memory.c */void unmap_vmas(struct mmu_gather *tlb, struct unmap_desc *unmap); #ifdef CONFIG_MMU bool cond_install_uffd_wp_ptes(struct vm_area_struct *vma,		unsigned long addr, pte_t *ptep, pte_t pte,		unsigned long nr_ptes); static inline void get_anon_vma(struct anon_vma *anon_vma){	atomic_inc(&anon_vma->refcount);} void __put_anon_vma(struct anon_vma *anon_vma); static inline void put_anon_vma(struct anon_vma *anon_vma){	if (atomic_dec_and_test(&anon_vma->refcount))		__put_anon_vma(anon_vma);} static inline void anon_vma_lock_write(struct anon_vma *anon_vma){	down_write(&anon_vma->root->rwsem);} static inline int anon_vma_trylock_write(struct anon_vma *anon_vma){	return down_write_trylock(&anon_vma->root->rwsem);} static inline void anon_vma_unlock_write(struct anon_vma *anon_vma){	up_write(&anon_vma->root->rwsem);} static inline void anon_vma_lock_read(struct anon_vma *anon_vma){	down_read(&anon_vma->root->rwsem);} static inline int anon_vma_trylock_read(struct anon_vma *anon_vma){	return down_read_trylock(&anon_vma->root->rwsem);} static inline void anon_vma_unlock_read(struct anon_vma *anon_vma){	up_read(&anon_vma->root->rwsem);} struct anon_vma *folio_get_anon_vma(const struct folio *folio); /* Operations which modify VMAs. */enum vma_operation {	VMA_OP_SPLIT,	VMA_OP_MERGE_UNFAULTED,	VMA_OP_REMAP,	VMA_OP_FORK,}; int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src,	enum vma_operation operation);int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma);int  __anon_vma_prepare(struct vm_area_struct *vma);void unlink_anon_vmas(struct vm_area_struct *vma); static inline int anon_vma_prepare(struct vm_area_struct *vma){	if (likely(vma->anon_vma))		return 0; 	return __anon_vma_prepare(vma);} /* Flags for folio_pte_batch(). */typedef int __bitwise fpb_t; /* Compare PTEs respecting the dirty bit. */#define FPB_RESPECT_DIRTY		((__force fpb_t)BIT(0)) /* Compare PTEs respecting the soft-dirty bit. */#define FPB_RESPECT_SOFT_DIRTY		((__force fpb_t)BIT(1)) /* Compare PTEs respecting the writable bit. */#define FPB_RESPECT_WRITE		((__force fpb_t)BIT(2)) /* * Merge PTE write bits: if any PTE in the batch is writable, modify the * PTE at @ptentp to be writable. */#define FPB_MERGE_WRITE			((__force fpb_t)BIT(3)) /* * Merge PTE young and dirty bits: if any PTE in the batch is young or dirty, * modify the PTE at @ptentp to be young or dirty, respectively. */#define FPB_MERGE_YOUNG_DIRTY		((__force fpb_t)BIT(4)) static inline pte_t __pte_batch_clear_ignored(pte_t pte, fpb_t flags){	if (!(flags & FPB_RESPECT_DIRTY))		pte = pte_mkclean(pte);	if (likely(!(flags & FPB_RESPECT_SOFT_DIRTY)))		pte = pte_clear_soft_dirty(pte);	if (likely(!(flags & FPB_RESPECT_WRITE)))		pte = pte_wrprotect(pte);	return pte_mkold(pte);} /** * folio_pte_batch_flags - detect a PTE batch for a large folio * @folio: The large folio to detect a PTE batch for. * @vma: The VMA. Only relevant with FPB_MERGE_WRITE, otherwise can be NULL. * @ptep: Page table pointer for the first entry. * @ptentp: Pointer to a COPY of the first page table entry whose flags this *	    function updates based on @flags if appropriate. * @max_nr: The maximum number of table entries to consider. * @flags: Flags to modify the PTE batch semantics. * * Detect a PTE batch: consecutive (present) PTEs that map consecutive * pages of the same large folio in a single VMA and a single page table. * * All PTEs inside a PTE batch have the same PTE bits set, excluding the PFN, * the accessed bit, writable bit, dirty bit (unless FPB_RESPECT_DIRTY is set) * and soft-dirty bit (unless FPB_RESPECT_SOFT_DIRTY is set). * * @ptep must map any page of the folio. max_nr must be at least one and * must be limited by the caller so scanning cannot exceed a single VMA and * a single page table. * * Depending on the FPB_MERGE_* flags, the pte stored at @ptentp will * be updated: it's crucial that a pointer to a COPY of the first * page table entry, obtained through ptep_get(), is provided as @ptentp. * * This function will be inlined to optimize based on the input parameters; * consider using folio_pte_batch() instead if applicable. * * Return: the number of table entries in the batch. */static inline unsigned int folio_pte_batch_flags(struct folio *folio,		struct vm_area_struct *vma, pte_t *ptep, pte_t *ptentp,		unsigned int max_nr, fpb_t flags){	bool any_writable = false, any_young = false, any_dirty = false;	pte_t expected_pte, pte = *ptentp;	unsigned int nr, cur_nr; 	VM_WARN_ON_FOLIO(!pte_present(pte), folio);	VM_WARN_ON_FOLIO(!folio_test_large(folio) || max_nr < 1, folio);	VM_WARN_ON_FOLIO(page_folio(pfn_to_page(pte_pfn(pte))) != folio, folio);	/*	 * Ensure this is a pointer to a copy not a pointer into a page table.	 * If this is a stack value, it won't be a valid virtual address, but	 * that's fine because it also cannot be pointing into the page table.	 */	VM_WARN_ON(virt_addr_valid(ptentp) && PageTable(virt_to_page(ptentp))); 	/* Limit max_nr to the actual remaining PFNs in the folio we could batch. */	max_nr = min_t(unsigned long, max_nr,		       folio_pfn(folio) + folio_nr_pages(folio) - pte_pfn(pte)); 	nr = pte_batch_hint(ptep, pte);	expected_pte = __pte_batch_clear_ignored(pte_advance_pfn(pte, nr), flags);	ptep = ptep + nr; 	while (nr < max_nr) {		pte = ptep_get(ptep); 		if (!pte_same(__pte_batch_clear_ignored(pte, flags), expected_pte))			break; 		if (flags & FPB_MERGE_WRITE)			any_writable |= pte_write(pte);		if (flags & FPB_MERGE_YOUNG_DIRTY) {			any_young |= pte_young(pte);			any_dirty |= pte_dirty(pte);		} 		cur_nr = pte_batch_hint(ptep, pte);		expected_pte = pte_advance_pfn(expected_pte, cur_nr);		ptep += cur_nr;		nr += cur_nr;	} 	if (any_writable)		*ptentp = pte_mkwrite(*ptentp, vma);	if (any_young)		*ptentp = pte_mkyoung(*ptentp);	if (any_dirty)		*ptentp = pte_mkdirty(*ptentp); 	return min(nr, max_nr);} unsigned int folio_pte_batch(struct folio *folio, pte_t *ptep, pte_t pte,		unsigned int max_nr); /** * pte_move_swp_offset - Move the swap entry offset field of a swap pte *	 forward or backward by delta * @pte: The initial pte state; must be a swap entry * @delta: The direction and the offset we are moving; forward if delta *	 is positive; backward if delta is negative * * Moves the swap offset, while maintaining all other fields, including * swap type, and any swp pte bits. The resulting pte is returned. */static inline pte_t pte_move_swp_offset(pte_t pte, long delta){	const softleaf_t entry = softleaf_from_pte(pte);	pte_t new = __swp_entry_to_pte(__swp_entry(swp_type(entry),						   (swp_offset(entry) + delta))); 	if (pte_swp_soft_dirty(pte))		new = pte_swp_mksoft_dirty(new);	if (pte_swp_exclusive(pte))		new = pte_swp_mkexclusive(new);	if (pte_swp_uffd(pte))		new = pte_swp_mkuffd(new); 	return new;}  /** * pte_next_swp_offset - Increment the swap entry offset field of a swap pte. * @pte: The initial pte state; must be a swap entry. *

Lines 1–500 of 1657.