Pull misc fixes from Andrew Morton: "16 hotfixes. 9 are cc:stable, 12 are for MM. There's a patch series from Pratyush Yadav which fixes a few things in the new-in-6.19 LUO memfd code. Plus the usual shower of singletons - please see the changelogs for details" * tag 'mm-hotfixes-stable-2026-01-29-09-41' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: vmcoreinfo: make hwerr_data visible for debugging mm/zone_device: reinitialize large zone device private folios mm/mm_init: don't cond_resched() in deferred_init_memmap_chunk() if called from deferred_grow_zone() mm/kfence: randomize the freelist on initialization kho: kho_preserve_vmalloc(): don't return 0 when ENOMEM kho: init alloc tags when restoring pages from reserved memory mm: memfd_luo: restore and free memfd_luo_ser on failure mm: memfd_luo: use memfd_alloc_file() instead of shmem_file_setup() memfd: export alloc_file() flex_proportions: make fprop_new_period() hardirq safe mailmap: add entry for Viacheslav Bocharov mm/memory-failure: teach kill_accessing_process to accept hugetlb tail page pfn mm/memory-failure: fix missing ->mf_stats count in hugetlb poison mm, swap: restore swap_space attr aviod kernel panic mm/kasan: fix KASAN poisoning in vrealloc() mm/shmem, swap: fix race of truncate and swap entry split
Unified · Split
| @@ -851,6 +851,7 @@ Valentin Schneider <vschneid@redhat.com> <valentin.schneider@arm.com> · 850 unmodified lines | ||
| 851 | 851 | Veera Sundaram Sankaran <quic_veeras@quicinc.com> <veeras@codeaurora.org> |
| 852 | 852 | Veerabhadrarao Badiganti <quic_vbadigan@quicinc.com> <vbadigan@codeaurora.org> |
| 853 | 853 | Venkateswara Naralasetty <quic_vnaralas@quicinc.com> <vnaralas@codeaurora.org> |
| 854 | +Viacheslav Bocharov <v@baodeep.com> <adeep@lexina.in> | |
| 854 | 855 | Vikash Garodia <vikash.garodia@oss.qualcomm.com> <vgarodia@codeaurora.org> |
| 855 | 856 | Vikash Garodia <vikash.garodia@oss.qualcomm.com> <quic_vgarodia@quicinc.com> |
| 856 | 857 | Vincent Mailhol <mailhol@kernel.org> <mailhol.vincent@wanadoo.fr> |
| @@ -723,7 +723,7 @@ static struct page *kvmppc_uvmem_get_page(unsigned long gpa, struct kvm *kvm) · 722 unmodified lines | ||
| 723 | 723 | |
| 724 | 724 | dpage = pfn_to_page(uvmem_pfn); |
| 725 | 725 | dpage->zone_device_data = pvt; |
| 726 | − zone_device_page_init(dpage, 0); | |
| 726 | + zone_device_page_init(dpage, &kvmppc_uvmem_pgmap, 0); | |
| 727 | 727 | return dpage; |
| 728 | 728 | out_clear: |
| 729 | 729 | spin_lock(&kvmppc_uvmem_bitmap_lock); |
| @@ -217,7 +217,7 @@ svm_migrate_get_vram_page(struct svm_range *prange, unsigned long pfn) · 216 unmodified lines | ||
| 217 | 217 | page = pfn_to_page(pfn); |
| 218 | 218 | svm_range_bo_ref(prange->svm_bo); |
| 219 | 219 | page->zone_device_data = prange->svm_bo; |
| 220 | − zone_device_page_init(page, 0); | |
| 220 | + zone_device_page_init(page, page_pgmap(page), 0); | |
| 221 | 221 | } |
| 222 | 222 | |
| 223 | 223 | static void |
| @@ -197,7 +197,7 @@ static void drm_pagemap_get_devmem_page(struct page *page, · 196 unmodified lines | ||
| 197 | 197 | struct drm_pagemap_zdd *zdd) |
| 198 | 198 | { |
| 199 | 199 | page->zone_device_data = drm_pagemap_zdd_get(zdd); |
| 200 | − zone_device_page_init(page, 0); | |
| 200 | + zone_device_page_init(page, page_pgmap(page), 0); | |
| 201 | 201 | } |
| 202 | 202 | |
| 203 | 203 | /** |
| @@ -425,7 +425,7 @@ nouveau_dmem_page_alloc_locked(struct nouveau_drm *drm, bool is_large) · 424 unmodified lines | ||
| 425 | 425 | order = ilog2(DMEM_CHUNK_NPAGES); |
| 426 | 426 | } |
| 427 | 427 | |
| 428 | − zone_device_folio_init(folio, order); | |
| 428 | + zone_device_folio_init(folio, page_pgmap(folio_page(folio, 0)), order); | |
| 429 | 429 | return page; |
| 430 | 430 | } |
| 431 | 431 | |
| @@ -641,6 +641,17 @@ kasan_unpoison_vmap_areas(struct vm_struct **vms, int nr_vms, · 640 unmodified lines | ||
| 641 | 641 | __kasan_unpoison_vmap_areas(vms, nr_vms, flags); |
| 642 | 642 | } |
| 643 | 643 | |
| 644 | +void __kasan_vrealloc(const void *start, unsigned long old_size, | |
| 645 | + unsigned long new_size); | |
| 646 | + | |
| 647 | +static __always_inline void kasan_vrealloc(const void *start, | |
| 648 | + unsigned long old_size, | |
| 649 | + unsigned long new_size) | |
| 650 | +{ | |
| 651 | + if (kasan_enabled()) | |
| 652 | + __kasan_vrealloc(start, old_size, new_size); | |
| 653 | +} | |
| 654 | + | |
| 644 | 655 | #else /* CONFIG_KASAN_VMALLOC */ |
| 645 | 656 | |
| 646 | 657 | static inline void kasan_populate_early_vm_area_shadow(void *start, |
| @@ -670,6 +681,9 @@ kasan_unpoison_vmap_areas(struct vm_struct **vms, int nr_vms, · 23 unmodified lines | ||
| 670 | 681 | kasan_vmalloc_flags_t flags) |
| 671 | 682 | { } |
| 672 | 683 | |
| 684 | +static inline void kasan_vrealloc(const void *start, unsigned long old_size, | |
| 685 | + unsigned long new_size) { } | |
| 686 | + | |
| 673 | 687 | #endif /* CONFIG_KASAN_VMALLOC */ |
| 674 | 688 | |
| 675 | 689 | #if (defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)) && \ |
| @@ -17,6 +17,7 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx); · 16 unmodified lines | ||
| 17 | 17 | * to by vm_flags_ptr. |
| 18 | 18 | */ |
| 19 | 19 | int memfd_check_seals_mmap(struct file *file, vm_flags_t *vm_flags_ptr); |
| 20 | +struct file *memfd_alloc_file(const char *name, unsigned int flags); | |
| 20 | 21 | #else |
| 21 | 22 | static inline long memfd_fcntl(struct file *f, unsigned int c, unsigned int a) |
| 22 | 23 | { |
| @@ -31,6 +32,11 @@ static inline int memfd_check_seals_mmap(struct file *file, · 8 unmodified lines | ||
| 31 | 32 | { |
| 32 | 33 | return 0; |
| 33 | 34 | } |
| 35 | + | |
| 36 | +static inline struct file *memfd_alloc_file(const char *name, unsigned int flags) | |
| 37 | +{ | |
| 38 | + return ERR_PTR(-EINVAL); | |
| 39 | +} | |
| 34 | 40 | #endif |
| 35 | 41 | |
| 36 | 42 | #endif /* __LINUX_MEMFD_H */ |
| @@ -224,7 +224,8 @@ static inline bool is_fsdax_page(const struct page *page) · 223 unmodified lines | ||
| 224 | 224 | } |
| 225 | 225 | |
| 226 | 226 | #ifdef CONFIG_ZONE_DEVICE |
| 227 | −void zone_device_page_init(struct page *page, unsigned int order); | |
| 227 | +void zone_device_page_init(struct page *page, struct dev_pagemap *pgmap, | |
| 228 | + unsigned int order); | |
| 228 | 229 | void *memremap_pages(struct dev_pagemap *pgmap, int nid); |
| 229 | 230 | void memunmap_pages(struct dev_pagemap *pgmap); |
| 230 | 231 | void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap); |
| @@ -234,9 +235,11 @@ bool pgmap_pfn_valid(struct dev_pagemap *pgmap, unsigned long pfn); · 3 unmodified lines | ||
| 234 | 235 | |
| 235 | 236 | unsigned long memremap_compat_align(void); |
| 236 | 237 | |
| 237 | −static inline void zone_device_folio_init(struct folio *folio, unsigned int order) | |
| 238 | +static inline void zone_device_folio_init(struct folio *folio, | |
| 239 | + struct dev_pagemap *pgmap, | |
| 240 | + unsigned int order) | |
| 238 | 241 | { |
| 239 | − zone_device_page_init(&folio->page, order); | |
| 242 | + zone_device_page_init(&folio->page, pgmap, order); | |
| 240 | 243 | if (order) |
| 241 | 244 | folio_set_large_rmappable(folio); |
| 242 | 245 | } |
| @@ -255,6 +255,14 @@ static struct page *kho_restore_page(phys_addr_t phys, bool is_folio) · 254 unmodified lines | ||
| 255 | 255 | if (is_folio && info.order) |
| 256 | 256 | prep_compound_page(page, info.order); |
| 257 | 257 | |
| 258 | + /* Always mark headpage's codetag as empty to avoid accounting mismatch */ | |
| 259 | + clear_page_tag_ref(page); | |
| 260 | + if (!is_folio) { | |
| 261 | + /* Also do that for the non-compound tail pages */ | |
| 262 | + for (unsigned int i = 1; i < nr_pages; i++) | |
| 263 | + clear_page_tag_ref(page + i); | |
| 264 | + } | |
| 265 | + | |
| 258 | 266 | adjust_managed_page_count(page, nr_pages); |
| 259 | 267 | return page; |
| 260 | 268 | } |
| @@ -1006,8 +1014,10 @@ int kho_preserve_vmalloc(void *ptr, struct kho_vmalloc *preservation) · 745 unmodified lines | ||
| 1006 | 1014 | chunk->phys[idx++] = phys; |
| 1007 | 1015 | if (idx == ARRAY_SIZE(chunk->phys)) { |
| 1008 | 1016 | chunk = new_vmalloc_chunk(chunk); |
| 1009 | − if (!chunk) | |
| 1017 | + if (!chunk) { | |
| 1018 | + err = -ENOMEM; | |
| 1010 | 1019 | goto err_free; |
| 1020 | + } | |
| 1011 | 1021 | idx = 0; |
| 1012 | 1022 | } |
| 1013 | 1023 | } |
| @@ -36,7 +36,11 @@ struct hwerr_info { · 35 unmodified lines | ||
| 36 | 36 | time64_t timestamp; |
| 37 | 37 | }; |
| 38 | 38 | |
| 39 | −static struct hwerr_info hwerr_data[HWERR_RECOV_MAX]; | |
| 39 | +/* | |
| 40 | + * The hwerr_data[] array is declared with global scope so that it remains | |
| 41 | + * accessible to vmcoreinfo even when Link Time Optimization (LTO) is enabled. | |
| 42 | + */ | |
| 43 | +struct hwerr_info hwerr_data[HWERR_RECOV_MAX]; | |
| 40 | 44 | |
| 41 | 45 | Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type, |
| 42 | 46 | void *data, size_t data_len) |
| @@ -64,13 +64,14 @@ void fprop_global_destroy(struct fprop_global *p) · 63 unmodified lines | ||
| 64 | 64 | bool fprop_new_period(struct fprop_global *p, int periods) |
| 65 | 65 | { |
| 66 | 66 | s64 events = percpu_counter_sum(&p->events); |
| 67 | + unsigned long flags; | |
| 67 | 68 | |
| 68 | 69 | /* |
| 69 | 70 | * Don't do anything if there are no events. |
| 70 | 71 | */ |
| 71 | 72 | if (events <= 1) |
| 72 | 73 | return false; |
| 73 | − preempt_disable_nested(); | |
| 74 | + local_irq_save(flags); | |
| 74 | 75 | write_seqcount_begin(&p->sequence); |
| 75 | 76 | if (periods < 64) |
| 76 | 77 | events -= events >> periods; |
| @@ -78,7 +79,7 @@ bool fprop_new_period(struct fprop_global *p, int periods) · 1 unmodified line | ||
| 78 | 79 | percpu_counter_add(&p->events, -events); |
| 79 | 80 | p->period += periods; |
| 80 | 81 | write_seqcount_end(&p->sequence); |
| 81 | − preempt_enable_nested(); | |
| 82 | + local_irq_restore(flags); | |
| 82 | 83 | |
| 83 | 84 | return true; |
| 84 | 85 | } |
| @@ -662,7 +662,9 @@ static struct page *dmirror_devmem_alloc_page(struct dmirror *dmirror, · 661 unmodified lines | ||
| 662 | 662 | goto error; |
| 663 | 663 | } |
| 664 | 664 | |
| 665 | − zone_device_folio_init(page_folio(dpage), order); | |
| 665 | + zone_device_folio_init(page_folio(dpage), | |
| 666 | + page_pgmap(folio_page(page_folio(dpage), 0)), | |
| 667 | + order); | |
| 666 | 668 | dpage->zone_device_data = rpage; |
| 667 | 669 | return dpage; |
| 668 | 670 | |
| @@ -606,4 +606,25 @@ void __kasan_unpoison_vmap_areas(struct vm_struct **vms, int nr_vms, · 605 unmodified lines | ||
| 606 | 606 | __kasan_unpoison_vmalloc(addr, size, flags | KASAN_VMALLOC_KEEP_TAG); |
| 607 | 607 | } |
| 608 | 608 | } |
| 609 | + | |
| 610 | +void __kasan_vrealloc(const void *addr, unsigned long old_size, | |
| 611 | + unsigned long new_size) | |
| 612 | +{ | |
| 613 | + if (new_size < old_size) { | |
| 614 | + kasan_poison_last_granule(addr, new_size); | |
| 615 | + | |
| 616 | + new_size = round_up(new_size, KASAN_GRANULE_SIZE); | |
| 617 | + old_size = round_up(old_size, KASAN_GRANULE_SIZE); | |
| 618 | + if (new_size < old_size) | |
| 619 | + __kasan_poison_vmalloc(addr + new_size, | |
| 620 | + old_size - new_size); | |
| 621 | + } else if (new_size > old_size) { | |
| 622 | + old_size = round_down(old_size, KASAN_GRANULE_SIZE); | |
| 623 | + __kasan_unpoison_vmalloc(addr + old_size, | |
| 624 | + new_size - old_size, | |
| 625 | + KASAN_VMALLOC_PROT_NORMAL | | |
| 626 | + KASAN_VMALLOC_VM_ALLOC | | |
| 627 | + KASAN_VMALLOC_KEEP_TAG); | |
| 628 | + } | |
| 629 | +} | |
| 609 | 630 | #endif |
| @@ -596,7 +596,7 @@ static void rcu_guarded_free(struct rcu_head *h) · 595 unmodified lines | ||
| 596 | 596 | static unsigned long kfence_init_pool(void) |
| 597 | 597 | { |
| 598 | 598 | unsigned long addr, start_pfn; |
| 599 | − int i; | |
| 599 | + int i, rand; | |
| 600 | 600 | |
| 601 | 601 | if (!arch_kfence_init_pool()) |
| 602 | 602 | return (unsigned long)__kfence_pool; |
| @@ -647,13 +647,27 @@ static unsigned long kfence_init_pool(void) · 44 unmodified lines | ||
| 647 | 647 | INIT_LIST_HEAD(&meta->list); |
| 648 | 648 | raw_spin_lock_init(&meta->lock); |
| 649 | 649 | meta->state = KFENCE_OBJECT_UNUSED; |
| 650 | − meta->addr = addr; /* Initialize for validation in metadata_to_pageaddr(). */ | |
| 651 | − list_add_tail(&meta->list, &kfence_freelist); | |
| 650 | + /* Use addr to randomize the freelist. */ | |
| 651 | + meta->addr = i; | |
| 652 | 652 | |
| 653 | 653 | /* Protect the right redzone. */ |
| 654 | − if (unlikely(!kfence_protect(addr + PAGE_SIZE))) | |
| 654 | + if (unlikely(!kfence_protect(addr + 2 * i * PAGE_SIZE + PAGE_SIZE))) | |
| 655 | 655 | goto reset_slab; |
| 656 | + } | |
| 657 | + | |
| 658 | + for (i = CONFIG_KFENCE_NUM_OBJECTS; i > 0; i--) { | |
| 659 | + rand = get_random_u32_below(i); | |
| 660 | + swap(kfence_metadata_init[i - 1].addr, kfence_metadata_init[rand].addr); | |
| 661 | + } | |
| 656 | 662 | |
| 663 | + for (i = 0; i < CONFIG_KFENCE_NUM_OBJECTS; i++) { | |
| 664 | + struct kfence_metadata *meta_1 = &kfence_metadata_init[i]; | |
| 665 | + struct kfence_metadata *meta_2 = &kfence_metadata_init[meta_1->addr]; | |
| 666 | + | |
| 667 | + list_add_tail(&meta_2->list, &kfence_freelist); | |
| 668 | + } | |
| 669 | + for (i = 0; i < CONFIG_KFENCE_NUM_OBJECTS; i++) { | |
| 670 | + kfence_metadata_init[i].addr = addr; | |
| 657 | 671 | addr += 2 * PAGE_SIZE; |
| 658 | 672 | } |
| 659 | 673 | |
| @@ -666,6 +680,7 @@ static unsigned long kfence_init_pool(void) · 6 unmodified lines | ||
| 666 | 680 | return 0; |
| 667 | 681 | |
| 668 | 682 | reset_slab: |
| 683 | + addr += 2 * i * PAGE_SIZE; | |
| 669 | 684 | for (i = 0; i < KFENCE_POOL_SIZE / PAGE_SIZE; i++) { |
| 670 | 685 | struct page *page; |
| 671 | 686 | |
| @@ -456,7 +456,7 @@ err_name: · 455 unmodified lines | ||
| 456 | 456 | return ERR_PTR(error); |
| 457 | 457 | } |
| 458 | 458 | |
| 459 | −static struct file *alloc_file(const char *name, unsigned int flags) | |
| 459 | +struct file *memfd_alloc_file(const char *name, unsigned int flags) | |
| 460 | 460 | { |
| 461 | 461 | unsigned int *file_seals; |
| 462 | 462 | struct file *file; |
| @@ -520,5 +520,5 @@ SYSCALL_DEFINE2(memfd_create, · 57 unmodified lines | ||
| 520 | 520 | return PTR_ERR(name); |
| 521 | 521 | |
| 522 | 522 | fd_flags = (flags & MFD_CLOEXEC) ? O_CLOEXEC : 0; |
| 523 | − return FD_ADD(fd_flags, alloc_file(name, flags)); | |
| 523 | + return FD_ADD(fd_flags, memfd_alloc_file(name, flags)); | |
| 524 | 524 | } |
| @@ -78,6 +78,7 @@ · 77 unmodified lines | ||
| 78 | 78 | #include <linux/liveupdate.h> |
| 79 | 79 | #include <linux/shmem_fs.h> |
| 80 | 80 | #include <linux/vmalloc.h> |
| 81 | +#include <linux/memfd.h> | |
| 81 | 82 | #include "internal.h" |
| 82 | 83 | |
| 83 | 84 | static int memfd_luo_preserve_folios(struct file *file, |
| @@ -443,11 +444,11 @@ static int memfd_luo_retrieve(struct liveupdate_file_op_args *args) · 359 unmodified lines | ||
| 443 | 444 | if (!ser) |
| 444 | 445 | return -EINVAL; |
| 445 | 446 | |
| 446 | − file = shmem_file_setup("", 0, VM_NORESERVE); | |
| 447 | − | |
| 447 | + file = memfd_alloc_file("", 0); | |
| 448 | 448 | if (IS_ERR(file)) { |
| 449 | 449 | pr_err("failed to setup file: %pe\n", file); |
| 450 | − return PTR_ERR(file); | |
| 450 | + err = PTR_ERR(file); | |
| 451 | + goto free_ser; | |
| 451 | 452 | } |
| 452 | 453 | |
| 453 | 454 | vfs_setpos(file, ser->pos, MAX_LFS_FILESIZE); |
| @@ -473,7 +474,8 @@ static int memfd_luo_retrieve(struct liveupdate_file_op_args *args) · 19 unmodified lines | ||
| 473 | 474 | |
| 474 | 475 | put_file: |
| 475 | 476 | fput(file); |
| 476 | − | |
| 477 | +free_ser: | |
| 478 | + kho_restore_free(ser); | |
| 477 | 479 | return err; |
| 478 | 480 | } |
| 479 | 481 | |
| @@ -692,6 +692,8 @@ static int check_hwpoisoned_entry(pte_t pte, unsigned long addr, short shift, · 691 unmodified lines | ||
| 692 | 692 | unsigned long poisoned_pfn, struct to_kill *tk) |
| 693 | 693 | { |
| 694 | 694 | unsigned long pfn = 0; |
| 695 | + unsigned long hwpoison_vaddr; | |
| 696 | + unsigned long mask; | |
| 695 | 697 | |
| 696 | 698 | if (pte_present(pte)) { |
| 697 | 699 | pfn = pte_pfn(pte); |
| @@ -702,10 +704,12 @@ static int check_hwpoisoned_entry(pte_t pte, unsigned long addr, short shift, · 4 unmodified lines | ||
| 702 | 704 | pfn = softleaf_to_pfn(entry); |
| 703 | 705 | } |
| 704 | 706 | |
| 705 | − if (!pfn || pfn != poisoned_pfn) | |
| 707 | + mask = ~((1UL << (shift - PAGE_SHIFT)) - 1); | |
| 708 | + if (!pfn || pfn != (poisoned_pfn & mask)) | |
| 706 | 709 | return 0; |
| 707 | 710 | |
| 708 | − set_to_kill(tk, addr, shift); | |
| 711 | + hwpoison_vaddr = addr + ((poisoned_pfn - pfn) << PAGE_SHIFT); | |
| 712 | + set_to_kill(tk, hwpoison_vaddr, shift); | |
| 709 | 713 | return 1; |
| 710 | 714 | } |
| 711 | 715 | |
| @@ -1883,12 +1887,22 @@ static unsigned long __folio_free_raw_hwp(struct folio *folio, bool move_flag) · 1171 unmodified lines | ||
| 1883 | 1887 | return count; |
| 1884 | 1888 | } |
| 1885 | 1889 | |
| 1886 | −static int folio_set_hugetlb_hwpoison(struct folio *folio, struct page *page) | |
| 1890 | +#define MF_HUGETLB_FREED 0 /* freed hugepage */ | |
| 1891 | +#define MF_HUGETLB_IN_USED 1 /* in-use hugepage */ | |
| 1892 | +#define MF_HUGETLB_NON_HUGEPAGE 2 /* not a hugepage */ | |
| 1893 | +#define MF_HUGETLB_FOLIO_PRE_POISONED 3 /* folio already poisoned */ | |
| 1894 | +#define MF_HUGETLB_PAGE_PRE_POISONED 4 /* exact page already poisoned */ | |
| 1895 | +#define MF_HUGETLB_RETRY 5 /* hugepage is busy, retry */ | |
| 1896 | +/* | |
| 1897 | + * Set hugetlb folio as hwpoisoned, update folio private raw hwpoison list | |
| 1898 | + * to keep track of the poisoned pages. | |
| 1899 | + */ | |
| 1900 | +static int hugetlb_update_hwpoison(struct folio *folio, struct page *page) | |
| 1887 | 1901 | { |
| 1888 | 1902 | struct llist_head *head; |
| 1889 | 1903 | struct raw_hwp_page *raw_hwp; |
| 1890 | 1904 | struct raw_hwp_page *p; |
| 1891 | − int ret = folio_test_set_hwpoison(folio) ? -EHWPOISON : 0; | |
| 1905 | + int ret = folio_test_set_hwpoison(folio) ? MF_HUGETLB_FOLIO_PRE_POISONED : 0; | |
| 1892 | 1906 | |
| 1893 | 1907 | /* |
| 1894 | 1908 | * Once the hwpoison hugepage has lost reliable raw error info, |
| @@ -1896,20 +1910,17 @@ static int folio_set_hugetlb_hwpoison(struct folio *folio, struct page *page) · 1 unmodified line | ||
| 1896 | 1910 | * so skip to add additional raw error info. |
| 1897 | 1911 | */ |
| 1898 | 1912 | if (folio_test_hugetlb_raw_hwp_unreliable(folio)) |
| 1899 | − return -EHWPOISON; | |
| 1913 | + return MF_HUGETLB_FOLIO_PRE_POISONED; | |
| 1900 | 1914 | head = raw_hwp_list_head(folio); |
| 1901 | 1915 | llist_for_each_entry(p, head->first, node) { |
| 1902 | 1916 | if (p->page == page) |
| 1903 | − return -EHWPOISON; | |
| 1917 | + return MF_HUGETLB_PAGE_PRE_POISONED; | |
| 1904 | 1918 | } |
| 1905 | 1919 | |
| 1906 | 1920 | raw_hwp = kmalloc(sizeof(struct raw_hwp_page), GFP_ATOMIC); |
| 1907 | 1921 | if (raw_hwp) { |
| 1908 | 1922 | raw_hwp->page = page; |
| 1909 | 1923 | llist_add(&raw_hwp->node, head); |
| 1910 | − /* the first error event will be counted in action_result(). */ | |
| 1911 | − if (ret) | |
| 1912 | − num_poisoned_pages_inc(page_to_pfn(page)); | |
| 1913 | 1924 | } else { |
| 1914 | 1925 | /* |
| 1915 | 1926 | * Failed to save raw error info. We no longer trace all |
| @@ -1957,42 +1968,39 @@ void folio_clear_hugetlb_hwpoison(struct folio *folio) · 41 unmodified lines | ||
| 1957 | 1968 | |
| 1958 | 1969 | /* |
| 1959 | 1970 | * Called from hugetlb code with hugetlb_lock held. |
| 1960 | − * | |
| 1961 | − * Return values: | |
| 1962 | − * 0 - free hugepage | |
| 1963 | − * 1 - in-use hugepage | |
| 1964 | − * 2 - not a hugepage | |
| 1965 | − * -EBUSY - the hugepage is busy (try to retry) | |
| 1966 | − * -EHWPOISON - the hugepage is already hwpoisoned | |
| 1967 | 1971 | */ |
| 1968 | 1972 | int __get_huge_page_for_hwpoison(unsigned long pfn, int flags, |
| 1969 | 1973 | bool *migratable_cleared) |
| 1970 | 1974 | { |
| 1971 | 1975 | struct page *page = pfn_to_page(pfn); |
| 1972 | 1976 | struct folio *folio = page_folio(page); |
| 1973 | − int ret = 2; /* fallback to normal page handling */ | |
| 1974 | 1977 | bool count_increased = false; |
| 1978 | + int ret, rc; | |
| 1975 | 1979 | |
| 1976 | − if (!folio_test_hugetlb(folio)) | |
| 1980 | + if (!folio_test_hugetlb(folio)) { | |
| 1981 | + ret = MF_HUGETLB_NON_HUGEPAGE; | |
| 1977 | 1982 | goto out; |
| 1978 | − | |
| 1979 | − if (flags & MF_COUNT_INCREASED) { | |
| 1980 | − ret = 1; | |
| 1983 | + } else if (flags & MF_COUNT_INCREASED) { | |
| 1984 | + ret = MF_HUGETLB_IN_USED; | |
| 1981 | 1985 | count_increased = true; |
| 1982 | 1986 | } else if (folio_test_hugetlb_freed(folio)) { |
| 1983 | − ret = 0; | |
| 1987 | + ret = MF_HUGETLB_FREED; | |
| 1984 | 1988 | } else if (folio_test_hugetlb_migratable(folio)) { |
| 1985 | − ret = folio_try_get(folio); | |
| 1986 | − if (ret) | |
| 1989 | + if (folio_try_get(folio)) { | |
| 1990 | + ret = MF_HUGETLB_IN_USED; | |
| 1987 | 1991 | count_increased = true; |
| 1992 | + } else { | |
| 1993 | + ret = MF_HUGETLB_FREED; | |
| 1994 | + } | |
| 1988 | 1995 | } else { |
| 1989 | − ret = -EBUSY; | |
| 1996 | + ret = MF_HUGETLB_RETRY; | |
| 1990 | 1997 | if (!(flags & MF_NO_RETRY)) |
| 1991 | 1998 | goto out; |
| 1992 | 1999 | } |
| 1993 | 2000 | |
| 1994 | − if (folio_set_hugetlb_hwpoison(folio, page)) { | |
| 1995 | − ret = -EHWPOISON; | |
| 2001 | + rc = hugetlb_update_hwpoison(folio, page); | |
| 2002 | + if (rc >= MF_HUGETLB_FOLIO_PRE_POISONED) { | |
| 2003 | + ret = rc; | |
| 1996 | 2004 | goto out; |
| 1997 | 2005 | } |
| 1998 | 2006 | |
| @@ -2017,10 +2025,16 @@ out: · 18 unmodified lines | ||
| 2017 | 2025 | * with basic operations like hugepage allocation/free/demotion. |
| 2018 | 2026 | * So some of prechecks for hwpoison (pinning, and testing/setting |
| 2019 | 2027 | * PageHWPoison) should be done in single hugetlb_lock range. |
| 2028 | + * Returns: | |
| 2029 | + * 0 - not hugetlb, or recovered | |
| 2030 | + * -EBUSY - not recovered | |
| 2031 | + * -EOPNOTSUPP - hwpoison_filter'ed | |
| 2032 | + * -EHWPOISON - folio or exact page already poisoned | |
| 2033 | + * -EFAULT - kill_accessing_process finds current->mm null | |
| 2020 | 2034 | */ |
| 2021 | 2035 | static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb) |
| 2022 | 2036 | { |
| 2023 | − int res; | |
| 2037 | + int res, rv; | |
| 2024 | 2038 | struct page *p = pfn_to_page(pfn); |
| 2025 | 2039 | struct folio *folio; |
| 2026 | 2040 | unsigned long page_flags; |
| @@ -2029,22 +2043,29 @@ static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb · 2 unmodified lines | ||
| 2029 | 2043 | *hugetlb = 1; |
| 2030 | 2044 | retry: |
| 2031 | 2045 | res = get_huge_page_for_hwpoison(pfn, flags, &migratable_cleared); |
| 2032 | − if (res == 2) { /* fallback to normal page handling */ | |
| 2046 | + switch (res) { | |
| 2047 | + case MF_HUGETLB_NON_HUGEPAGE: /* fallback to normal page handling */ | |
| 2033 | 2048 | *hugetlb = 0; |
| 2034 | 2049 | return 0; |
| 2035 | − } else if (res == -EHWPOISON) { | |
| 2036 | − if (flags & MF_ACTION_REQUIRED) { | |
| 2037 | − folio = page_folio(p); | |
| 2038 | − res = kill_accessing_process(current, folio_pfn(folio), flags); | |
| 2039 | − } | |
| 2040 | − action_result(pfn, MF_MSG_ALREADY_POISONED, MF_FAILED); | |
| 2041 | − return res; | |
| 2042 | − } else if (res == -EBUSY) { | |
| 2050 | + case MF_HUGETLB_RETRY: | |
| 2043 | 2051 | if (!(flags & MF_NO_RETRY)) { |
| 2044 | 2052 | flags |= MF_NO_RETRY; |
| 2045 | 2053 | goto retry; |
| 2046 | 2054 | } |
| 2047 | 2055 | return action_result(pfn, MF_MSG_GET_HWPOISON, MF_IGNORED); |
| 2056 | + case MF_HUGETLB_FOLIO_PRE_POISONED: | |
| 2057 | + case MF_HUGETLB_PAGE_PRE_POISONED: | |
| 2058 | + rv = -EHWPOISON; | |
| 2059 | + if (flags & MF_ACTION_REQUIRED) | |
| 2060 | + rv = kill_accessing_process(current, pfn, flags); | |
| 2061 | + if (res == MF_HUGETLB_PAGE_PRE_POISONED) | |
| 2062 | + action_result(pfn, MF_MSG_ALREADY_POISONED, MF_FAILED); | |
| 2063 | + else | |
| 2064 | + action_result(pfn, MF_MSG_HUGE, MF_FAILED); | |
| 2065 | + return rv; | |
| 2066 | + default: | |
| 2067 | + WARN_ON((res != MF_HUGETLB_FREED) && (res != MF_HUGETLB_IN_USED)); | |
| 2068 | + break; | |
| 2048 | 2069 | } |
| 2049 | 2070 | |
| 2050 | 2071 | folio = page_folio(p); |
| @@ -2055,7 +2076,7 @@ retry: · 4 unmodified lines | ||
| 2055 | 2076 | if (migratable_cleared) |
| 2056 | 2077 | folio_set_hugetlb_migratable(folio); |
| 2057 | 2078 | folio_unlock(folio); |
| 2058 | − if (res == 1) | |
| 2079 | + if (res == MF_HUGETLB_IN_USED) | |
| 2059 | 2080 | folio_put(folio); |
| 2060 | 2081 | return -EOPNOTSUPP; |
| 2061 | 2082 | } |
| @@ -2064,7 +2085,7 @@ retry: · 2 unmodified lines | ||
| 2064 | 2085 | * Handling free hugepage. The possible race with hugepage allocation |
| 2065 | 2086 | * or demotion can be prevented by PageHWPoison flag. |
| 2066 | 2087 | */ |
| 2067 | − if (res == 0) { | |
| 2088 | + if (res == MF_HUGETLB_FREED) { | |
| 2068 | 2089 | folio_unlock(folio); |
| 2069 | 2090 | if (__page_handle_poison(p) > 0) { |
| 2070 | 2091 | page_ref_inc(p); |
| @@ -477,10 +477,43 @@ void free_zone_device_folio(struct folio *folio) · 476 unmodified lines | ||
| 477 | 477 | } |
| 478 | 478 | } |
| 479 | 479 | |
| 480 | −void zone_device_page_init(struct page *page, unsigned int order) | |
| 480 | +void zone_device_page_init(struct page *page, struct dev_pagemap *pgmap, | |
| 481 | + unsigned int order) | |
| 481 | 482 | { |
| 483 | + struct page *new_page = page; | |
| 484 | + unsigned int i; | |
| 485 | + | |
| 482 | 486 | VM_WARN_ON_ONCE(order > MAX_ORDER_NR_PAGES); |
| 483 | 487 | |
| 488 | + for (i = 0; i < (1UL << order); ++i, ++new_page) { | |
| 489 | + struct folio *new_folio = (struct folio *)new_page; | |
| 490 | + | |
| 491 | + /* | |
| 492 | + * new_page could have been part of previous higher order folio | |
| 493 | + * which encodes the order, in page + 1, in the flags bits. We | |
| 494 | + * blindly clear bits which could have set my order field here, | |
| 495 | + * including page head. | |
| 496 | + */ | |
| 497 | + new_page->flags.f &= ~0xffUL; /* Clear possible order, page head */ | |
| 498 | + | |
| 499 | +#ifdef NR_PAGES_IN_LARGE_FOLIO | |
| 500 | + /* | |
| 501 | + * This pointer math looks odd, but new_page could have been | |
| 502 | + * part of a previous higher order folio, which sets _nr_pages | |
| 503 | + * in page + 1 (new_page). Therefore, we use pointer casting to | |
| 504 | + * correctly locate the _nr_pages bits within new_page which | |
| 505 | + * could have modified by previous higher order folio. | |
| 506 | + */ | |
| 507 | + ((struct folio *)(new_page - 1))->_nr_pages = 0; | |
| 508 | +#endif | |
| 509 | + | |
| 510 | + new_folio->mapping = NULL; | |
| 511 | + new_folio->pgmap = pgmap; /* Also clear compound head */ | |
| 512 | + new_folio->share = 0; /* fsdax only, unused for device private */ | |
| 513 | + VM_WARN_ON_FOLIO(folio_ref_count(new_folio), new_folio); | |
| 514 | + VM_WARN_ON_FOLIO(!folio_is_zone_device(new_folio), new_folio); | |
| 515 | + } | |
| 516 | + | |
| 484 | 517 | /* |
| 485 | 518 | * Drivers shouldn't be allocating pages after calling |
| 486 | 519 | * memunmap_pages(). |
| @@ -2059,7 +2059,7 @@ static unsigned long __init deferred_init_pages(struct zone *zone, · 2058 unmodified lines | ||
| 2059 | 2059 | */ |
| 2060 | 2060 | static unsigned long __init |
| 2061 | 2061 | deferred_init_memmap_chunk(unsigned long start_pfn, unsigned long end_pfn, |
| 2062 | − struct zone *zone) | |
| 2062 | + struct zone *zone, bool can_resched) | |
| 2063 | 2063 | { |
| 2064 | 2064 | int nid = zone_to_nid(zone); |
| 2065 | 2065 | unsigned long nr_pages = 0; |
| @@ -2085,10 +2085,10 @@ deferred_init_memmap_chunk(unsigned long start_pfn, unsigned long end_pfn, · 19 unmodified lines | ||
| 2085 | 2085 | |
| 2086 | 2086 | spfn = chunk_end; |
| 2087 | 2087 | |
| 2088 | − if (irqs_disabled()) | |
| 2089 | − touch_nmi_watchdog(); | |
| 2090 | − else | |
| 2088 | + if (can_resched) | |
| 2091 | 2089 | cond_resched(); |
| 2090 | + else | |
| 2091 | + touch_nmi_watchdog(); | |
| 2092 | 2092 | } |
| 2093 | 2093 | } |
| 2094 | 2094 | |
| @@ -2101,7 +2101,7 @@ deferred_init_memmap_job(unsigned long start_pfn, unsigned long end_pfn, · 6 unmodified lines | ||
| 2101 | 2101 | { |
| 2102 | 2102 | struct zone *zone = arg; |
| 2103 | 2103 | |
| 2104 | − deferred_init_memmap_chunk(start_pfn, end_pfn, zone); | |
| 2104 | + deferred_init_memmap_chunk(start_pfn, end_pfn, zone, true); | |
| 2105 | 2105 | } |
| 2106 | 2106 | |
| 2107 | 2107 | static unsigned int __init |
| @@ -2216,7 +2216,7 @@ bool __init deferred_grow_zone(struct zone *zone, unsigned int order) · 108 unmodified lines | ||
| 2216 | 2216 | for (spfn = first_deferred_pfn, epfn = SECTION_ALIGN_UP(spfn + 1); |
| 2217 | 2217 | nr_pages < nr_pages_needed && spfn < zone_end_pfn(zone); |
| 2218 | 2218 | spfn = epfn, epfn += PAGES_PER_SECTION) { |
| 2219 | − nr_pages += deferred_init_memmap_chunk(spfn, epfn, zone); | |
| 2219 | + nr_pages += deferred_init_memmap_chunk(spfn, epfn, zone, false); | |
| 2220 | 2220 | } |
| 2221 | 2221 | |
| 2222 | 2222 | /* |
| @@ -962,17 +962,29 @@ static void shmem_delete_from_page_cache(struct folio *folio, void *radswap) · 961 unmodified lines | ||
| 962 | 962 | * being freed). |
| 963 | 963 | */ |
| 964 | 964 | static long shmem_free_swap(struct address_space *mapping, |
| 965 | − pgoff_t index, void *radswap) | |
| 965 | + pgoff_t index, pgoff_t end, void *radswap) | |
| 966 | 966 | { |
| 967 | − int order = xa_get_order(&mapping->i_pages, index); | |
| 968 | − void *old; | |
| 967 | + XA_STATE(xas, &mapping->i_pages, index); | |
| 968 | + unsigned int nr_pages = 0; | |
| 969 | + pgoff_t base; | |
| 970 | + void *entry; | |
| 969 | 971 | |
| 970 | − old = xa_cmpxchg_irq(&mapping->i_pages, index, radswap, NULL, 0); | |
| 971 | − if (old != radswap) | |
| 972 | − return 0; | |
| 973 | − free_swap_and_cache_nr(radix_to_swp_entry(radswap), 1 << order); | |
| 972 | + xas_lock_irq(&xas); | |
| 973 | + entry = xas_load(&xas); | |
| 974 | + if (entry == radswap) { | |
| 975 | + nr_pages = 1 << xas_get_order(&xas); | |
| 976 | + base = round_down(xas.xa_index, nr_pages); | |
| 977 | + if (base < index || base + nr_pages - 1 > end) | |
| 978 | + nr_pages = 0; | |
| 979 | + else | |
| 980 | + xas_store(&xas, NULL); | |
| 981 | + } | |
| 982 | + xas_unlock_irq(&xas); | |
| 983 | + | |
| 984 | + if (nr_pages) | |
| 985 | + free_swap_and_cache_nr(radix_to_swp_entry(radswap), nr_pages); | |
| 974 | 986 | |
| 975 | − return 1 << order; | |
| 987 | + return nr_pages; | |
| 976 | 988 | } |
| 977 | 989 | |
| 978 | 990 | /* |
| @@ -1124,8 +1136,8 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, uoff_t lend, · 145 unmodified lines | ||
| 1124 | 1136 | if (xa_is_value(folio)) { |
| 1125 | 1137 | if (unfalloc) |
| 1126 | 1138 | continue; |
| 1127 | − nr_swaps_freed += shmem_free_swap(mapping, | |
| 1128 | − indices[i], folio); | |
| 1139 | + nr_swaps_freed += shmem_free_swap(mapping, indices[i], | |
| 1140 | + end - 1, folio); | |
| 1129 | 1141 | continue; |
| 1130 | 1142 | } |
| 1131 | 1143 | |
| @@ -1191,12 +1203,23 @@ whole_folios: · 59 unmodified lines | ||
| 1191 | 1203 | folio = fbatch.folios[i]; |
| 1192 | 1204 | |
| 1193 | 1205 | if (xa_is_value(folio)) { |
| 1206 | + int order; | |
| 1194 | 1207 | long swaps_freed; |
| 1195 | 1208 | |
| 1196 | 1209 | if (unfalloc) |
| 1197 | 1210 | continue; |
| 1198 | − swaps_freed = shmem_free_swap(mapping, indices[i], folio); | |
| 1211 | + swaps_freed = shmem_free_swap(mapping, indices[i], | |
| 1212 | + end - 1, folio); | |
| 1199 | 1213 | if (!swaps_freed) { |
| 1214 | + /* | |
| 1215 | + * If found a large swap entry cross the end border, | |
| 1216 | + * skip it as the truncate_inode_partial_folio above | |
| 1217 | + * should have at least zerod its content once. | |
| 1218 | + */ | |
| 1219 | + order = shmem_confirm_swap(mapping, indices[i], | |
| 1220 | + radix_to_swp_entry(folio)); | |
| 1221 | + if (order > 0 && indices[i] + (1 << order) > end) | |
| 1222 | + continue; | |
| 1200 | 1223 | /* Swap was replaced by page: retry */ |
| 1201 | 1224 | index = indices[i]; |
| 1202 | 1225 | break; |
| @@ -198,7 +198,7 @@ int swap_writeout(struct folio *folio, struct swap_iocb **swap_plug); · 197 unmodified lines | ||
| 198 | 198 | void __swap_writepage(struct folio *folio, struct swap_iocb **swap_plug); |
| 199 | 199 | |
| 200 | 200 | /* linux/mm/swap_state.c */ |
| 201 | −extern struct address_space swap_space __ro_after_init; | |
| 201 | +extern struct address_space swap_space __read_mostly; | |
| 202 | 202 | static inline struct address_space *swap_address_space(swp_entry_t entry) |
| 203 | 203 | { |
| 204 | 204 | return &swap_space; |
| @@ -37,8 +37,7 @@ static const struct address_space_operations swap_aops = { · 36 unmodified lines | ||
| 37 | 37 | #endif |
| 38 | 38 | }; |
| 39 | 39 | |
| 40 | −/* Set swap_space as read only as swap cache is handled by swap table */ | |
| 41 | −struct address_space swap_space __ro_after_init = { | |
| 40 | +struct address_space swap_space __read_mostly = { | |
| 42 | 41 | .a_ops = &swap_aops, |
| 43 | 42 | }; |
| 44 | 43 | |
| @@ -4322,7 +4322,7 @@ void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align · 4321 unmodified lines | ||
| 4322 | 4322 | if (want_init_on_free() || want_init_on_alloc(flags)) |
| 4323 | 4323 | memset((void *)p + size, 0, old_size - size); |
| 4324 | 4324 | vm->requested_size = size; |
| 4325 | − kasan_poison_vmalloc(p + size, old_size - size); | |
| 4325 | + kasan_vrealloc(p, old_size, size); | |
| 4326 | 4326 | return (void *)p; |
| 4327 | 4327 | } |
| 4328 | 4328 | |
| @@ -4330,16 +4330,13 @@ void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align · 1 unmodified line | ||
| 4330 | 4330 | * We already have the bytes available in the allocation; use them. |
| 4331 | 4331 | */ |
| 4332 | 4332 | if (size <= alloced_size) { |
| 4333 | − kasan_unpoison_vmalloc(p + old_size, size - old_size, | |
| 4334 | − KASAN_VMALLOC_PROT_NORMAL | | |
| 4335 | − KASAN_VMALLOC_VM_ALLOC | | |
| 4336 | − KASAN_VMALLOC_KEEP_TAG); | |
| 4337 | 4333 | /* |
| 4338 | 4334 | * No need to zero memory here, as unused memory will have |
| 4339 | 4335 | * already been zeroed at initial allocation time or during |
| 4340 | 4336 | * realloc shrink time. |
| 4341 | 4337 | */ |
| 4342 | 4338 | vm->requested_size = size; |
| 4339 | + kasan_vrealloc(p, old_size, size); | |
| 4343 | 4340 | return (void *)p; |
| 4344 | 4341 | } |
| 4345 | 4342 | |