Merge e8847d18cd ("mm/hugetlb: unshare page tables during VMA split, not before") into android12-5.10-lts
Steps on the way to 5.10.239 Resolves merge conflicts in: include/linux/hugetlb.h mm/hugetlb.c Change-Id: I7e00df7ef9e81680637d61a1d9dda6d6f46e72af Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -194,6 +194,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
|
||||
|
||||
bool is_hugetlb_entry_migration(pte_t pte);
|
||||
void hugetlb_unshare_all_pmds(struct vm_area_struct *vma);
|
||||
void hugetlb_split(struct vm_area_struct *vma, unsigned long addr);
|
||||
|
||||
#else /* !CONFIG_HUGETLB_PAGE */
|
||||
|
||||
@@ -380,6 +381,8 @@ static inline vm_fault_t hugetlb_fault(struct mm_struct *mm,
|
||||
|
||||
static inline void hugetlb_unshare_all_pmds(struct vm_area_struct *vma) { }
|
||||
|
||||
static inline void hugetlb_split(struct vm_area_struct *vma, unsigned long addr) {}
|
||||
|
||||
#endif /* !CONFIG_HUGETLB_PAGE */
|
||||
/*
|
||||
* hugepages at page global directory. If arch support
|
||||
|
||||
59
mm/hugetlb.c
59
mm/hugetlb.c
@@ -78,9 +78,6 @@ DEFINE_SPINLOCK(hugetlb_lock);
|
||||
static int num_fault_mutexes;
|
||||
struct mutex *hugetlb_fault_mutex_table ____cacheline_aligned_in_smp;
|
||||
|
||||
static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
|
||||
unsigned long start, unsigned long end);
|
||||
|
||||
static inline bool PageHugeFreed(struct page *head)
|
||||
{
|
||||
return page_private(head + 4) == -1UL;
|
||||
@@ -98,6 +95,8 @@ static inline void ClearPageHugeFreed(struct page *head)
|
||||
|
||||
/* Forward declaration */
|
||||
static int hugetlb_acct_memory(struct hstate *h, long delta);
|
||||
static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
|
||||
unsigned long start, unsigned long end, bool take_locks);
|
||||
|
||||
static inline void unlock_or_release_subpool(struct hugepage_subpool *spool)
|
||||
{
|
||||
@@ -3701,26 +3700,40 @@ static int hugetlb_vm_op_split(struct vm_area_struct *vma, unsigned long addr)
|
||||
{
|
||||
if (addr & ~(huge_page_mask(hstate_vma(vma))))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hugetlb_split(struct vm_area_struct *vma, unsigned long addr)
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
* This function is called in the middle of a VMA split operation, with
|
||||
* MM, VMA and rmap all write-locked to prevent concurrent page table
|
||||
* walks (except hardware and gup_fast()).
|
||||
*/
|
||||
mmap_assert_write_locked(vma->vm_mm);
|
||||
i_mmap_assert_write_locked(vma->vm_file->f_mapping);
|
||||
|
||||
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);
|
||||
if (floor >= vma->vm_start && ceil <= vma->vm_end) {
|
||||
/*
|
||||
* Locking:
|
||||
* Use take_locks=false here.
|
||||
* The file rmap lock is already held.
|
||||
* The hugetlb VMA lock can't be taken when we already
|
||||
* hold the file rmap lock, and we don't need it because
|
||||
* its purpose is to synchronize against concurrent page
|
||||
* table walks, which are not possible thanks to the
|
||||
* locks held by our caller.
|
||||
*/
|
||||
hugetlb_unshare_pmds(vma, floor, ceil, /* take_locks = */ false);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long hugetlb_vm_op_pagesize(struct vm_area_struct *vma)
|
||||
@@ -5769,9 +5782,16 @@ void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If @take_locks is false, the caller must ensure that no concurrent page table
|
||||
* access can happen (except for gup_fast() and hardware page walks).
|
||||
* If @take_locks is true, we take the hugetlb VMA lock (to lock out things like
|
||||
* concurrent page fault handling) and the file rmap lock.
|
||||
*/
|
||||
static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
|
||||
unsigned long start,
|
||||
unsigned long end)
|
||||
unsigned long end,
|
||||
bool take_locks)
|
||||
{
|
||||
struct hstate *h = hstate_vma(vma);
|
||||
unsigned long sz = huge_page_size(h);
|
||||
@@ -5795,7 +5815,11 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
|
||||
mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, mm,
|
||||
start, end);
|
||||
mmu_notifier_invalidate_range_start(&range);
|
||||
i_mmap_lock_write(vma->vm_file->f_mapping);
|
||||
if (take_locks) {
|
||||
i_mmap_lock_write(vma->vm_file->f_mapping);
|
||||
} else {
|
||||
i_mmap_assert_write_locked(vma->vm_file->f_mapping);
|
||||
}
|
||||
for (address = start; address < end; address += PUD_SIZE) {
|
||||
unsigned long tmp = address;
|
||||
|
||||
@@ -5808,7 +5832,9 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
|
||||
spin_unlock(ptl);
|
||||
}
|
||||
flush_hugetlb_tlb_range(vma, start, end);
|
||||
i_mmap_unlock_write(vma->vm_file->f_mapping);
|
||||
if (take_locks) {
|
||||
i_mmap_unlock_write(vma->vm_file->f_mapping);
|
||||
}
|
||||
/*
|
||||
* No need to call mmu_notifier_invalidate_range(), see
|
||||
* Documentation/vm/mmu_notifier.rst.
|
||||
@@ -5823,7 +5849,8 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
|
||||
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));
|
||||
ALIGN_DOWN(vma->vm_end, PUD_SIZE),
|
||||
/* take_locks = */ true);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMA
|
||||
|
||||
@@ -880,7 +880,15 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start,
|
||||
}
|
||||
}
|
||||
again:
|
||||
/*
|
||||
* Get rid of huge pages and shared page tables straddling the split
|
||||
* boundary.
|
||||
*/
|
||||
vma_adjust_trans_huge(orig_vma, start, end, adjust_next);
|
||||
if (is_vm_hugetlb_page(orig_vma)) {
|
||||
hugetlb_split(orig_vma, start);
|
||||
hugetlb_split(orig_vma, end);
|
||||
}
|
||||
|
||||
if (file) {
|
||||
mapping = file->f_mapping;
|
||||
|
||||
Reference in New Issue
Block a user