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>
This commit is contained in:
parent
828347f8f9
commit
5cbc198ae0
@ -374,16 +374,13 @@ static inline struct page *read_mapping_page(struct address_space *mapping,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the offset in PAGE_SIZE.
|
* Get index of the page with in radix-tree
|
||||||
* (TODO: hugepage should have ->index in PAGE_SIZE)
|
* (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;
|
pgoff_t pgoff;
|
||||||
|
|
||||||
if (unlikely(PageHeadHuge(page)))
|
|
||||||
return page->index << compound_order(page);
|
|
||||||
|
|
||||||
if (likely(!PageTransTail(page)))
|
if (likely(!PageTransTail(page)))
|
||||||
return page->index;
|
return page->index;
|
||||||
|
|
||||||
@ -396,6 +393,18 @@ static inline pgoff_t page_to_pgoff(struct page *page)
|
|||||||
return pgoff;
|
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.
|
* Return byte-offset into filesystem object for page.
|
||||||
*/
|
*/
|
||||||
|
@ -283,7 +283,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
|
|||||||
|
|
||||||
if (!trylock_page(page))
|
if (!trylock_page(page))
|
||||||
continue;
|
continue;
|
||||||
WARN_ON(page_to_pgoff(page) != index);
|
WARN_ON(page_to_index(page) != index);
|
||||||
if (PageWriteback(page)) {
|
if (PageWriteback(page)) {
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
continue;
|
continue;
|
||||||
@ -371,7 +371,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
|
|||||||
}
|
}
|
||||||
|
|
||||||
lock_page(page);
|
lock_page(page);
|
||||||
WARN_ON(page_to_pgoff(page) != index);
|
WARN_ON(page_to_index(page) != index);
|
||||||
wait_on_page_writeback(page);
|
wait_on_page_writeback(page);
|
||||||
truncate_inode_page(mapping, page);
|
truncate_inode_page(mapping, page);
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
@ -492,7 +492,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,
|
|||||||
if (!trylock_page(page))
|
if (!trylock_page(page))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
WARN_ON(page_to_pgoff(page) != index);
|
WARN_ON(page_to_index(page) != index);
|
||||||
|
|
||||||
/* Middle of THP: skip */
|
/* Middle of THP: skip */
|
||||||
if (PageTransTail(page)) {
|
if (PageTransTail(page)) {
|
||||||
@ -612,7 +612,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
|
|||||||
}
|
}
|
||||||
|
|
||||||
lock_page(page);
|
lock_page(page);
|
||||||
WARN_ON(page_to_pgoff(page) != index);
|
WARN_ON(page_to_index(page) != index);
|
||||||
if (page->mapping != mapping) {
|
if (page->mapping != mapping) {
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
continue;
|
continue;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user