The VM_BUG_ON_PAGE in page_move_anon_rmap() is more trouble than it's worth: the syzkaller fuzzer hit it again. It's still wrong for some THP cases, because linear_page_index() was never intended to apply to addresses before the start of a vma. That's easily fixed with a signed long cast inside linear_page_index(); and Dmitry has tested such a patch, to verify the false positive. But why extend linear_page_index() just for this case? when the avoidance in page_move_anon_rmap() has already grown ugly, and there's no reason for the check at all (nothing else there is using address or index). Remove address arg from page_move_anon_rmap(), remove VM_BUG_ON_PAGE, remove CONFIG_DEBUG_VM PageTransHuge adjustment. And one more thing: should the compound_head(page) be done inside or outside page_move_anon_rmap()? It's usually pushed down to the lowest level nowadays (and mm/memory.c shows no other explicit use of it), so I think it's better done in page_move_anon_rmap() than by caller.
Unified · Split
| @@ -158,7 +158,7 @@ struct anon_vma *page_get_anon_vma(struct page *page); · 157 unmodified lines | ||
| 158 | 158 | /* |
| 159 | 159 | * rmap interfaces called when adding or removing pte of page |
| 160 | 160 | */ |
| 161 | −void page_move_anon_rmap(struct page *, struct vm_area_struct *, unsigned long); | |
| 161 | +void page_move_anon_rmap(struct page *, struct vm_area_struct *); | |
| 162 | 162 | void page_add_anon_rmap(struct page *, struct vm_area_struct *, |
| 163 | 163 | unsigned long, bool); |
| 164 | 164 | void do_page_add_anon_rmap(struct page *, struct vm_area_struct *, |
| @@ -3383,7 +3383,7 @@ retry_avoidcopy: · 3382 unmodified lines | ||
| 3383 | 3383 | /* If no-one else is actually using this page, avoid the copy |
| 3384 | 3384 | * and just make the page writable */ |
| 3385 | 3385 | if (page_mapcount(old_page) == 1 && PageAnon(old_page)) { |
| 3386 | − page_move_anon_rmap(old_page, vma, address); | |
| 3386 | + page_move_anon_rmap(old_page, vma); | |
| 3387 | 3387 | set_huge_ptep_writable(vma, address, ptep); |
| 3388 | 3388 | return 0; |
| 3389 | 3389 | } |
| @@ -2399,8 +2399,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, · 2398 unmodified lines | ||
| 2399 | 2399 | * Protected against the rmap code by |
| 2400 | 2400 | * the page lock. |
| 2401 | 2401 | */ |
| 2402 | − page_move_anon_rmap(compound_head(old_page), | |
| 2403 | − vma, address); | |
| 2402 | + page_move_anon_rmap(old_page, vma); | |
| 2404 | 2403 | } |
| 2405 | 2404 | unlock_page(old_page); |
| 2406 | 2405 | return wp_page_reuse(mm, vma, address, page_table, ptl, |
| @@ -1084,23 +1084,20 @@ EXPORT_SYMBOL_GPL(page_mkclean); · 1083 unmodified lines | ||
| 1084 | 1084 | * page_move_anon_rmap - move a page to our anon_vma |
| 1085 | 1085 | * @page: the page to move to our anon_vma |
| 1086 | 1086 | * @vma: the vma the page belongs to |
| 1087 | − * @address: the user virtual address mapped | |
| 1088 | 1087 | * |
| 1089 | 1088 | * When a page belongs exclusively to one process after a COW event, |
| 1090 | 1089 | * that page can be moved into the anon_vma that belongs to just that |
| 1091 | 1090 | * process, so the rmap code will not search the parent or sibling |
| 1092 | 1091 | * processes. |
| 1093 | 1092 | */ |
| 1094 | −void page_move_anon_rmap(struct page *page, | |
| 1095 | − struct vm_area_struct *vma, unsigned long address) | |
| 1093 | +void page_move_anon_rmap(struct page *page, struct vm_area_struct *vma) | |
| 1096 | 1094 | { |
| 1097 | 1095 | struct anon_vma *anon_vma = vma->anon_vma; |
| 1098 | 1096 | |
| 1097 | + page = compound_head(page); | |
| 1098 | + | |
| 1099 | 1099 | VM_BUG_ON_PAGE(!PageLocked(page), page); |
| 1100 | 1100 | VM_BUG_ON_VMA(!anon_vma, vma); |
| 1101 | − if (IS_ENABLED(CONFIG_DEBUG_VM) && PageTransHuge(page)) | |
| 1102 | − address &= HPAGE_PMD_MASK; | |
| 1103 | − VM_BUG_ON_PAGE(page->index != linear_page_index(vma, address), page); | |
| 1104 | 1101 | |
| 1105 | 1102 | anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON; |
| 1106 | 1103 | /* |