Skip to content

Commit 5980768

Browse files
yhuang-inteltorvalds
authored andcommitted
mm, THP, swap: support splitting THP for THP swap out
After adding swapping out support for THP (Transparent Huge Page), it is possible that a THP in swap cache (partly swapped out) need to be split. To split such a THP, the swap cluster backing the THP need to be split too, that is, the CLUSTER_FLAG_HUGE flag need to be cleared for the swap cluster. The patch implemented this. And because the THP swap writing needs the THP keeps as huge page during writing. The PageWriteback flag is checked before splitting. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: "Huang, Ying" <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Minchan Kim <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: Shaohua Li <[email protected]> Cc: Rik van Riel <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: "Kirill A . Shutemov" <[email protected]> Cc: Dan Williams <[email protected]> Cc: Jens Axboe <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Ross Zwisler <[email protected]> [for brd.c, zram_drv.c, pmem.c] Cc: Vishal L Verma <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 225311a commit 5980768

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

include/linux/swap.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,15 @@ static inline swp_entry_t get_swap_page(struct page *page)
527527

528528
#endif /* CONFIG_SWAP */
529529

530+
#ifdef CONFIG_THP_SWAP
531+
extern int split_swap_cluster(swp_entry_t entry);
532+
#else
533+
static inline int split_swap_cluster(swp_entry_t entry)
534+
{
535+
return 0;
536+
}
537+
#endif
538+
530539
#ifdef CONFIG_MEMCG
531540
static inline int mem_cgroup_swappiness(struct mem_cgroup *memcg)
532541
{

mm/huge_memory.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2481,6 +2481,9 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
24812481
VM_BUG_ON_PAGE(!PageLocked(page), page);
24822482
VM_BUG_ON_PAGE(!PageCompound(page), page);
24832483

2484+
if (PageWriteback(page))
2485+
return -EBUSY;
2486+
24842487
if (PageAnon(head)) {
24852488
/*
24862489
* The caller does not necessarily hold an mmap_sem that would
@@ -2558,7 +2561,12 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
25582561
__dec_node_page_state(page, NR_SHMEM_THPS);
25592562
spin_unlock(&pgdata->split_queue_lock);
25602563
__split_huge_page(page, list, flags);
2561-
ret = 0;
2564+
if (PageSwapCache(head)) {
2565+
swp_entry_t entry = { .val = page_private(head) };
2566+
2567+
ret = split_swap_cluster(entry);
2568+
} else
2569+
ret = 0;
25622570
} else {
25632571
if (IS_ENABLED(CONFIG_DEBUG_VM) && mapcount) {
25642572
pr_alert("total_mapcount: %u, page_count(): %u\n",

mm/swapfile.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,21 @@ static void swapcache_free_cluster(swp_entry_t entry)
12161216
}
12171217
}
12181218
}
1219+
1220+
int split_swap_cluster(swp_entry_t entry)
1221+
{
1222+
struct swap_info_struct *si;
1223+
struct swap_cluster_info *ci;
1224+
unsigned long offset = swp_offset(entry);
1225+
1226+
si = _swap_info_get(entry);
1227+
if (!si)
1228+
return -EBUSY;
1229+
ci = lock_cluster(si, offset);
1230+
cluster_clear_huge(ci);
1231+
unlock_cluster(ci);
1232+
return 0;
1233+
}
12191234
#else
12201235
static inline void swapcache_free_cluster(swp_entry_t entry)
12211236
{

0 commit comments

Comments
 (0)