Skip to content

Commit e9b61f1

Browse files
kiryltorvalds
authored andcommitted
thp: reintroduce split_huge_page()
This patch adds implementation of split_huge_page() for new refcountings. Unlike previous implementation, new split_huge_page() can fail if somebody holds GUP pin on the page. It also means that pin on page would prevent it from bening split under you. It makes situation in many places much cleaner. The basic scheme of split_huge_page(): - Check that sum of mapcounts of all subpage is equal to page_count() plus one (caller pin). Foll off with -EBUSY. This way we can avoid useless PMD-splits. - Freeze the page counters by splitting all PMD and setup migration PTEs. - Re-check sum of mapcounts against page_count(). Page's counts are stable now. -EBUSY if page is pinned. - Split compound page. - Unfreeze the page by removing migration entries. Signed-off-by: Kirill A. Shutemov <[email protected]> Tested-by: Sasha Levin <[email protected]> Tested-by: Aneesh Kumar K.V <[email protected]> Acked-by: Jerome Marchand <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Mel Gorman <[email protected]> Cc: Rik van Riel <[email protected]> Cc: Naoya Horiguchi <[email protected]> Cc: Steve Capper <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Christoph Lameter <[email protected]> Cc: David Rientjes <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 4e41a30 commit e9b61f1

File tree

5 files changed

+415
-45
lines changed

5 files changed

+415
-45
lines changed

include/linux/huge_mm.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,11 @@ extern bool is_vma_temporary_stack(struct vm_area_struct *vma);
9090

9191
extern unsigned long transparent_hugepage_flags;
9292

93-
#define split_huge_page_to_list(page, list) BUILD_BUG()
94-
#define split_huge_page(page) BUILD_BUG()
93+
int split_huge_page_to_list(struct page *page, struct list_head *list);
94+
static inline int split_huge_page(struct page *page)
95+
{
96+
return split_huge_page_to_list(page, NULL);
97+
}
9598

9699
void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
97100
unsigned long address);

include/linux/pagemap.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,10 +394,21 @@ static inline struct page *read_mapping_page(struct address_space *mapping,
394394
*/
395395
static inline pgoff_t page_to_pgoff(struct page *page)
396396
{
397+
pgoff_t pgoff;
398+
397399
if (unlikely(PageHeadHuge(page)))
398400
return page->index << compound_order(page);
399-
else
401+
402+
if (likely(!PageTransTail(page)))
400403
return page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
404+
405+
/*
406+
* We don't initialize ->index for tail pages: calculate based on
407+
* head page
408+
*/
409+
pgoff = compound_head(page)->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
410+
pgoff += page - compound_head(page);
411+
return pgoff;
401412
}
402413

403414
/*

0 commit comments

Comments
 (0)