mm: fix false-positive WARN_ON() in truncate/invalidate for hugetlb
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Wed, 30 Nov 2016 23:54:19 +0000 (15:54 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 1 Dec 2016 00:32:52 +0000 (16:32 -0800)
Hugetlb pages have ->index in size of the huge pages (PMD_SIZE or
PUD_SIZE), not in PAGE_SIZE as other types of pages.  This means we
cannot user page_to_pgoff() to check whether we've got the right page
for the radix-tree index.

Let's introduce page_to_index() which would return radix-tree index for
given page.

We will be able to get rid of this once hugetlb will be switched to
multi-order entries.

Fixes: fc127da085c2 ("truncate: handle file thp")
Link: http://lkml.kernel.org/r/20161123093053.mjbnvn5zwxw5e6lk@black.fi.intel.com
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Reported-by: Doug Nelson <doug.nelson@intel.com>
Tested-by: Doug Nelson <doug.nelson@intel.com>
Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: <stable@vger.kernel.org> [4.8+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/pagemap.h
mm/truncate.c

index dd15d39e1985908614271dcb8e8712c4fffa4f63..7dbe9148b2f8a661257d0aa620cf1f61fa7d5f57 100644 (file)
@@ -374,16 +374,13 @@ static inline struct page *read_mapping_page(struct address_space *mapping,
 }
 
 /*
- * Get the offset in PAGE_SIZE.
- * (TODO: hugepage should have ->index in PAGE_SIZE)
+ * Get index of the page with in radix-tree
+ * (TODO: remove once hugetlb pages will have ->index in PAGE_SIZE)
  */
-static inline pgoff_t page_to_pgoff(struct page *page)
+static inline pgoff_t page_to_index(struct page *page)
 {
        pgoff_t pgoff;
 
-       if (unlikely(PageHeadHuge(page)))
-               return page->index << compound_order(page);
-
        if (likely(!PageTransTail(page)))
                return page->index;
 
@@ -396,6 +393,18 @@ static inline pgoff_t page_to_pgoff(struct page *page)
        return pgoff;
 }
 
+/*
+ * Get the offset in PAGE_SIZE.
+ * (TODO: hugepage should have ->index in PAGE_SIZE)
+ */
+static inline pgoff_t page_to_pgoff(struct page *page)
+{
+       if (unlikely(PageHeadHuge(page)))
+               return page->index << compound_order(page);
+
+       return page_to_index(page);
+}
+
 /*
  * Return byte-offset into filesystem object for page.
  */
index a01cce450a2692bf4b3c28b105d0444256a0f176..8d8c62d89e6d101bce9373c20258d1bbc9df7fa2 100644 (file)
@@ -283,7 +283,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
 
                        if (!trylock_page(page))
                                continue;
-                       WARN_ON(page_to_pgoff(page) != index);
+                       WARN_ON(page_to_index(page) != index);
                        if (PageWriteback(page)) {
                                unlock_page(page);
                                continue;
@@ -371,7 +371,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
                        }
 
                        lock_page(page);
-                       WARN_ON(page_to_pgoff(page) != index);
+                       WARN_ON(page_to_index(page) != index);
                        wait_on_page_writeback(page);
                        truncate_inode_page(mapping, page);
                        unlock_page(page);
@@ -492,7 +492,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
                        if (!trylock_page(page))
                                continue;
 
-                       WARN_ON(page_to_pgoff(page) != index);
+                       WARN_ON(page_to_index(page) != index);
 
                        /* Middle of THP: skip */
                        if (PageTransTail(page)) {
@@ -612,7 +612,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
                        }
 
                        lock_page(page);
-                       WARN_ON(page_to_pgoff(page) != index);
+                       WARN_ON(page_to_index(page) != index);
                        if (page->mapping != mapping) {
                                unlock_page(page);
                                continue;