On 19.04.22 19:40, Vlastimil Babka wrote: > On 3/29/22 18:04, David Hildenbrand wrote: >> Let's verify when (un)pinning anonymous pages that we always deal with >> exclusive anonymous pages, which guarantees that we'll have a reliable >> PIN, meaning that we cannot end up with the GUP pin being inconsistent >> with he pages mapped into the page tables due to a COW triggered >> by a write fault. >> >> When pinning pages, after conditionally triggering GUP unsharing of >> possibly shared anonymous pages, we should always only see exclusive >> anonymous pages. Note that anonymous pages that are mapped writable >> must be marked exclusive, otherwise we'd have a BUG. >> >> When pinning during ordinary GUP, simply add a check after our >> conditional GUP-triggered unsharing checks. As we know exactly how the >> page is mapped, we know exactly in which page we have to check for >> PageAnonExclusive(). >> >> When pinning via GUP-fast we have to be careful, because we can race with >> fork(): verify only after we made sure via the seqcount that we didn't >> race with concurrent fork() that we didn't end up pinning a possibly >> shared anonymous page. >> >> Similarly, when unpinning, verify that the pages are still marked as >> exclusive: otherwise something turned the pages possibly shared, which >> can result in random memory corruptions, which we really want to catch. >> >> With only the pinned pages at hand and not the actual page table entries >> we have to be a bit careful: hugetlb pages are always mapped via a >> single logical page table entry referencing the head page and >> PG_anon_exclusive of the head page applies. Anon THP are a bit more >> complicated, because we might have obtained the page reference either via >> a PMD or a PTE -- depending on the mapping type we either have to check >> PageAnonExclusive of the head page (PMD-mapped THP) or the tail page >> (PTE-mapped THP) applies: as we don't know and to make our life easier, >> check that either is set. >> >> Take care to not verify in case we're unpinning during GUP-fast because >> we detected concurrent fork(): we might stumble over an anonymous page >> that is now shared. >> >> Signed-off-by: David Hildenbrand <david@xxxxxxxxxx> > > Acked-by: Vlastimil Babka <vbabka@xxxxxxx> > > Nits: > >> @@ -510,6 +563,10 @@ static struct page *follow_page_pte(struct vm_area_struct *vma, >> page = ERR_PTR(-EMLINK); >> goto out; >> } >> + >> + VM_BUG_ON((flags & FOLL_PIN) && PageAnon(page) && >> + !PageAnonExclusive(page)); > > Do we rather want VM_BUG_ON_PAGE? Also for the same tests in mm/huge*.c below. Make sense, thanks: diff --git a/mm/gup.c b/mm/gup.c index 5c17d4816441..46ffd8c51c6e 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -564,8 +564,8 @@ static struct page *follow_page_pte(struct vm_area_struct *vma, goto out; } - VM_BUG_ON((flags & FOLL_PIN) && PageAnon(page) && - !PageAnonExclusive(page)); + VM_BUG_ON_PAGE((flags & FOLL_PIN) && PageAnon(page) && + !PageAnonExclusive(page), page); /* try_grab_page() does nothing unless FOLL_GET or FOLL_PIN is set. */ if (unlikely(!try_grab_page(page, flags))) { diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 390f22334ee9..a2f44d8d3d47 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1392,8 +1392,8 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma, if (!pmd_write(*pmd) && gup_must_unshare(flags, page)) return ERR_PTR(-EMLINK); - VM_BUG_ON((flags & FOLL_PIN) && PageAnon(page) && - !PageAnonExclusive(page)); + VM_BUG_ON_PAGE((flags & FOLL_PIN) && PageAnon(page) && + !PageAnonExclusive(page), page); if (!try_grab_page(page, flags)) return ERR_PTR(-ENOMEM); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 8a635b5b5270..0ba2b1930b21 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -6100,8 +6100,8 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, pfn_offset = (vaddr & ~huge_page_mask(h)) >> PAGE_SHIFT; page = pte_page(huge_ptep_get(pte)); - VM_BUG_ON((flags & FOLL_PIN) && PageAnon(page) && - !PageAnonExclusive(page)); + VM_BUG_ON_PAGE((flags & FOLL_PIN) && PageAnon(page) && + !PageAnonExclusive(page), page); /* * If subpage information not requested, update counters -- Thanks, David / dhildenb