mm, rmap: check all VMAs that PTE-mapped THP can be part of
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Fri, 24 Feb 2017 22:57:54 +0000 (14:57 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 25 Feb 2017 01:46:55 +0000 (17:46 -0800)
Current rmap code can miss a VMA that maps PTE-mapped THP if the first
suppage of the THP was unmapped from the VMA.

We need to walk rmap for the whole range of offsets that THP covers, not
only the first one.

vma_address() also need to be corrected to check the range instead of
the first subpage.

Link: http://lkml.kernel.org/r/20170129173858.45174-6-kirill.shutemov@linux.intel.com
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Hillf Danton <hillf.zj@alibaba-inc.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Vladimir Davydov <vdavydov.dev@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
mm/internal.h
mm/rmap.c

index 8ab72f4374e046e604cc7c5f15049f960f1b864e..ccfc2a2969f4402bdbfb27e0b48df151f4da68b7 100644 (file)
@@ -335,12 +335,15 @@ __vma_address(struct page *page, struct vm_area_struct *vma)
 static inline unsigned long
 vma_address(struct page *page, struct vm_area_struct *vma)
 {
-       unsigned long address = __vma_address(page, vma);
+       unsigned long start, end;
+
+       start = __vma_address(page, vma);
+       end = start + PAGE_SIZE * (hpage_nr_pages(page) - 1);
 
        /* page should be within @vma mapping range */
-       VM_BUG_ON_VMA(address < vma->vm_start || address >= vma->vm_end, vma);
+       VM_BUG_ON_VMA(end < vma->vm_start || start >= vma->vm_end, vma);
 
-       return address;
+       return max(start, vma->vm_start);
 }
 
 #else /* !CONFIG_MMU */
index 0dff8accd6297bebd79c6d91a1731429eeac5ea4..c4bad599cc7bdf08a22b8869b522c64c0383f662 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1757,7 +1757,7 @@ static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,
                bool locked)
 {
        struct anon_vma *anon_vma;
-       pgoff_t pgoff;
+       pgoff_t pgoff_start, pgoff_end;
        struct anon_vma_chain *avc;
        int ret = SWAP_AGAIN;
 
@@ -1771,8 +1771,10 @@ static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,
        if (!anon_vma)
                return ret;
 
-       pgoff = page_to_pgoff(page);
-       anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff, pgoff) {
+       pgoff_start = page_to_pgoff(page);
+       pgoff_end = pgoff_start + hpage_nr_pages(page) - 1;
+       anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root,
+                       pgoff_start, pgoff_end) {
                struct vm_area_struct *vma = avc->vma;
                unsigned long address = vma_address(page, vma);
 
@@ -1810,7 +1812,7 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
                bool locked)
 {
        struct address_space *mapping = page_mapping(page);
-       pgoff_t pgoff;
+       pgoff_t pgoff_start, pgoff_end;
        struct vm_area_struct *vma;
        int ret = SWAP_AGAIN;
 
@@ -1825,10 +1827,12 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
        if (!mapping)
                return ret;
 
-       pgoff = page_to_pgoff(page);
+       pgoff_start = page_to_pgoff(page);
+       pgoff_end = pgoff_start + hpage_nr_pages(page) - 1;
        if (!locked)
                i_mmap_lock_read(mapping);
-       vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
+       vma_interval_tree_foreach(vma, &mapping->i_mmap,
+                       pgoff_start, pgoff_end) {
                unsigned long address = vma_address(page, vma);
 
                cond_resched();