Commit eeccf287 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'mm-stable-2026-02-18-19-48' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull more MM  updates from Andrew Morton:

 - "mm/vmscan: fix demotion targets checks in reclaim/demotion" fixes a
   couple of issues in the demotion code - pages were failed demotion
   and were finding themselves demoted into disallowed nodes (Bing Jiao)

 - "Remove XA_ZERO from error recovery of dup_mmap()" fixes a rare
   mapledtree race and performs a number of cleanups (Liam Howlett)

 - "mm: add bitmap VMA flag helpers and convert all mmap_prepare to use
   them" implements a lot of cleanups following on from the conversion
   of the VMA flags into a bitmap (Lorenzo Stoakes)

 - "support batch checking of references and unmapping for large folios"
   implements batching to greatly improve the performance of reclaiming
   clean file-backed large folios (Baolin Wang)

 - "selftests/mm: add memory failure selftests" does as claimed (Miaohe
   Lin)

* tag 'mm-stable-2026-02-18-19-48' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (36 commits)
  mm/page_alloc: clear page->private in free_pages_prepare()
  selftests/mm: add memory failure dirty pagecache test
  selftests/mm: add memory failure clean pagecache test
  selftests/mm: add memory failure anonymous page test
  mm: rmap: support batched unmapping for file large folios
  arm64: mm: implement the architecture-specific clear_flush_young_ptes()
  arm64: mm: support batch clearing of the young flag for large folios
  arm64: mm: factor out the address and ptep alignment into a new helper
  mm: rmap: support batched checks of the references for large folios
  tools/testing/vma: add VMA userland tests for VMA flag functions
  tools/testing/vma: separate out vma_internal.h into logical headers
  tools/testing/vma: separate VMA userland tests into separate files
  mm: make vm_area_desc utilise vma_flags_t only
  mm: update all remaining mmap_prepare users to use vma_flags_t
  mm: update shmem_[kernel]_file_*() functions to use vma_flags_t
  mm: update secretmem to use VMA flags on mmap_prepare
  mm: update hugetlbfs to use VMA flags on mmap_prepare
  mm: add basic VMA flag operation helper functions
  tools: bitmap: add missing bitmap_[subset(), andnot()]
  mm: add mk_vma_flags() bitmap flag macro helper
  ...
parents 956b9cbd ac1ea219
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -11845,6 +11845,7 @@ F: include/linux/memory-failure.h
F:	include/trace/events/memory-failure.h
F:	mm/hwpoison-inject.c
F:	mm/memory-failure.c
F:	tools/testing/selftests/mm/memory-failure.c
HYCON HY46XX TOUCHSCREEN SUPPORT
M:	Giulio Benetti <giulio.benetti@benettiengineering.com>
+17 −6
Original line number Diff line number Diff line
@@ -1648,10 +1648,10 @@ extern void contpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr,
extern pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
				unsigned long addr, pte_t *ptep,
				unsigned int nr, int full);
extern int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
				unsigned long addr, pte_t *ptep);
extern int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
				unsigned long addr, pte_t *ptep);
int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
				unsigned long addr, pte_t *ptep, unsigned int nr);
int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
				unsigned long addr, pte_t *ptep, unsigned int nr);
extern void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
				pte_t *ptep, unsigned int nr);
extern int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
@@ -1823,7 +1823,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
	if (likely(!pte_valid_cont(orig_pte)))
		return __ptep_test_and_clear_young(vma, addr, ptep);

	return contpte_ptep_test_and_clear_young(vma, addr, ptep);
	return contpte_test_and_clear_young_ptes(vma, addr, ptep, 1);
}

#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
@@ -1835,7 +1835,18 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
	if (likely(!pte_valid_cont(orig_pte)))
		return __ptep_clear_flush_young(vma, addr, ptep);

	return contpte_ptep_clear_flush_young(vma, addr, ptep);
	return contpte_clear_flush_young_ptes(vma, addr, ptep, 1);
}

#define clear_flush_young_ptes clear_flush_young_ptes
static inline int clear_flush_young_ptes(struct vm_area_struct *vma,
					 unsigned long addr, pte_t *ptep,
					 unsigned int nr)
{
	if (likely(nr == 1 && !pte_cont(__ptep_get(ptep))))
		return __ptep_clear_flush_young(vma, addr, ptep);

	return contpte_clear_flush_young_ptes(vma, addr, ptep, nr);
}

#define wrprotect_ptes wrprotect_ptes
+40 −22
Original line number Diff line number Diff line
@@ -26,6 +26,26 @@ static inline pte_t *contpte_align_down(pte_t *ptep)
	return PTR_ALIGN_DOWN(ptep, sizeof(*ptep) * CONT_PTES);
}

static inline pte_t *contpte_align_addr_ptep(unsigned long *start,
					     unsigned long *end, pte_t *ptep,
					     unsigned int nr)
{
	/*
	 * Note: caller must ensure these nr PTEs are consecutive (present)
	 * PTEs that map consecutive pages of the same large folio within a
	 * single VMA and a single page table.
	 */
	if (pte_cont(__ptep_get(ptep + nr - 1)))
		*end = ALIGN(*end, CONT_PTE_SIZE);

	if (pte_cont(__ptep_get(ptep))) {
		*start = ALIGN_DOWN(*start, CONT_PTE_SIZE);
		ptep = contpte_align_down(ptep);
	}

	return ptep;
}

static void contpte_try_unfold_partial(struct mm_struct *mm, unsigned long addr,
					pte_t *ptep, unsigned int nr)
{
@@ -488,8 +508,9 @@ pte_t contpte_get_and_clear_full_ptes(struct mm_struct *mm,
}
EXPORT_SYMBOL_GPL(contpte_get_and_clear_full_ptes);

int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
					unsigned long addr, pte_t *ptep)
int contpte_test_and_clear_young_ptes(struct vm_area_struct *vma,
					unsigned long addr, pte_t *ptep,
					unsigned int nr)
{
	/*
	 * ptep_clear_flush_young() technically requires us to clear the access
@@ -498,41 +519,45 @@ int contpte_ptep_test_and_clear_young(struct vm_area_struct *vma,
	 * contig range when the range is covered by a single folio, we can get
	 * away with clearing young for the whole contig range here, so we avoid
	 * having to unfold.
	 *
	 * The 'nr' means consecutive (present) PTEs that map consecutive pages
	 * of the same large folio in a single VMA and a single page table.
	 */

	unsigned long end = addr + nr * PAGE_SIZE;
	int young = 0;
	int i;

	ptep = contpte_align_down(ptep);
	addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);

	for (i = 0; i < CONT_PTES; i++, ptep++, addr += PAGE_SIZE)
	ptep = contpte_align_addr_ptep(&addr, &end, ptep, nr);
	for (; addr != end; ptep++, addr += PAGE_SIZE)
		young |= __ptep_test_and_clear_young(vma, addr, ptep);

	return young;
}
EXPORT_SYMBOL_GPL(contpte_ptep_test_and_clear_young);
EXPORT_SYMBOL_GPL(contpte_test_and_clear_young_ptes);

int contpte_ptep_clear_flush_young(struct vm_area_struct *vma,
					unsigned long addr, pte_t *ptep)
int contpte_clear_flush_young_ptes(struct vm_area_struct *vma,
				unsigned long addr, pte_t *ptep,
				unsigned int nr)
{
	int young;

	young = contpte_ptep_test_and_clear_young(vma, addr, ptep);
	young = contpte_test_and_clear_young_ptes(vma, addr, ptep, nr);

	if (young) {
		unsigned long end = addr + nr * PAGE_SIZE;

		contpte_align_addr_ptep(&addr, &end, ptep, nr);
		/*
		 * See comment in __ptep_clear_flush_young(); same rationale for
		 * eliding the trailing DSB applies here.
		 */
		addr = ALIGN_DOWN(addr, CONT_PTE_SIZE);
		__flush_tlb_range_nosync(vma->vm_mm, addr, addr + CONT_PTE_SIZE,
		__flush_tlb_range_nosync(vma->vm_mm, addr, end,
					 PAGE_SIZE, true, 3);
	}

	return young;
}
EXPORT_SYMBOL_GPL(contpte_ptep_clear_flush_young);
EXPORT_SYMBOL_GPL(contpte_clear_flush_young_ptes);

void contpte_wrprotect_ptes(struct mm_struct *mm, unsigned long addr,
					pte_t *ptep, unsigned int nr)
@@ -569,14 +594,7 @@ void contpte_clear_young_dirty_ptes(struct vm_area_struct *vma,
	unsigned long start = addr;
	unsigned long end = start + nr * PAGE_SIZE;

	if (pte_cont(__ptep_get(ptep + nr - 1)))
		end = ALIGN(end, CONT_PTE_SIZE);

	if (pte_cont(__ptep_get(ptep))) {
		start = ALIGN_DOWN(start, CONT_PTE_SIZE);
		ptep = contpte_align_down(ptep);
	}

	ptep = contpte_align_addr_ptep(&start, &end, ptep, nr);
	__clear_young_dirty_ptes(vma, start, ptep, (end - start) / PAGE_SIZE, flags);
}
EXPORT_SYMBOL_GPL(contpte_clear_young_dirty_ptes);
+1 −1
Original line number Diff line number Diff line
@@ -83,7 +83,7 @@ static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs)
	encl_size = secs->size + PAGE_SIZE;

	backing = shmem_file_setup("SGX backing", encl_size + (encl_size >> 5),
				   VM_NORESERVE);
				   mk_vma_flags(VMA_NORESERVE_BIT));
	if (IS_ERR(backing)) {
		ret = PTR_ERR(backing);
		goto err_out_shrink;
+3 −3
Original line number Diff line number Diff line
@@ -306,7 +306,7 @@ static unsigned zero_mmap_capabilities(struct file *file)
/* can't do an in-place private mapping if there's no MMU */
static inline int private_mapping_ok(struct vm_area_desc *desc)
{
	return is_nommu_shared_mapping(desc->vm_flags);
	return is_nommu_shared_vma_flags(&desc->vma_flags);
}
#else

@@ -360,7 +360,7 @@ static int mmap_mem_prepare(struct vm_area_desc *desc)

	desc->vm_ops = &mmap_mem_ops;

	/* Remap-pfn-range will mark the range VM_IO. */
	/* Remap-pfn-range will mark the range with the I/O flag. */
	mmap_action_remap_full(desc, desc->pgoff);
	/* We filter remap errors to -EAGAIN. */
	desc->action.error_hook = mmap_filter_error;
@@ -520,7 +520,7 @@ static int mmap_zero_prepare(struct vm_area_desc *desc)
#ifndef CONFIG_MMU
	return -ENOSYS;
#endif
	if (desc->vm_flags & VM_SHARED)
	if (vma_desc_test_flags(desc, VMA_SHARED_BIT))
		return shmem_zero_setup_desc(desc);

	desc->action.success_hook = mmap_zero_private_success;
Loading