Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'mm-hotfixes-stable-2025-08-21-18-17' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull misc fixes from Andrew Morton:
"20 hotfixes. 10 are cc:stable and the remainder address post-6.16
issues or aren't considered necessary for -stable kernels. 17 of these
fixes are for MM.

As usual, singletons all over the place, apart from a three-patch
series of KHO followup work from Pasha which is actually also a bunch
of singletons"

* tag 'mm-hotfixes-stable-2025-08-21-18-17' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
mm/mremap: fix WARN with uffd that has remap events disabled
mm/damon/sysfs-schemes: put damos dests dir after removing its files
mm/migrate: fix NULL movable_ops if CONFIG_ZSMALLOC=m
mm/damon/core: fix damos_commit_filter not changing allow
mm/memory-failure: fix infinite UCE for VM_PFNMAP pfn
MAINTAINERS: mark MGLRU as maintained
mm: rust: add page.rs to MEMORY MANAGEMENT - RUST
iov_iter: iterate_folioq: fix handling of offset >= folio size
selftests/damon: fix selftests by installing drgn related script
.mailmap: add entry for Easwar Hariharan
selftests/mm: add test for invalid multi VMA operations
mm/mremap: catch invalid multi VMA moves earlier
mm/mremap: allow multi-VMA move when filesystem uses thp_get_unmapped_area
mm/damon/core: fix commit_ops_filters by using correct nth function
tools/testing: add linux/args.h header and fix radix, VMA tests
mm/debug_vm_pgtable: clear page table entries at destroy_args()
squashfs: fix memory leak in squashfs_fill_super
kho: warn if KHO is disabled due to an error
kho: mm: don't allow deferred struct page with KHO
kho: init new_physxa->phys_bits to fix lockdep

+487 -70
+2
.mailmap
··· 226 226 Douglas Gilbert <dougg@torque.net> 227 227 Drew Fustini <fustini@kernel.org> <drew@pdp7.com> 228 228 <duje@dujemihanovic.xyz> <duje.mihanovic@skole.hr> 229 + Easwar Hariharan <easwar.hariharan@linux.microsoft.com> <easwar.hariharan@intel.com> 230 + Easwar Hariharan <easwar.hariharan@linux.microsoft.com> <eahariha@linux.microsoft.com> 229 231 Ed L. Cashin <ecashin@coraid.com> 230 232 Elliot Berman <quic_eberman@quicinc.com> <eberman@codeaurora.org> 231 233 Enric Balletbo i Serra <eballetbo@kernel.org> <enric.balletbo@collabora.com>
+19
MAINTAINERS
··· 16058 16058 F: mm/migrate.c 16059 16059 F: mm/migrate_device.c 16060 16060 16061 + MEMORY MANAGEMENT - MGLRU (MULTI-GEN LRU) 16062 + M: Andrew Morton <akpm@linux-foundation.org> 16063 + M: Axel Rasmussen <axelrasmussen@google.com> 16064 + M: Yuanchu Xie <yuanchu@google.com> 16065 + R: Wei Xu <weixugc@google.com> 16066 + L: linux-mm@kvack.org 16067 + S: Maintained 16068 + W: http://www.linux-mm.org 16069 + T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm 16070 + F: Documentation/admin-guide/mm/multigen_lru.rst 16071 + F: Documentation/mm/multigen_lru.rst 16072 + F: include/linux/mm_inline.h 16073 + F: include/linux/mmzone.h 16074 + F: mm/swap.c 16075 + F: mm/vmscan.c 16076 + F: mm/workingset.c 16077 + 16061 16078 MEMORY MANAGEMENT - MISC 16062 16079 M: Andrew Morton <akpm@linux-foundation.org> 16063 16080 M: David Hildenbrand <david@redhat.com> ··· 16265 16248 W: http://www.linux-mm.org 16266 16249 T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm 16267 16250 F: rust/helpers/mm.c 16251 + F: rust/helpers/page.c 16268 16252 F: rust/kernel/mm.rs 16269 16253 F: rust/kernel/mm/ 16254 + F: rust/kernel/page.rs 16270 16255 16271 16256 MEMORY MAPPING 16272 16257 M: Andrew Morton <akpm@linux-foundation.org>
+7 -7
fs/squashfs/super.c
··· 187 187 unsigned short flags; 188 188 unsigned int fragments; 189 189 u64 lookup_table_start, xattr_id_table_start, next_table; 190 - int err; 190 + int err, devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE); 191 191 192 192 TRACE("Entered squashfs_fill_superblock\n"); 193 + 194 + if (!devblksize) { 195 + errorf(fc, "squashfs: unable to set blocksize\n"); 196 + return -EINVAL; 197 + } 193 198 194 199 sb->s_fs_info = kzalloc(sizeof(*msblk), GFP_KERNEL); 195 200 if (sb->s_fs_info == NULL) { ··· 206 201 207 202 msblk->panic_on_errors = (opts->errors == Opt_errors_panic); 208 203 209 - msblk->devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE); 210 - if (!msblk->devblksize) { 211 - errorf(fc, "squashfs: unable to set blocksize\n"); 212 - return -EINVAL; 213 - } 214 - 204 + msblk->devblksize = devblksize; 215 205 msblk->devblksize_log2 = ffz(~msblk->devblksize); 216 206 217 207 mutex_init(&msblk->meta_index_mutex);
+11 -9
include/linux/iov_iter.h
··· 160 160 161 161 do { 162 162 struct folio *folio = folioq_folio(folioq, slot); 163 - size_t part, remain, consumed; 163 + size_t part, remain = 0, consumed; 164 164 size_t fsize; 165 165 void *base; 166 166 ··· 168 168 break; 169 169 170 170 fsize = folioq_folio_size(folioq, slot); 171 - base = kmap_local_folio(folio, skip); 172 - part = umin(len, PAGE_SIZE - skip % PAGE_SIZE); 173 - remain = step(base, progress, part, priv, priv2); 174 - kunmap_local(base); 175 - consumed = part - remain; 176 - len -= consumed; 177 - progress += consumed; 178 - skip += consumed; 171 + if (skip < fsize) { 172 + base = kmap_local_folio(folio, skip); 173 + part = umin(len, PAGE_SIZE - skip % PAGE_SIZE); 174 + remain = step(base, progress, part, priv, priv2); 175 + kunmap_local(base); 176 + consumed = part - remain; 177 + len -= consumed; 178 + progress += consumed; 179 + skip += consumed; 180 + } 179 181 if (skip >= fsize) { 180 182 skip = 0; 181 183 slot++;
+5
include/linux/migrate.h
··· 79 79 void folio_migrate_flags(struct folio *newfolio, struct folio *folio); 80 80 int folio_migrate_mapping(struct address_space *mapping, 81 81 struct folio *newfolio, struct folio *folio, int extra_count); 82 + int set_movable_ops(const struct movable_operations *ops, enum pagetype type); 82 83 83 84 #else 84 85 ··· 98 97 99 98 static inline int migrate_huge_page_move_mapping(struct address_space *mapping, 100 99 struct folio *dst, struct folio *src) 100 + { 101 + return -ENOSYS; 102 + } 103 + static inline int set_movable_ops(const struct movable_operations *ops, enum pagetype type) 101 104 { 102 105 return -ENOSYS; 103 106 }
+1
kernel/Kconfig.kexec
··· 97 97 config KEXEC_HANDOVER 98 98 bool "kexec handover" 99 99 depends on ARCH_SUPPORTS_KEXEC_HANDOVER && ARCH_SUPPORTS_KEXEC_FILE 100 + depends on !DEFERRED_STRUCT_PAGE_INIT 100 101 select MEMBLOCK_KHO_SCRATCH 101 102 select KEXEC_FILE 102 103 select DEBUG_FS
+25 -4
kernel/kexec_handover.c
··· 144 144 unsigned int order) 145 145 { 146 146 struct kho_mem_phys_bits *bits; 147 - struct kho_mem_phys *physxa; 147 + struct kho_mem_phys *physxa, *new_physxa; 148 148 const unsigned long pfn_high = pfn >> order; 149 149 150 150 might_sleep(); 151 151 152 - physxa = xa_load_or_alloc(&track->orders, order, sizeof(*physxa)); 153 - if (IS_ERR(physxa)) 154 - return PTR_ERR(physxa); 152 + physxa = xa_load(&track->orders, order); 153 + if (!physxa) { 154 + int err; 155 + 156 + new_physxa = kzalloc(sizeof(*physxa), GFP_KERNEL); 157 + if (!new_physxa) 158 + return -ENOMEM; 159 + 160 + xa_init(&new_physxa->phys_bits); 161 + physxa = xa_cmpxchg(&track->orders, order, NULL, new_physxa, 162 + GFP_KERNEL); 163 + 164 + err = xa_err(physxa); 165 + if (err || physxa) { 166 + xa_destroy(&new_physxa->phys_bits); 167 + kfree(new_physxa); 168 + 169 + if (err) 170 + return err; 171 + } else { 172 + physxa = new_physxa; 173 + } 174 + } 155 175 156 176 bits = xa_load_or_alloc(&physxa->phys_bits, pfn_high / PRESERVE_BITS, 157 177 sizeof(*bits)); ··· 564 544 err_free_scratch_desc: 565 545 memblock_free(kho_scratch, kho_scratch_cnt * sizeof(*kho_scratch)); 566 546 err_disable_kho: 547 + pr_warn("Failed to reserve scratch area, disabling kexec handover\n"); 567 548 kho_enable = false; 568 549 } 569 550
+6
mm/balloon_compaction.c
··· 254 254 .putback_page = balloon_page_putback, 255 255 }; 256 256 257 + static int __init balloon_init(void) 258 + { 259 + return set_movable_ops(&balloon_mops, PGTY_offline); 260 + } 261 + core_initcall(balloon_init); 262 + 257 263 #endif /* CONFIG_BALLOON_COMPACTION */
+14 -1
mm/damon/core.c
··· 845 845 return NULL; 846 846 } 847 847 848 + static struct damos_filter *damos_nth_ops_filter(int n, struct damos *s) 849 + { 850 + struct damos_filter *filter; 851 + int i = 0; 852 + 853 + damos_for_each_ops_filter(filter, s) { 854 + if (i++ == n) 855 + return filter; 856 + } 857 + return NULL; 858 + } 859 + 848 860 static void damos_commit_filter_arg( 849 861 struct damos_filter *dst, struct damos_filter *src) 850 862 { ··· 883 871 { 884 872 dst->type = src->type; 885 873 dst->matching = src->matching; 874 + dst->allow = src->allow; 886 875 damos_commit_filter_arg(dst, src); 887 876 } 888 877 ··· 921 908 int i = 0, j = 0; 922 909 923 910 damos_for_each_ops_filter_safe(dst_filter, next, dst) { 924 - src_filter = damos_nth_filter(i++, src); 911 + src_filter = damos_nth_ops_filter(i++, src); 925 912 if (src_filter) 926 913 damos_commit_filter(dst_filter, src_filter); 927 914 else
+1 -1
mm/damon/sysfs-schemes.c
··· 2158 2158 { 2159 2159 damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern); 2160 2160 kobject_put(&scheme->access_pattern->kobj); 2161 - kobject_put(&scheme->dests->kobj); 2162 2161 damos_sysfs_dests_rm_dirs(scheme->dests); 2162 + kobject_put(&scheme->dests->kobj); 2163 2163 damon_sysfs_quotas_rm_dirs(scheme->quotas); 2164 2164 kobject_put(&scheme->quotas->kobj); 2165 2165 kobject_put(&scheme->watermarks->kobj);
+7 -2
mm/debug_vm_pgtable.c
··· 990 990 991 991 /* Free page table entries */ 992 992 if (args->start_ptep) { 993 + pmd_clear(args->pmdp); 993 994 pte_free(args->mm, args->start_ptep); 994 995 mm_dec_nr_ptes(args->mm); 995 996 } 996 997 997 998 if (args->start_pmdp) { 999 + pud_clear(args->pudp); 998 1000 pmd_free(args->mm, args->start_pmdp); 999 1001 mm_dec_nr_pmds(args->mm); 1000 1002 } 1001 1003 1002 1004 if (args->start_pudp) { 1005 + p4d_clear(args->p4dp); 1003 1006 pud_free(args->mm, args->start_pudp); 1004 1007 mm_dec_nr_puds(args->mm); 1005 1008 } 1006 1009 1007 - if (args->start_p4dp) 1010 + if (args->start_p4dp) { 1011 + pgd_clear(args->pgdp); 1008 1012 p4d_free(args->mm, args->start_p4dp); 1013 + } 1009 1014 1010 1015 /* Free vma and mm struct */ 1011 1016 if (args->vma) 1012 1017 vm_area_free(args->vma); 1013 1018 1014 1019 if (args->mm) 1015 - mmdrop(args->mm); 1020 + mmput(args->mm); 1016 1021 } 1017 1022 1018 1023 static struct page * __init
+8
mm/memory-failure.c
··· 853 853 #define hwpoison_hugetlb_range NULL 854 854 #endif 855 855 856 + static int hwpoison_test_walk(unsigned long start, unsigned long end, 857 + struct mm_walk *walk) 858 + { 859 + /* We also want to consider pages mapped into VM_PFNMAP. */ 860 + return 0; 861 + } 862 + 856 863 static const struct mm_walk_ops hwpoison_walk_ops = { 857 864 .pmd_entry = hwpoison_pte_range, 858 865 .hugetlb_entry = hwpoison_hugetlb_range, 866 + .test_walk = hwpoison_test_walk, 859 867 .walk_lock = PGWALK_RDLOCK, 860 868 }; 861 869
+30 -8
mm/migrate.c
··· 43 43 #include <linux/sched/sysctl.h> 44 44 #include <linux/memory-tiers.h> 45 45 #include <linux/pagewalk.h> 46 - #include <linux/balloon_compaction.h> 47 - #include <linux/zsmalloc.h> 48 46 49 47 #include <asm/tlbflush.h> 50 48 ··· 50 52 51 53 #include "internal.h" 52 54 #include "swap.h" 55 + 56 + static const struct movable_operations *offline_movable_ops; 57 + static const struct movable_operations *zsmalloc_movable_ops; 58 + 59 + int set_movable_ops(const struct movable_operations *ops, enum pagetype type) 60 + { 61 + /* 62 + * We only allow for selected types and don't handle concurrent 63 + * registration attempts yet. 64 + */ 65 + switch (type) { 66 + case PGTY_offline: 67 + if (offline_movable_ops && ops) 68 + return -EBUSY; 69 + offline_movable_ops = ops; 70 + break; 71 + case PGTY_zsmalloc: 72 + if (zsmalloc_movable_ops && ops) 73 + return -EBUSY; 74 + zsmalloc_movable_ops = ops; 75 + break; 76 + default: 77 + return -EINVAL; 78 + } 79 + return 0; 80 + } 81 + EXPORT_SYMBOL_GPL(set_movable_ops); 53 82 54 83 static const struct movable_operations *page_movable_ops(struct page *page) 55 84 { ··· 87 62 * it as movable, the page type must be sticky until the page gets freed 88 63 * back to the buddy. 89 64 */ 90 - #ifdef CONFIG_BALLOON_COMPACTION 91 65 if (PageOffline(page)) 92 66 /* Only balloon compaction sets PageOffline pages movable. */ 93 - return &balloon_mops; 94 - #endif /* CONFIG_BALLOON_COMPACTION */ 95 - #if defined(CONFIG_ZSMALLOC) && defined(CONFIG_COMPACTION) 67 + return offline_movable_ops; 96 68 if (PageZsmalloc(page)) 97 - return &zsmalloc_mops; 98 - #endif /* defined(CONFIG_ZSMALLOC) && defined(CONFIG_COMPACTION) */ 69 + return zsmalloc_movable_ops; 70 + 99 71 return NULL; 100 72 } 101 73
+47 -35
mm/mremap.c
··· 323 323 } 324 324 #endif 325 325 326 + static inline bool uffd_supports_page_table_move(struct pagetable_move_control *pmc) 327 + { 328 + /* 329 + * If we are moving a VMA that has uffd-wp registered but with 330 + * remap events disabled (new VMA will not be registered with uffd), we 331 + * need to ensure that the uffd-wp state is cleared from all pgtables. 332 + * This means recursing into lower page tables in move_page_tables(). 333 + * 334 + * We might get called with VMAs reversed when recovering from a 335 + * failed page table move. In that case, the 336 + * "old"-but-actually-"originally new" VMA during recovery will not have 337 + * a uffd context. Recursing into lower page tables during the original 338 + * move but not during the recovery move will cause trouble, because we 339 + * run into already-existing page tables. So check both VMAs. 340 + */ 341 + return !vma_has_uffd_without_event_remap(pmc->old) && 342 + !vma_has_uffd_without_event_remap(pmc->new); 343 + } 344 + 326 345 #ifdef CONFIG_HAVE_MOVE_PMD 327 346 static bool move_normal_pmd(struct pagetable_move_control *pmc, 328 347 pmd_t *old_pmd, pmd_t *new_pmd) ··· 353 334 pmd_t pmd; 354 335 355 336 if (!arch_supports_page_table_move()) 337 + return false; 338 + if (!uffd_supports_page_table_move(pmc)) 356 339 return false; 357 340 /* 358 341 * The destination pmd shouldn't be established, free_pgtables() ··· 380 359 * this point, and verify that it really is empty. We'll see. 381 360 */ 382 361 if (WARN_ON_ONCE(!pmd_none(*new_pmd))) 383 - return false; 384 - 385 - /* If this pmd belongs to a uffd vma with remap events disabled, we need 386 - * to ensure that the uffd-wp state is cleared from all pgtables. This 387 - * means recursing into lower page tables in move_page_tables(), and we 388 - * can reuse the existing code if we simply treat the entry as "not 389 - * moved". 390 - */ 391 - if (vma_has_uffd_without_event_remap(vma)) 392 362 return false; 393 363 394 364 /* ··· 430 418 431 419 if (!arch_supports_page_table_move()) 432 420 return false; 421 + if (!uffd_supports_page_table_move(pmc)) 422 + return false; 433 423 /* 434 424 * The destination pud shouldn't be established, free_pgtables() 435 425 * should have released it. 436 426 */ 437 427 if (WARN_ON_ONCE(!pud_none(*new_pud))) 438 - return false; 439 - 440 - /* If this pud belongs to a uffd vma with remap events disabled, we need 441 - * to ensure that the uffd-wp state is cleared from all pgtables. This 442 - * means recursing into lower page tables in move_page_tables(), and we 443 - * can reuse the existing code if we simply treat the entry as "not 444 - * moved". 445 - */ 446 - if (vma_has_uffd_without_event_remap(vma)) 447 428 return false; 448 429 449 430 /* ··· 1625 1620 1626 1621 static bool vma_multi_allowed(struct vm_area_struct *vma) 1627 1622 { 1628 - struct file *file; 1623 + struct file *file = vma->vm_file; 1629 1624 1630 1625 /* 1631 1626 * We can't support moving multiple uffd VMAs as notify requires ··· 1638 1633 * Custom get unmapped area might result in MREMAP_FIXED not 1639 1634 * being obeyed. 1640 1635 */ 1641 - file = vma->vm_file; 1642 - if (file && !vma_is_shmem(vma) && !is_vm_hugetlb_page(vma)) { 1643 - const struct file_operations *fop = file->f_op; 1636 + if (!file || !file->f_op->get_unmapped_area) 1637 + return true; 1638 + /* Known good. */ 1639 + if (vma_is_shmem(vma)) 1640 + return true; 1641 + if (is_vm_hugetlb_page(vma)) 1642 + return true; 1643 + if (file->f_op->get_unmapped_area == thp_get_unmapped_area) 1644 + return true; 1644 1645 1645 - if (fop->get_unmapped_area) 1646 - return false; 1647 - } 1648 - 1649 - return true; 1646 + return false; 1650 1647 } 1651 1648 1652 1649 static int check_prep_vma(struct vma_remap_struct *vrm) ··· 1825 1818 unsigned long start = vrm->addr; 1826 1819 unsigned long end = vrm->addr + vrm->old_len; 1827 1820 unsigned long new_addr = vrm->new_addr; 1828 - bool allowed = true, seen_vma = false; 1829 1821 unsigned long target_addr = new_addr; 1830 1822 unsigned long res = -EFAULT; 1831 1823 unsigned long last_end; 1824 + bool seen_vma = false; 1825 + 1832 1826 VMA_ITERATOR(vmi, current->mm, start); 1833 1827 1834 1828 /* ··· 1842 1834 unsigned long addr = max(vma->vm_start, start); 1843 1835 unsigned long len = min(end, vma->vm_end) - addr; 1844 1836 unsigned long offset, res_vma; 1845 - 1846 - if (!allowed) 1847 - return -EFAULT; 1837 + bool multi_allowed; 1848 1838 1849 1839 /* No gap permitted at the start of the range. */ 1850 1840 if (!seen_vma && start < vma->vm_start) ··· 1871 1865 vrm->new_addr = target_addr + offset; 1872 1866 vrm->old_len = vrm->new_len = len; 1873 1867 1874 - allowed = vma_multi_allowed(vma); 1875 - if (seen_vma && !allowed) 1876 - return -EFAULT; 1868 + multi_allowed = vma_multi_allowed(vma); 1869 + if (!multi_allowed) { 1870 + /* This is not the first VMA, abort immediately. */ 1871 + if (seen_vma) 1872 + return -EFAULT; 1873 + /* This is the first, but there are more, abort. */ 1874 + if (vma->vm_end < end) 1875 + return -EFAULT; 1876 + } 1877 1877 1878 1878 res_vma = check_prep_vma(vrm); 1879 1879 if (!res_vma) ··· 1888 1876 return res_vma; 1889 1877 1890 1878 if (!seen_vma) { 1891 - VM_WARN_ON_ONCE(allowed && res_vma != new_addr); 1879 + VM_WARN_ON_ONCE(multi_allowed && res_vma != new_addr); 1892 1880 res = res_vma; 1893 1881 } 1894 1882
+10
mm/zsmalloc.c
··· 2246 2246 2247 2247 static int __init zs_init(void) 2248 2248 { 2249 + int rc __maybe_unused; 2250 + 2249 2251 #ifdef CONFIG_ZPOOL 2250 2252 zpool_register_driver(&zs_zpool_driver); 2253 + #endif 2254 + #ifdef CONFIG_COMPACTION 2255 + rc = set_movable_ops(&zsmalloc_mops, PGTY_zsmalloc); 2256 + if (rc) 2257 + return rc; 2251 2258 #endif 2252 2259 zs_stat_init(); 2253 2260 return 0; ··· 2264 2257 { 2265 2258 #ifdef CONFIG_ZPOOL 2266 2259 zpool_unregister_driver(&zs_zpool_driver); 2260 + #endif 2261 + #ifdef CONFIG_COMPACTION 2262 + set_movable_ops(NULL, PGTY_zsmalloc); 2267 2263 #endif 2268 2264 zs_stat_exit(); 2269 2265 }
+28
tools/include/linux/args.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef _LINUX_ARGS_H 4 + #define _LINUX_ARGS_H 5 + 6 + /* 7 + * How do these macros work? 8 + * 9 + * In __COUNT_ARGS() _0 to _12 are just placeholders from the start 10 + * in order to make sure _n is positioned over the correct number 11 + * from 12 to 0 (depending on X, which is a variadic argument list). 12 + * They serve no purpose other than occupying a position. Since each 13 + * macro parameter must have a distinct identifier, those identifiers 14 + * are as good as any. 15 + * 16 + * In COUNT_ARGS() we use actual integers, so __COUNT_ARGS() returns 17 + * that as _n. 18 + */ 19 + 20 + /* This counts to 15. Any more, it will return 16th argument. */ 21 + #define __COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _n, X...) _n 22 + #define COUNT_ARGS(X...) __COUNT_ARGS(, ##X, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) 23 + 24 + /* Concatenate two parameters, but allow them to be expanded beforehand. */ 25 + #define __CONCAT(a, b) a ## b 26 + #define CONCATENATE(a, b) __CONCAT(a, b) 27 + 28 + #endif /* _LINUX_ARGS_H */
+1
tools/testing/selftests/damon/Makefile
··· 4 4 TEST_GEN_FILES += access_memory access_memory_even 5 5 6 6 TEST_FILES = _damon_sysfs.py 7 + TEST_FILES += drgn_dump_damon_status.py 7 8 8 9 # functionality tests 9 10 TEST_PROGS += sysfs.sh
+261 -3
tools/testing/selftests/mm/mremap_test.c
··· 5 5 #define _GNU_SOURCE 6 6 7 7 #include <errno.h> 8 + #include <fcntl.h> 9 + #include <linux/userfaultfd.h> 8 10 #include <stdlib.h> 9 11 #include <stdio.h> 10 12 #include <string.h> 13 + #include <sys/ioctl.h> 11 14 #include <sys/mman.h> 15 + #include <syscall.h> 12 16 #include <time.h> 13 17 #include <stdbool.h> 14 18 ··· 172 168 173 169 if (first_val <= start && second_val >= end) { 174 170 success = true; 171 + fflush(maps_fp); 175 172 break; 176 173 } 177 174 } 178 175 179 176 return success; 177 + } 178 + 179 + /* Check if [ptr, ptr + size) mapped in /proc/self/maps. */ 180 + static bool is_ptr_mapped(FILE *maps_fp, void *ptr, unsigned long size) 181 + { 182 + unsigned long start = (unsigned long)ptr; 183 + unsigned long end = start + size; 184 + 185 + return is_range_mapped(maps_fp, start, end); 180 186 } 181 187 182 188 /* ··· 747 733 dont_unmap ? " [dontunnmap]" : ""); 748 734 } 749 735 736 + #ifdef __NR_userfaultfd 737 + static void mremap_move_multi_invalid_vmas(FILE *maps_fp, 738 + unsigned long page_size) 739 + { 740 + char *test_name = "mremap move multiple invalid vmas"; 741 + const size_t size = 10 * page_size; 742 + bool success = true; 743 + char *ptr, *tgt_ptr; 744 + int uffd, err, i; 745 + void *res; 746 + struct uffdio_api api = { 747 + .api = UFFD_API, 748 + .features = UFFD_EVENT_PAGEFAULT, 749 + }; 750 + 751 + uffd = syscall(__NR_userfaultfd, O_NONBLOCK); 752 + if (uffd == -1) { 753 + err = errno; 754 + perror("userfaultfd"); 755 + if (err == EPERM) { 756 + ksft_test_result_skip("%s - missing uffd", test_name); 757 + return; 758 + } 759 + success = false; 760 + goto out; 761 + } 762 + if (ioctl(uffd, UFFDIO_API, &api)) { 763 + perror("ioctl UFFDIO_API"); 764 + success = false; 765 + goto out_close_uffd; 766 + } 767 + 768 + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, 769 + MAP_PRIVATE | MAP_ANON, -1, 0); 770 + if (ptr == MAP_FAILED) { 771 + perror("mmap"); 772 + success = false; 773 + goto out_close_uffd; 774 + } 775 + 776 + tgt_ptr = mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); 777 + if (tgt_ptr == MAP_FAILED) { 778 + perror("mmap"); 779 + success = false; 780 + goto out_close_uffd; 781 + } 782 + if (munmap(tgt_ptr, size)) { 783 + perror("munmap"); 784 + success = false; 785 + goto out_unmap; 786 + } 787 + 788 + /* 789 + * Unmap so we end up with: 790 + * 791 + * 0 2 4 6 8 10 offset in buffer 792 + * |*| |*| |*| |*| |*| 793 + * |*| |*| |*| |*| |*| 794 + * 795 + * Additionally, register each with UFFD. 796 + */ 797 + for (i = 0; i < 10; i += 2) { 798 + void *unmap_ptr = &ptr[(i + 1) * page_size]; 799 + unsigned long start = (unsigned long)&ptr[i * page_size]; 800 + struct uffdio_register reg = { 801 + .range = { 802 + .start = start, 803 + .len = page_size, 804 + }, 805 + .mode = UFFDIO_REGISTER_MODE_MISSING, 806 + }; 807 + 808 + if (ioctl(uffd, UFFDIO_REGISTER, &reg) == -1) { 809 + perror("ioctl UFFDIO_REGISTER"); 810 + success = false; 811 + goto out_unmap; 812 + } 813 + if (munmap(unmap_ptr, page_size)) { 814 + perror("munmap"); 815 + success = false; 816 + goto out_unmap; 817 + } 818 + } 819 + 820 + /* 821 + * Now try to move the entire range which is invalid for multi VMA move. 822 + * 823 + * This will fail, and no VMA should be moved, as we check this ahead of 824 + * time. 825 + */ 826 + res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr); 827 + err = errno; 828 + if (res != MAP_FAILED) { 829 + fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n"); 830 + success = false; 831 + goto out_unmap; 832 + } 833 + if (err != EFAULT) { 834 + errno = err; 835 + perror("mrmeap() unexpected error"); 836 + success = false; 837 + goto out_unmap; 838 + } 839 + if (is_ptr_mapped(maps_fp, tgt_ptr, page_size)) { 840 + fprintf(stderr, 841 + "Invalid uffd-armed VMA at start of multi range moved\n"); 842 + success = false; 843 + goto out_unmap; 844 + } 845 + 846 + /* 847 + * Now try to move a single VMA, this should succeed as not multi VMA 848 + * move. 849 + */ 850 + res = mremap(ptr, page_size, page_size, 851 + MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr); 852 + if (res == MAP_FAILED) { 853 + perror("mremap single invalid-multi VMA"); 854 + success = false; 855 + goto out_unmap; 856 + } 857 + 858 + /* 859 + * Unmap the VMA, and remap a non-uffd registered (therefore, multi VMA 860 + * move valid) VMA at the start of ptr range. 861 + */ 862 + if (munmap(tgt_ptr, page_size)) { 863 + perror("munmap"); 864 + success = false; 865 + goto out_unmap; 866 + } 867 + res = mmap(ptr, page_size, PROT_READ | PROT_WRITE, 868 + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); 869 + if (res == MAP_FAILED) { 870 + perror("mmap"); 871 + success = false; 872 + goto out_unmap; 873 + } 874 + 875 + /* 876 + * Now try to move the entire range, we should succeed in moving the 877 + * first VMA, but no others, and report a failure. 878 + */ 879 + res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr); 880 + err = errno; 881 + if (res != MAP_FAILED) { 882 + fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n"); 883 + success = false; 884 + goto out_unmap; 885 + } 886 + if (err != EFAULT) { 887 + errno = err; 888 + perror("mrmeap() unexpected error"); 889 + success = false; 890 + goto out_unmap; 891 + } 892 + if (!is_ptr_mapped(maps_fp, tgt_ptr, page_size)) { 893 + fprintf(stderr, "Valid VMA not moved\n"); 894 + success = false; 895 + goto out_unmap; 896 + } 897 + 898 + /* 899 + * Unmap the VMA, and map valid VMA at start of ptr range, and replace 900 + * all existing multi-move invalid VMAs, except the last, with valid 901 + * multi-move VMAs. 902 + */ 903 + if (munmap(tgt_ptr, page_size)) { 904 + perror("munmap"); 905 + success = false; 906 + goto out_unmap; 907 + } 908 + if (munmap(ptr, size - 2 * page_size)) { 909 + perror("munmap"); 910 + success = false; 911 + goto out_unmap; 912 + } 913 + for (i = 0; i < 8; i += 2) { 914 + res = mmap(&ptr[i * page_size], page_size, 915 + PROT_READ | PROT_WRITE, 916 + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); 917 + if (res == MAP_FAILED) { 918 + perror("mmap"); 919 + success = false; 920 + goto out_unmap; 921 + } 922 + } 923 + 924 + /* 925 + * Now try to move the entire range, we should succeed in moving all but 926 + * the last VMA, and report a failure. 927 + */ 928 + res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr); 929 + err = errno; 930 + if (res != MAP_FAILED) { 931 + fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n"); 932 + success = false; 933 + goto out_unmap; 934 + } 935 + if (err != EFAULT) { 936 + errno = err; 937 + perror("mrmeap() unexpected error"); 938 + success = false; 939 + goto out_unmap; 940 + } 941 + 942 + for (i = 0; i < 10; i += 2) { 943 + bool is_mapped = is_ptr_mapped(maps_fp, 944 + &tgt_ptr[i * page_size], page_size); 945 + 946 + if (i < 8 && !is_mapped) { 947 + fprintf(stderr, "Valid VMA not moved at %d\n", i); 948 + success = false; 949 + goto out_unmap; 950 + } else if (i == 8 && is_mapped) { 951 + fprintf(stderr, "Invalid VMA moved at %d\n", i); 952 + success = false; 953 + goto out_unmap; 954 + } 955 + } 956 + 957 + out_unmap: 958 + if (munmap(tgt_ptr, size)) 959 + perror("munmap tgt"); 960 + if (munmap(ptr, size)) 961 + perror("munmap src"); 962 + out_close_uffd: 963 + close(uffd); 964 + out: 965 + if (success) 966 + ksft_test_result_pass("%s\n", test_name); 967 + else 968 + ksft_test_result_fail("%s\n", test_name); 969 + } 970 + #else 971 + static void mremap_move_multi_invalid_vmas(FILE *maps_fp, unsigned long page_size) 972 + { 973 + char *test_name = "mremap move multiple invalid vmas"; 974 + 975 + ksft_test_result_skip("%s - missing uffd", test_name); 976 + } 977 + #endif /* __NR_userfaultfd */ 978 + 750 979 /* Returns the time taken for the remap on success else returns -1. */ 751 980 static long long remap_region(struct config c, unsigned int threshold_mb, 752 981 char *rand_addr) ··· 1331 1074 char *rand_addr; 1332 1075 size_t rand_size; 1333 1076 int num_expand_tests = 2; 1334 - int num_misc_tests = 8; 1077 + int num_misc_tests = 9; 1335 1078 struct test test_cases[MAX_TEST] = {}; 1336 1079 struct test perf_test_cases[MAX_PERF_TEST]; 1337 1080 int page_size; ··· 1454 1197 mremap_expand_merge(maps_fp, page_size); 1455 1198 mremap_expand_merge_offset(maps_fp, page_size); 1456 1199 1457 - fclose(maps_fp); 1458 - 1459 1200 mremap_move_within_range(pattern_seed, rand_addr); 1460 1201 mremap_move_1mb_from_start(pattern_seed, rand_addr); 1461 1202 mremap_shrink_multiple_vmas(page_size, /* inplace= */true); ··· 1462 1207 mremap_move_multiple_vmas(pattern_seed, page_size, /* dontunmap= */ true); 1463 1208 mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ false); 1464 1209 mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ true); 1210 + mremap_move_multi_invalid_vmas(maps_fp, page_size); 1211 + 1212 + fclose(maps_fp); 1465 1213 1466 1214 if (run_perf_tests) { 1467 1215 ksft_print_msg("\n%s\n",
+4
tools/testing/shared/linux/idr.h
··· 1 + /* Avoid duplicate definitions due to system headers. */ 2 + #ifdef __CONCAT 3 + #undef __CONCAT 4 + #endif 1 5 #include "../../../../include/linux/idr.h"