@@ -23,6 +23,11 @@ struct ksm_sysfs {
23
23
unsigned long use_zero_pages ;
24
24
};
25
25
26
+ enum ksm_test_name {
27
+ CHECK_KSM_MERGE ,
28
+ CHECK_KSM_UNMERGE
29
+ };
30
+
26
31
static int ksm_write_sysfs (const char * file_path , unsigned long val )
27
32
{
28
33
FILE * f = fopen (file_path , "w" );
@@ -75,7 +80,12 @@ static int str_to_prot(char *prot_str)
75
80
76
81
static void print_help (void )
77
82
{
78
- printf ("usage: ksm_tests [-h] [-a prot] [-p page_count] [-l timeout]\n" );
83
+ printf ("usage: ksm_tests [-h] <test type> [-a prot] [-p page_count] [-l timeout]\n" );
84
+
85
+ printf ("Supported <test type>:\n"
86
+ " -M (page merging)\n"
87
+ " -U (page unmerging)\n\n" );
88
+
79
89
printf (" -a: specify the access protections of pages.\n"
80
90
" <prot> must be of the form [rwx].\n"
81
91
" Default: %s\n" , KSM_PROT_STR_DEFAULT );
@@ -239,6 +249,46 @@ static int check_ksm_merge(int mapping, int prot, long page_count, int timeout,
239
249
return KSFT_FAIL ;
240
250
}
241
251
252
+ static int check_ksm_unmerge (int mapping , int prot , int timeout , size_t page_size )
253
+ {
254
+ void * map_ptr ;
255
+ struct timespec start_time ;
256
+ int page_count = 2 ;
257
+
258
+ if (clock_gettime (CLOCK_MONOTONIC_RAW , & start_time )) {
259
+ perror ("clock_gettime" );
260
+ return KSFT_FAIL ;
261
+ }
262
+
263
+ /* fill pages with the same data and merge them */
264
+ map_ptr = allocate_memory (NULL , prot , mapping , '*' , page_size * page_count );
265
+ if (!map_ptr )
266
+ return KSFT_FAIL ;
267
+
268
+ if (ksm_merge_pages (map_ptr , page_size * page_count , start_time , timeout ))
269
+ goto err_out ;
270
+
271
+ /* change 1 byte in each of the 2 pages -- KSM must automatically unmerge them */
272
+ memset (map_ptr , '-' , 1 );
273
+ memset (map_ptr + page_size , '+' , 1 );
274
+
275
+ /* get at least 1 scan, so KSM can detect that the pages were modified */
276
+ if (ksm_do_scan (1 , start_time , timeout ))
277
+ goto err_out ;
278
+
279
+ /* check that unmerging was successful and 0 pages are currently merged */
280
+ if (assert_ksm_pages_count (0 )) {
281
+ printf ("OK\n" );
282
+ munmap (map_ptr , page_size * page_count );
283
+ return KSFT_PASS ;
284
+ }
285
+
286
+ err_out :
287
+ printf ("Not OK\n" );
288
+ munmap (map_ptr , page_size * page_count );
289
+ return KSFT_FAIL ;
290
+ }
291
+
242
292
int main (int argc , char * argv [])
243
293
{
244
294
int ret , opt ;
@@ -247,8 +297,9 @@ int main(int argc, char *argv[])
247
297
long page_count = KSM_PAGE_COUNT_DEFAULT ;
248
298
size_t page_size = sysconf (_SC_PAGESIZE );
249
299
struct ksm_sysfs ksm_sysfs_old ;
300
+ int test_name = CHECK_KSM_MERGE ;
250
301
251
- while ((opt = getopt (argc , argv , "ha:p:l:" )) != -1 ) {
302
+ while ((opt = getopt (argc , argv , "ha:p:l:MU " )) != -1 ) {
252
303
switch (opt ) {
253
304
case 'a' :
254
305
prot = str_to_prot (optarg );
@@ -270,6 +321,11 @@ int main(int argc, char *argv[])
270
321
case 'h' :
271
322
print_help ();
272
323
break ;
324
+ case 'M' :
325
+ break ;
326
+ case 'U' :
327
+ test_name = CHECK_KSM_UNMERGE ;
328
+ break ;
273
329
default :
274
330
return KSFT_FAIL ;
275
331
}
@@ -294,8 +350,16 @@ int main(int argc, char *argv[])
294
350
ksm_write_sysfs (KSM_FP ("pages_to_scan" ), page_count ))
295
351
return KSFT_FAIL ;
296
352
297
- ret = check_ksm_merge (MAP_PRIVATE | MAP_ANONYMOUS , prot , page_count , ksm_scan_limit_sec ,
298
- page_size );
353
+ switch (test_name ) {
354
+ case CHECK_KSM_MERGE :
355
+ ret = check_ksm_merge (MAP_PRIVATE | MAP_ANONYMOUS , prot , page_count ,
356
+ ksm_scan_limit_sec , page_size );
357
+ break ;
358
+ case CHECK_KSM_UNMERGE :
359
+ ret = check_ksm_unmerge (MAP_PRIVATE | MAP_ANONYMOUS , prot , ksm_scan_limit_sec ,
360
+ page_size );
361
+ break ;
362
+ }
299
363
300
364
if (ksm_restore (& ksm_sysfs_old )) {
301
365
printf ("Cannot restore default tunables\n" );
0 commit comments