FAILED: patch "[PATCH] hugetlb: unshare some PMDs when splitting VMAs" failed to apply to 5.15-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Possible dependencies:
b30c14cd6102 ("hugetlb: unshare some PMDs when splitting VMAs")ecfbd733878d ("hugetlb: take hugetlb vma_lock when clearing vma_lock->vma pointer") 131a79b474e9 ("hugetlb: fix vma lock handling during split vma and range unmapping") 40549ba8f8e0 ("hugetlb: use new vma_lock for pmd sharing synchronization")378397ccb8e5 ("hugetlb: create hugetlb_unmap_file_folio to unmap single file folio") 8d9bfb260814 ("hugetlb: add vma based lock for pmd sharing")12710fd69634 ("hugetlb: rename vma_shareable() and refactor code")c86272287bc6 ("hugetlb: create remove_inode_single_folio to remove single file folio") 7e1813d48dd3 ("hugetlb: rename remove_huge_page to hugetlb_delete_from_page_cache") 3a47c54f09c4 ("hugetlbfs: revert use i_mmap_rwsem for more pmd sharing synchronization") 188a39725ad7 ("hugetlbfs: revert use i_mmap_rwsem to address page fault/truncate race") 5e6b1bf1b5c3 ("hugetlb: remove meaningless BUG_ON(huge_pte_none())")3a5497a2dae3 ("mm/hugetlb: fix missing call to restore_reserve_on_error()")6614a3c3164a ("Merge tag 'mm-stable-2022-08-03' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From b30c14cd61025eeea2f2e8569606cd167ba9ad2d Mon Sep 17 00:00:00 2001
From: James Houghton <[email protected]>
Date: Wed, 4 Jan 2023 23:19:10 +0000
Subject: [PATCH] hugetlb: unshare some PMDs when splitting VMAs
PMD sharing can only be done in PUD_SIZE-aligned pieces of VMAs; however, it is possible that HugeTLB VMAs are split without unsharing the PMDs first.
Without this fix, it is possible to hit the uffd-wp-related WARN_ON_ONCE in hugetlb_change_protection [1]. The key there is that hugetlb_unshare_all_pmds will not attempt to unshare PMDs in non-PUD_SIZE-aligned sections of the VMA.
It might seem ideal to unshare in hugetlb_vm_op_open, but we need to unshare in both the new and old VMAs, so unsharing in hugetlb_vm_op_split seems natural.
[1]: https://lore.kernel.org/linux-mm/CADrL8HVeOkj0QH5VZZbRzybNE8CG-tEGFshnA+bG9nMgcWtBSg@mail.gmail.com/
mm/hugetlb.c +35 -9
@@ -94,6 +94,8 @@ static int hugetlb_acct_memory(struct hstate *h, long delta);static void hugetlb_vma_lock_free (struct vm_area_struct *vma);static void hugetlb_vma_lock_alloc (struct vm_area_struct *vma);static void __hugetlb_vma_unlock_write_free (struct vm_area_struct *vma); +static void hugetlb_unshare_pmds (struct vm_area_struct *vma, +unsigned long start,unsigned long end);static inline bool subpool_is_free (struct hugepage_subpool *spool) {
@@ -4834,6 +4836,25 @@ static int hugetlb_vm_op_split(struct vm_area_struct *vma, unsigned long addr) {if (addr & ~(huge_page_mask (hstate_vma (vma))))return -EINVAL ; + +/* +* PMD sharing is only possible for PUD_SIZE-aligned address ranges +* in HugeTLB VMAs. If we will lose PUD_SIZE alignment due to this +* split, unshare PMDs in the PUD_SIZE interval surrounding addr now. +*/ +if (addr & ~PUD_MASK ) { +/* +* hugetlb_vm_op_split is called right before we attempt to +* split the VMA. We will need to unshare PMDs in the old and +* new VMAs, so let's unshare before we split. +*/ +unsigned long floor = addr &PUD_MASK ; +unsigned long ceil = floor +PUD_SIZE ; + +if (floor >= vma->vm_start && ceil <= vma->vm_end) +hugetlb_unshare_pmds (vma, floor, ceil); + } +return 0 ; }
@@ -7322,26 +7343,21 @@ void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio, int re } } -/* -* This function will unconditionally remove all the shared pmd pgtable entries -* within the specific vma for a hugetlbfs memory range. -*/ -void hugetlb_unshare_all_pmds (struct vm_area_struct *vma) +static void hugetlb_unshare_pmds (struct vm_area_struct *vma, +unsigned long start, +unsigned long end) {struct hstate *h =hstate_vma (vma);unsigned long sz =huge_page_size (h);struct mm_struct *mm = vma->vm_mm;struct mmu_notifier_range range; -unsigned long address, start, end; +unsigned long address;spinlock_t *ptl;pte_t *ptep;if (!(vma->vm_flags &VM_MAYSHARE ))return ; - start =ALIGN (vma->vm_start,PUD_SIZE ); - end =ALIGN_DOWN (vma->vm_end,PUD_SIZE ); -if (start >= end)return ;
@@ -7373,6 +7389,16 @@ void hugetlb_unshare_all_pmds(struct vm_area_struct *vma)mmu_notifier_invalidate_range_end (&range); } +/* +* This function will unconditionally remove all the shared pmd pgtable entries +* within the specific vma for a hugetlbfs memory range. +*/ +void hugetlb_unshare_all_pmds (struct vm_area_struct *vma) +{ +hugetlb_unshare_pmds (vma,ALIGN (vma->vm_start,PUD_SIZE ), +ALIGN_DOWN (vma->vm_end,PUD_SIZE )); +} +#ifdef CONFIG_CMA static bool cma_reserve_called__initdata ;