2626#include <linux/hashtable.h>
2727#include <linux/userfaultfd_k.h>
2828#include <linux/page_idle.h>
29+ #include <linux/swapops.h>
2930
3031#include <asm/tlb.h>
3132#include <asm/pgalloc.h>
@@ -52,7 +53,8 @@ enum scan_result {
5253 SCAN_SWAP_CACHE_PAGE ,
5354 SCAN_DEL_PAGE_LRU ,
5455 SCAN_ALLOC_HUGE_PAGE_FAIL ,
55- SCAN_CGROUP_CHARGE_FAIL
56+ SCAN_CGROUP_CHARGE_FAIL ,
57+ SCAN_EXCEED_SWAP_PTE
5658};
5759
5860#define CREATE_TRACE_POINTS
@@ -94,6 +96,7 @@ static DECLARE_WAIT_QUEUE_HEAD(khugepaged_wait);
9496 * fault.
9597 */
9698static unsigned int khugepaged_max_ptes_none __read_mostly = HPAGE_PMD_NR - 1 ;
99+ static unsigned int khugepaged_max_ptes_swap __read_mostly = HPAGE_PMD_NR /8 ;
97100
98101static int khugepaged (void * none );
99102static int khugepaged_slab_init (void );
@@ -580,6 +583,33 @@ static struct kobj_attribute khugepaged_max_ptes_none_attr =
580583 __ATTR (max_ptes_none , 0644 , khugepaged_max_ptes_none_show ,
581584 khugepaged_max_ptes_none_store );
582585
586+ static ssize_t khugepaged_max_ptes_swap_show (struct kobject * kobj ,
587+ struct kobj_attribute * attr ,
588+ char * buf )
589+ {
590+ return sprintf (buf , "%u\n" , khugepaged_max_ptes_swap );
591+ }
592+
593+ static ssize_t khugepaged_max_ptes_swap_store (struct kobject * kobj ,
594+ struct kobj_attribute * attr ,
595+ const char * buf , size_t count )
596+ {
597+ int err ;
598+ unsigned long max_ptes_swap ;
599+
600+ err = kstrtoul (buf , 10 , & max_ptes_swap );
601+ if (err || max_ptes_swap > HPAGE_PMD_NR - 1 )
602+ return - EINVAL ;
603+
604+ khugepaged_max_ptes_swap = max_ptes_swap ;
605+
606+ return count ;
607+ }
608+
609+ static struct kobj_attribute khugepaged_max_ptes_swap_attr =
610+ __ATTR (max_ptes_swap , 0644 , khugepaged_max_ptes_swap_show ,
611+ khugepaged_max_ptes_swap_store );
612+
583613static struct attribute * khugepaged_attr [] = {
584614 & khugepaged_defrag_attr .attr ,
585615 & khugepaged_max_ptes_none_attr .attr ,
@@ -588,6 +618,7 @@ static struct attribute *khugepaged_attr[] = {
588618 & full_scans_attr .attr ,
589619 & scan_sleep_millisecs_attr .attr ,
590620 & alloc_sleep_millisecs_attr .attr ,
621+ & khugepaged_max_ptes_swap_attr .attr ,
591622 NULL ,
592623};
593624
@@ -2720,7 +2751,7 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
27202751 struct page * page = NULL ;
27212752 unsigned long _address ;
27222753 spinlock_t * ptl ;
2723- int node = NUMA_NO_NODE ;
2754+ int node = NUMA_NO_NODE , unmapped = 0 ;
27242755 bool writable = false, referenced = false;
27252756
27262757 VM_BUG_ON (address & ~HPAGE_PMD_MASK );
@@ -2736,6 +2767,14 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
27362767 for (_address = address , _pte = pte ; _pte < pte + HPAGE_PMD_NR ;
27372768 _pte ++ , _address += PAGE_SIZE ) {
27382769 pte_t pteval = * _pte ;
2770+ if (is_swap_pte (pteval )) {
2771+ if (++ unmapped <= khugepaged_max_ptes_swap ) {
2772+ continue ;
2773+ } else {
2774+ ret = SCAN_EXCEED_SWAP_PTE ;
2775+ goto out_unmap ;
2776+ }
2777+ }
27392778 if (pte_none (pteval ) || is_zero_pfn (pte_pfn (pteval ))) {
27402779 if (!userfaultfd_armed (vma ) &&
27412780 ++ none_or_zero <= khugepaged_max_ptes_none ) {
@@ -2816,7 +2855,7 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
28162855 }
28172856out :
28182857 trace_mm_khugepaged_scan_pmd (mm , page_to_pfn (page ), writable , referenced ,
2819- none_or_zero , result );
2858+ none_or_zero , result , unmapped );
28202859 return ret ;
28212860}
28222861
0 commit comments