Skip to content

Commit 6f1bace

Browse files
Ryan Robertsakpm00
authored andcommitted
arm64: hugetlb: fix set_huge_pte_at() to work with all swap entries
When called with a swap entry that does not embed a PFN (e.g. PTE_MARKER_POISONED or PTE_MARKER_UFFD_WP), the previous implementation of set_huge_pte_at() would either cause a BUG() to fire (if CONFIG_DEBUG_VM is enabled) or cause a dereference of an invalid address and subsequent panic. arm64's huge pte implementation supports multiple huge page sizes, some of which are implemented in the page table with multiple contiguous entries. So set_huge_pte_at() needs to work out how big the logical pte is, so that it can also work out how many physical ptes (or pmds) need to be written. It previously did this by grabbing the folio out of the pte and querying its size. However, there are cases when the pte being set is actually a swap entry. But this also used to work fine, because for huge ptes, we only ever saw migration entries and hwpoison entries. And both of these types of swap entries have a PFN embedded, so the code would grab that and everything still worked out. But over time, more calls to set_huge_pte_at() have been added that set swap entry types that do not embed a PFN. And this causes the code to go bang. The triggering case is for the uffd poison test, commit 99aa772 ("selftests/mm: add uffd unit test for UFFDIO_POISON"), which causes a PTE_MARKER_POISONED swap entry to be set, coutesey of commit 8a13897 ("mm: userfaultfd: support UFFDIO_POISON for hugetlbfs") - added in v6.5-rc7. Although review shows that there are other call sites that set PTE_MARKER_UFFD_WP (which also has no PFN), these don't trigger on arm64 because arm64 doesn't support UFFD WP. Arguably, the root cause is really due to commit 18f3962 ("mm: hugetlb: kill set_huge_swap_pte_at()"), which aimed to simplify the interface to the core code by removing set_huge_swap_pte_at() (which took a page size parameter) and replacing it with calls to set_huge_pte_at() where the size was inferred from the folio, as descibed above. While that commit didn't break anything at the time, it did break the interface because it couldn't handle swap entries without PFNs. And since then new callers have come along which rely on this working. But given the brokeness is only observable after commit 8a13897 ("mm: userfaultfd: support UFFDIO_POISON for hugetlbfs"), that one gets the Fixes tag. Now that we have modified the set_huge_pte_at() interface to pass the huge page size in the previous patch, we can trivially fix this issue. Link: https://lkml.kernel.org/r/[email protected] Fixes: 8a13897 ("mm: userfaultfd: support UFFDIO_POISON for hugetlbfs") Signed-off-by: Ryan Roberts <[email protected]> Reviewed-by: Axel Rasmussen <[email protected]> Cc: Albert Ou <[email protected]> Cc: Alexander Gordeev <[email protected]> Cc: Alexandre Ghiti <[email protected]> Cc: Anshuman Khandual <[email protected]> Cc: Arnd Bergmann <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Christian Borntraeger <[email protected]> Cc: Christophe Leroy <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: David S. Miller <[email protected]> Cc: Gerald Schaefer <[email protected]> Cc: Heiko Carstens <[email protected]> Cc: Helge Deller <[email protected]> Cc: "James E.J. Bottomley" <[email protected]> Cc: Lorenzo Stoakes <[email protected]> Cc: Mike Kravetz <[email protected]> Cc: Muchun Song <[email protected]> Cc: Nicholas Piggin <[email protected]> Cc: Palmer Dabbelt <[email protected]> Cc: Paul Walmsley <[email protected]> Cc: Peter Xu <[email protected]> Cc: Qi Zheng <[email protected]> Cc: SeongJae Park <[email protected]> Cc: Sven Schnelle <[email protected]> Cc: Uladzislau Rezki (Sony) <[email protected]> Cc: Vasily Gorbik <[email protected]> Cc: Will Deacon <[email protected]> Cc: <[email protected]> [6.5+] Signed-off-by: Andrew Morton <[email protected]>
1 parent 935d4f0 commit 6f1bace

File tree

1 file changed

+3
-14
lines changed

1 file changed

+3
-14
lines changed

arch/arm64/mm/hugetlbpage.c

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,6 @@ static void clear_flush(struct mm_struct *mm,
241241
flush_tlb_range(&vma, saddr, addr);
242242
}
243243

244-
static inline struct folio *hugetlb_swap_entry_to_folio(swp_entry_t entry)
245-
{
246-
VM_BUG_ON(!is_migration_entry(entry) && !is_hwpoison_entry(entry));
247-
248-
return page_folio(pfn_to_page(swp_offset_pfn(entry)));
249-
}
250-
251244
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
252245
pte_t *ptep, pte_t pte, unsigned long sz)
253246
{
@@ -257,13 +250,10 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
257250
unsigned long pfn, dpfn;
258251
pgprot_t hugeprot;
259252

260-
if (!pte_present(pte)) {
261-
struct folio *folio;
262-
263-
folio = hugetlb_swap_entry_to_folio(pte_to_swp_entry(pte));
264-
ncontig = num_contig_ptes(folio_size(folio), &pgsize);
253+
ncontig = num_contig_ptes(sz, &pgsize);
265254

266-
for (i = 0; i < ncontig; i++, ptep++)
255+
if (!pte_present(pte)) {
256+
for (i = 0; i < ncontig; i++, ptep++, addr += pgsize)
267257
set_pte_at(mm, addr, ptep, pte);
268258
return;
269259
}
@@ -273,7 +263,6 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
273263
return;
274264
}
275265

276-
ncontig = find_num_contig(mm, addr, ptep, &pgsize);
277266
pfn = pte_pfn(pte);
278267
dpfn = pgsize >> PAGE_SHIFT;
279268
hugeprot = pte_pgprot(pte);

0 commit comments

Comments
 (0)