1414#ifndef MADV_PAGEOUT
1515#define MADV_PAGEOUT 21
1616#endif
17+ #ifndef MADV_COLLAPSE
18+ #define MADV_COLLAPSE 25
19+ #endif
1720
1821#define BASE_ADDR ((void *)(1UL << 30))
1922static unsigned long hpage_pmd_size ;
@@ -95,18 +98,6 @@ struct settings {
9598 struct khugepaged_settings khugepaged ;
9699};
97100
98- static struct settings default_settings = {
99- .thp_enabled = THP_MADVISE ,
100- .thp_defrag = THP_DEFRAG_ALWAYS ,
101- .shmem_enabled = SHMEM_NEVER ,
102- .use_zero_page = 0 ,
103- .khugepaged = {
104- .defrag = 1 ,
105- .alloc_sleep_millisecs = 10 ,
106- .scan_sleep_millisecs = 10 ,
107- },
108- };
109-
110101static struct settings saved_settings ;
111102static bool skip_settings_restore ;
112103
@@ -284,6 +275,39 @@ static void write_settings(struct settings *settings)
284275 write_num ("khugepaged/pages_to_scan" , khugepaged -> pages_to_scan );
285276}
286277
278+ #define MAX_SETTINGS_DEPTH 4
279+ static struct settings settings_stack [MAX_SETTINGS_DEPTH ];
280+ static int settings_index ;
281+
282+ static struct settings * current_settings (void )
283+ {
284+ if (!settings_index ) {
285+ printf ("Fail: No settings set" );
286+ exit (EXIT_FAILURE );
287+ }
288+ return settings_stack + settings_index - 1 ;
289+ }
290+
291+ static void push_settings (struct settings * settings )
292+ {
293+ if (settings_index >= MAX_SETTINGS_DEPTH ) {
294+ printf ("Fail: Settings stack exceeded" );
295+ exit (EXIT_FAILURE );
296+ }
297+ settings_stack [settings_index ++ ] = * settings ;
298+ write_settings (current_settings ());
299+ }
300+
301+ static void pop_settings (void )
302+ {
303+ if (settings_index <= 0 ) {
304+ printf ("Fail: Settings stack empty" );
305+ exit (EXIT_FAILURE );
306+ }
307+ -- settings_index ;
308+ write_settings (current_settings ());
309+ }
310+
287311static void restore_settings (int sig )
288312{
289313 if (skip_settings_restore )
@@ -327,14 +351,6 @@ static void save_settings(void)
327351 signal (SIGQUIT , restore_settings );
328352}
329353
330- static void adjust_settings (void )
331- {
332-
333- printf ("Adjust settings..." );
334- write_settings (& default_settings );
335- success ("OK" );
336- }
337-
338354#define MAX_LINE_LENGTH 500
339355
340356static bool check_for_pattern (FILE * fp , char * pattern , char * buf )
@@ -493,6 +509,38 @@ static void validate_memory(int *p, unsigned long start, unsigned long end)
493509 }
494510}
495511
512+ static void madvise_collapse (const char * msg , char * p , bool expect )
513+ {
514+ int ret ;
515+ struct settings settings = * current_settings ();
516+
517+ printf ("%s..." , msg );
518+ /* Sanity check */
519+ if (check_huge (p )) {
520+ printf ("Unexpected huge page\n" );
521+ exit (EXIT_FAILURE );
522+ }
523+
524+ /*
525+ * Prevent khugepaged interference and tests that MADV_COLLAPSE
526+ * ignores /sys/kernel/mm/transparent_hugepage/enabled
527+ */
528+ settings .thp_enabled = THP_NEVER ;
529+ push_settings (& settings );
530+
531+ /* Clear VM_NOHUGEPAGE */
532+ madvise (p , hpage_pmd_size , MADV_HUGEPAGE );
533+ ret = madvise (p , hpage_pmd_size , MADV_COLLAPSE );
534+ if (((bool )ret ) == expect )
535+ fail ("Fail: Bad return value" );
536+ else if (check_huge (p ) != expect )
537+ fail ("Fail: check_huge()" );
538+ else
539+ success ("OK" );
540+
541+ pop_settings ();
542+ }
543+
496544#define TICK 500000
497545static bool wait_for_scan (const char * msg , char * p )
498546{
@@ -542,11 +590,11 @@ static void khugepaged_collapse(const char *msg, char *p, bool expect)
542590
543591static void alloc_at_fault (void )
544592{
545- struct settings settings = default_settings ;
593+ struct settings settings = * current_settings () ;
546594 char * p ;
547595
548596 settings .thp_enabled = THP_ALWAYS ;
549- write_settings (& settings );
597+ push_settings (& settings );
550598
551599 p = alloc_mapping ();
552600 * p = 1 ;
@@ -556,7 +604,7 @@ static void alloc_at_fault(void)
556604 else
557605 fail ("Fail" );
558606
559- write_settings ( & default_settings );
607+ pop_settings ( );
560608
561609 madvise (p , page_size , MADV_DONTNEED );
562610 printf ("Split huge PMD on MADV_DONTNEED..." );
@@ -602,11 +650,11 @@ static void collapse_single_pte_entry(struct collapse_context *c)
602650static void collapse_max_ptes_none (struct collapse_context * c )
603651{
604652 int max_ptes_none = hpage_pmd_nr / 2 ;
605- struct settings settings = default_settings ;
653+ struct settings settings = * current_settings () ;
606654 void * p ;
607655
608656 settings .khugepaged .max_ptes_none = max_ptes_none ;
609- write_settings (& settings );
657+ push_settings (& settings );
610658
611659 p = alloc_mapping ();
612660
@@ -623,7 +671,7 @@ static void collapse_max_ptes_none(struct collapse_context *c)
623671 }
624672
625673 munmap (p , hpage_pmd_size );
626- write_settings ( & default_settings );
674+ pop_settings ( );
627675}
628676
629677static void collapse_swapin_single_pte (struct collapse_context * c )
@@ -703,7 +751,6 @@ static void collapse_single_pte_entry_compound(struct collapse_context *c)
703751
704752 p = alloc_hpage ();
705753 madvise (p , hpage_pmd_size , MADV_NOHUGEPAGE );
706-
707754 printf ("Split huge page leaving single PTE mapping compound page..." );
708755 madvise (p + page_size , hpage_pmd_size - page_size , MADV_DONTNEED );
709756 if (!check_huge (p ))
@@ -864,7 +911,7 @@ static void collapse_fork_compound(struct collapse_context *c)
864911 c -> collapse ("Collapse PTE table full of compound pages in child" ,
865912 p , true);
866913 write_num ("khugepaged/max_ptes_shared" ,
867- default_settings . khugepaged .max_ptes_shared );
914+ current_settings () -> khugepaged .max_ptes_shared );
868915
869916 validate_memory (p , 0 , hpage_pmd_size );
870917 munmap (p , hpage_pmd_size );
@@ -943,9 +990,21 @@ static void collapse_max_ptes_shared(struct collapse_context *c)
943990 munmap (p , hpage_pmd_size );
944991}
945992
946- int main (void )
993+ int main (int argc , const char * * argv )
947994{
948995 struct collapse_context c ;
996+ struct settings default_settings = {
997+ .thp_enabled = THP_MADVISE ,
998+ .thp_defrag = THP_DEFRAG_ALWAYS ,
999+ .shmem_enabled = SHMEM_NEVER ,
1000+ .use_zero_page = 0 ,
1001+ .khugepaged = {
1002+ .defrag = 1 ,
1003+ .alloc_sleep_millisecs = 10 ,
1004+ .scan_sleep_millisecs = 10 ,
1005+ },
1006+ };
1007+ const char * tests = argc == 1 ? "all" : argv [1 ];
9491008
9501009 setbuf (stdout , NULL );
9511010
@@ -959,26 +1018,46 @@ int main(void)
9591018 default_settings .khugepaged .pages_to_scan = hpage_pmd_nr * 8 ;
9601019
9611020 save_settings ();
962- adjust_settings ( );
1021+ push_settings ( & default_settings );
9631022
9641023 alloc_at_fault ();
9651024
966- printf ("\n*** Testing context: khugepaged ***\n" );
967- c .collapse = & khugepaged_collapse ;
968- c .enforce_pte_scan_limits = true;
969-
970- collapse_full (& c );
971- collapse_empty (& c );
972- collapse_single_pte_entry (& c );
973- collapse_max_ptes_none (& c );
974- collapse_swapin_single_pte (& c );
975- collapse_max_ptes_swap (& c );
976- collapse_single_pte_entry_compound (& c );
977- collapse_full_of_compound (& c );
978- collapse_compound_extreme (& c );
979- collapse_fork (& c );
980- collapse_fork_compound (& c );
981- collapse_max_ptes_shared (& c );
1025+ if (!strcmp (tests , "khugepaged" ) || !strcmp (tests , "all" )) {
1026+ printf ("\n*** Testing context: khugepaged ***\n" );
1027+ c .collapse = & khugepaged_collapse ;
1028+ c .enforce_pte_scan_limits = true;
1029+
1030+ collapse_full (& c );
1031+ collapse_empty (& c );
1032+ collapse_single_pte_entry (& c );
1033+ collapse_max_ptes_none (& c );
1034+ collapse_swapin_single_pte (& c );
1035+ collapse_max_ptes_swap (& c );
1036+ collapse_single_pte_entry_compound (& c );
1037+ collapse_full_of_compound (& c );
1038+ collapse_compound_extreme (& c );
1039+ collapse_fork (& c );
1040+ collapse_fork_compound (& c );
1041+ collapse_max_ptes_shared (& c );
1042+ }
1043+ if (!strcmp (tests , "madvise" ) || !strcmp (tests , "all" )) {
1044+ printf ("\n*** Testing context: madvise ***\n" );
1045+ c .collapse = & madvise_collapse ;
1046+ c .enforce_pte_scan_limits = false;
1047+
1048+ collapse_full (& c );
1049+ collapse_empty (& c );
1050+ collapse_single_pte_entry (& c );
1051+ collapse_max_ptes_none (& c );
1052+ collapse_swapin_single_pte (& c );
1053+ collapse_max_ptes_swap (& c );
1054+ collapse_single_pte_entry_compound (& c );
1055+ collapse_full_of_compound (& c );
1056+ collapse_compound_extreme (& c );
1057+ collapse_fork (& c );
1058+ collapse_fork_compound (& c );
1059+ collapse_max_ptes_shared (& c );
1060+ }
9821061
9831062 restore_settings (0 );
9841063}
0 commit comments