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 | * rmap interfaces called when adding or removing pte of page | 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 | void page_add_anon_rmap(struct page *, struct vm_area_struct *, | 162 | void page_add_anon_rmap(struct page *, struct vm_area_struct *, |
| 163 | unsigned long, bool); | 163 | unsigned long, bool); |
| 164 | void do_page_add_anon_rmap(struct page *, struct vm_area_struct *, | 164 | void do_page_add_anon_rmap(struct page *, struct vm_area_struct *, |
| @@ -3383,7 +3383,7 @@ retry_avoidcopy: · 3382 unmodified lines | |||
| 3383 | /* If no-one else is actually using this page, avoid the copy | 3383 | /* If no-one else is actually using this page, avoid the copy |
| 3384 | * and just make the page writable */ | 3384 | * and just make the page writable */ |
| 3385 | if (page_mapcount(old_page) == 1 && PageAnon(old_page)) { | 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 | set_huge_ptep_writable(vma, address, ptep); | 3387 | set_huge_ptep_writable(vma, address, ptep); |
| 3388 | return 0; | 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 | * Protected against the rmap code by | 2399 | * Protected against the rmap code by |
| 2400 | * the page lock. | 2400 | * the page lock. |
| 2401 | */ | 2401 | */ |
| 2402 | page_move_anon_rmap(compound_head(old_page), | 2402 | page_move_anon_rmap(old_page, vma); |
| 2403 | vma, address); | ||
| 2404 | } | 2403 | } |
| 2405 | unlock_page(old_page); | 2404 | unlock_page(old_page); |
| 2406 | return wp_page_reuse(mm, vma, address, page_table, ptl, | 2405 | return wp_page_reuse(mm, vma, address, page_table, ptl, |
| @@ -1084,23 +1084,20 @@ EXPORT_SYMBOL_GPL(page_mkclean); · 1083 unmodified lines | |||
| 1084 | * page_move_anon_rmap - move a page to our anon_vma | 1084 | * page_move_anon_rmap - move a page to our anon_vma |
| 1085 | * @page: the page to move to our anon_vma | 1085 | * @page: the page to move to our anon_vma |
| 1086 | * @vma: the vma the page belongs to | 1086 | * @vma: the vma the page belongs to |
| 1087 | * @address: the user virtual address mapped | ||
| 1088 | * | 1087 | * |
| 1089 | * When a page belongs exclusively to one process after a COW event, | 1088 | * When a page belongs exclusively to one process after a COW event, |
| 1090 | * that page can be moved into the anon_vma that belongs to just that | 1089 | * that page can be moved into the anon_vma that belongs to just that |
| 1091 | * process, so the rmap code will not search the parent or sibling | 1090 | * process, so the rmap code will not search the parent or sibling |
| 1092 | * processes. | 1091 | * processes. |
| 1093 | */ | 1092 | */ |
| 1094 | void page_move_anon_rmap(struct page *page, | 1093 | void page_move_anon_rmap(struct page *page, struct vm_area_struct *vma) |
| 1095 | struct vm_area_struct *vma, unsigned long address) | ||
| 1096 | { | 1094 | { |
| 1097 | struct anon_vma *anon_vma = vma->anon_vma; | 1095 | struct anon_vma *anon_vma = vma->anon_vma; |
| 1098 | 1096 | ||
| 1097 | page = compound_head(page); | ||
| 1098 | |||
| 1099 | VM_BUG_ON_PAGE(!PageLocked(page), page); | 1099 | VM_BUG_ON_PAGE(!PageLocked(page), page); |
| 1100 | VM_BUG_ON_VMA(!anon_vma, vma); | 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 | anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON; | 1102 | anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON; |
| 1106 | /* | 1103 | /* |