aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>2016-11-30 18:54:19 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-11-30 19:32:52 -0500
commit5cbc198ae08d84bd416b672ad8bd1222acd0855c (patch)
tree985d1c3e96076aaca0f485d26f04b9957f920013
parent828347f8f9a558cf1af2faa46387a26564f2ac3e (diff)
mm: fix false-positive WARN_ON() in truncate/invalidate for hugetlb
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>
-rw-r--r--include/linux/pagemap.h21
-rw-r--r--mm/truncate.c8
2 files changed, 19 insertions, 10 deletions
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index dd15d39e1985..7dbe9148b2f8 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -374,16 +374,13 @@ static inline struct page *read_mapping_page(struct address_space *mapping,
374} 374}
375 375
376/* 376/*
377 * Get the offset in PAGE_SIZE. 377 * Get index of the page with in radix-tree
378 * (TODO: hugepage should have ->index in PAGE_SIZE) 378 * (TODO: remove once hugetlb pages will have ->index in PAGE_SIZE)
379 */ 379 */
380static inline pgoff_t page_to_pgoff(struct page *page) 380static inline pgoff_t page_to_index(struct page *page)
381{ 381{
382 pgoff_t pgoff; 382 pgoff_t pgoff;
383 383
384 if (unlikely(PageHeadHuge(page)))
385 return page->index << compound_order(page);
386
387 if (likely(!PageTransTail(page))) 384 if (likely(!PageTransTail(page)))
388 return page->index; 385 return page->index;
389 386
@@ -397,6 +394,18 @@ static inline pgoff_t page_to_pgoff(struct page *page)
397} 394}
398 395
399/* 396/*
397 * Get the offset in PAGE_SIZE.
398 * (TODO: hugepage should have ->index in PAGE_SIZE)
399 */
400static inline pgoff_t page_to_pgoff(struct page *page)
401{
402 if (unlikely(PageHeadHuge(page)))
403 return page->index << compound_order(page);
404
405 return page_to_index(page);
406}
407
408/*
400 * Return byte-offset into filesystem object for page. 409 * Return byte-offset into filesystem object for page.
401 */ 410 */
402static inline loff_t page_offset(struct page *page) 411static inline loff_t page_offset(struct page *page)
diff --git a/mm/truncate.c b/mm/truncate.c
index a01cce450a26..8d8c62d89e6d 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -283,7 +283,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
283 283
284 if (!trylock_page(page)) 284 if (!trylock_page(page))
285 continue; 285 continue;
286 WARN_ON(page_to_pgoff(page) != index); 286 WARN_ON(page_to_index(page) != index);
287 if (PageWriteback(page)) { 287 if (PageWriteback(page)) {
288 unlock_page(page); 288 unlock_page(page);
289 continue; 289 continue;
@@ -371,7 +371,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
371 } 371 }
372 372
373 lock_page(page); 373 lock_page(page);
374 WARN_ON(page_to_pgoff(page) != index); 374 WARN_ON(page_to_index(page) != index);
375 wait_on_page_writeback(page); 375 wait_on_page_writeback(page);
376 truncate_inode_page(mapping, page); 376 truncate_inode_page(mapping, page);
377 unlock_page(page); 377 unlock_page(page);
@@ -492,7 +492,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
492 if (!trylock_page(page)) 492 if (!trylock_page(page))
493 continue; 493 continue;
494 494
495 WARN_ON(page_to_pgoff(page) != index); 495 WARN_ON(page_to_index(page) != index);
496 496
497 /* Middle of THP: skip */ 497 /* Middle of THP: skip */
498 if (PageTransTail(page)) { 498 if (PageTransTail(page)) {
@@ -612,7 +612,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
612 } 612 }
613 613
614 lock_page(page); 614 lock_page(page);
615 WARN_ON(page_to_pgoff(page) != index); 615 WARN_ON(page_to_index(page) != index);
616 if (page->mapping != mapping) { 616 if (page->mapping != mapping) {
617 unlock_page(page); 617 unlock_page(page);
618 continue; 618 continue;