16
16
#include <sys/mount.h>
17
17
#include <malloc.h>
18
18
#include <stdbool.h>
19
+ #include <time.h>
19
20
#include "vm_util.h"
20
21
#include "../kselftest.h"
21
22
@@ -24,10 +25,11 @@ unsigned int pageshift;
24
25
uint64_t pmd_pagesize ;
25
26
26
27
#define SPLIT_DEBUGFS "/sys/kernel/debug/split_huge_pages"
28
+ #define SMAP_PATH "/proc/self/smaps"
27
29
#define INPUT_MAX 80
28
30
29
- #define PID_FMT "%d,0x%lx,0x%lx"
30
- #define PATH_FMT "%s,0x%lx,0x%lx"
31
+ #define PID_FMT "%d,0x%lx,0x%lx,%d "
32
+ #define PATH_FMT "%s,0x%lx,0x%lx,%d "
31
33
32
34
#define PFN_MASK ((1UL<<55)-1)
33
35
#define KPF_THP (1UL<<22)
@@ -102,7 +104,7 @@ void split_pmd_thp(void)
102
104
103
105
/* split all THPs */
104
106
write_debugfs (PID_FMT , getpid (), (uint64_t )one_page ,
105
- (uint64_t )one_page + len );
107
+ (uint64_t )one_page + len , 0 );
106
108
107
109
for (i = 0 ; i < len ; i ++ )
108
110
if (one_page [i ] != (char )i )
@@ -177,7 +179,7 @@ void split_pte_mapped_thp(void)
177
179
178
180
/* split all remapped THPs */
179
181
write_debugfs (PID_FMT , getpid (), (uint64_t )pte_mapped ,
180
- (uint64_t )pte_mapped + pagesize * 4 );
182
+ (uint64_t )pte_mapped + pagesize * 4 , 0 );
181
183
182
184
/* smap does not show THPs after mremap, use kpageflags instead */
183
185
thp_size = 0 ;
@@ -237,7 +239,7 @@ void split_file_backed_thp(void)
237
239
}
238
240
239
241
/* split the file-backed THP */
240
- write_debugfs (PATH_FMT , testfile , pgoff_start , pgoff_end );
242
+ write_debugfs (PATH_FMT , testfile , pgoff_start , pgoff_end , 0 );
241
243
242
244
status = unlink (testfile );
243
245
if (status ) {
@@ -265,26 +267,180 @@ void split_file_backed_thp(void)
265
267
ksft_exit_fail_msg ("Error occurred\n" );
266
268
}
267
269
270
+ bool prepare_thp_fs (const char * xfs_path , char * thp_fs_template ,
271
+ const char * * thp_fs_loc )
272
+ {
273
+ if (xfs_path ) {
274
+ * thp_fs_loc = xfs_path ;
275
+ return false;
276
+ }
277
+
278
+ * thp_fs_loc = mkdtemp (thp_fs_template );
279
+
280
+ if (!* thp_fs_loc )
281
+ ksft_exit_fail_msg ("cannot create temp folder\n" );
282
+
283
+ return true;
284
+ }
285
+
286
+ void cleanup_thp_fs (const char * thp_fs_loc , bool created_tmp )
287
+ {
288
+ int status ;
289
+
290
+ if (!created_tmp )
291
+ return ;
292
+
293
+ status = rmdir (thp_fs_loc );
294
+ if (status )
295
+ ksft_exit_fail_msg ("cannot remove tmp dir: %s\n" ,
296
+ strerror (errno ));
297
+ }
298
+
299
+ int create_pagecache_thp_and_fd (const char * testfile , size_t fd_size , int * fd ,
300
+ char * * addr )
301
+ {
302
+ size_t i ;
303
+ int dummy ;
304
+
305
+ srand (time (NULL ));
306
+
307
+ * fd = open (testfile , O_CREAT | O_RDWR , 0664 );
308
+ if (* fd == -1 )
309
+ ksft_exit_fail_msg ("Failed to create a file at %s\n" , testfile );
310
+
311
+ for (i = 0 ; i < fd_size ; i ++ ) {
312
+ unsigned char byte = (unsigned char )i ;
313
+
314
+ write (* fd , & byte , sizeof (byte ));
315
+ }
316
+ close (* fd );
317
+ sync ();
318
+ * fd = open ("/proc/sys/vm/drop_caches" , O_WRONLY );
319
+ if (* fd == -1 ) {
320
+ ksft_perror ("open drop_caches" );
321
+ goto err_out_unlink ;
322
+ }
323
+ if (write (* fd , "3" , 1 ) != 1 ) {
324
+ ksft_perror ("write to drop_caches" );
325
+ goto err_out_unlink ;
326
+ }
327
+ close (* fd );
328
+
329
+ * fd = open (testfile , O_RDWR );
330
+ if (* fd == -1 ) {
331
+ ksft_perror ("Failed to open testfile\n" );
332
+ goto err_out_unlink ;
333
+ }
334
+
335
+ * addr = mmap (NULL , fd_size , PROT_READ |PROT_WRITE , MAP_SHARED , * fd , 0 );
336
+ if (* addr == (char * )-1 ) {
337
+ ksft_perror ("cannot mmap" );
338
+ goto err_out_close ;
339
+ }
340
+ madvise (* addr , fd_size , MADV_HUGEPAGE );
341
+
342
+ for (size_t i = 0 ; i < fd_size ; i ++ )
343
+ dummy += * (* addr + i );
344
+
345
+ if (!check_huge_file (* addr , fd_size / pmd_pagesize , pmd_pagesize )) {
346
+ ksft_print_msg ("No large pagecache folio generated, please provide a filesystem supporting large folio\n" );
347
+ munmap (* addr , fd_size );
348
+ close (* fd );
349
+ unlink (testfile );
350
+ ksft_test_result_skip ("Pagecache folio split skipped\n" );
351
+ return -2 ;
352
+ }
353
+ return 0 ;
354
+ err_out_close :
355
+ close (* fd );
356
+ err_out_unlink :
357
+ unlink (testfile );
358
+ ksft_exit_fail_msg ("Failed to create large pagecache folios\n" );
359
+ return -1 ;
360
+ }
361
+
362
+ void split_thp_in_pagecache_to_order (size_t fd_size , int order , const char * fs_loc )
363
+ {
364
+ int fd ;
365
+ char * addr ;
366
+ size_t i ;
367
+ char testfile [INPUT_MAX ];
368
+ int err = 0 ;
369
+
370
+ err = snprintf (testfile , INPUT_MAX , "%s/test" , fs_loc );
371
+
372
+ if (err < 0 )
373
+ ksft_exit_fail_msg ("cannot generate right test file name\n" );
374
+
375
+ err = create_pagecache_thp_and_fd (testfile , fd_size , & fd , & addr );
376
+ if (err )
377
+ return ;
378
+ err = 0 ;
379
+
380
+ write_debugfs (PID_FMT , getpid (), (uint64_t )addr , (uint64_t )addr + fd_size , order );
381
+
382
+ for (i = 0 ; i < fd_size ; i ++ )
383
+ if (* (addr + i ) != (char )i ) {
384
+ ksft_print_msg ("%lu byte corrupted in the file\n" , i );
385
+ err = EXIT_FAILURE ;
386
+ goto out ;
387
+ }
388
+
389
+ if (!check_huge_file (addr , 0 , pmd_pagesize )) {
390
+ ksft_print_msg ("Still FilePmdMapped not split\n" );
391
+ err = EXIT_FAILURE ;
392
+ goto out ;
393
+ }
394
+
395
+ out :
396
+ munmap (addr , fd_size );
397
+ close (fd );
398
+ unlink (testfile );
399
+ if (err )
400
+ ksft_exit_fail_msg ("Split PMD-mapped pagecache folio to order %d failed\n" , order );
401
+ ksft_test_result_pass ("Split PMD-mapped pagecache folio to order %d passed\n" , order );
402
+ }
403
+
268
404
int main (int argc , char * * argv )
269
405
{
406
+ int i ;
407
+ size_t fd_size ;
408
+ char * optional_xfs_path = NULL ;
409
+ char fs_loc_template [] = "/tmp/thp_fs_XXXXXX" ;
410
+ const char * fs_loc ;
411
+ bool created_tmp ;
412
+
270
413
ksft_print_header ();
271
414
272
415
if (geteuid () != 0 ) {
273
416
ksft_print_msg ("Please run the benchmark as root\n" );
274
417
ksft_finished ();
275
418
}
276
419
277
- ksft_set_plan (3 );
420
+ if (argc > 1 )
421
+ optional_xfs_path = argv [1 ];
422
+
423
+ ksft_set_plan (3 + 9 );
278
424
279
425
pagesize = getpagesize ();
280
426
pageshift = ffs (pagesize ) - 1 ;
281
427
pmd_pagesize = read_pmd_pagesize ();
282
428
if (!pmd_pagesize )
283
429
ksft_exit_fail_msg ("Reading PMD pagesize failed\n" );
284
430
431
+ fd_size = 2 * pmd_pagesize ;
432
+
285
433
split_pmd_thp ();
286
434
split_pte_mapped_thp ();
287
435
split_file_backed_thp ();
288
436
437
+ created_tmp = prepare_thp_fs (optional_xfs_path , fs_loc_template ,
438
+ & fs_loc );
439
+ for (i = 8 ; i >= 0 ; i -- )
440
+ split_thp_in_pagecache_to_order (fd_size , i , fs_loc );
441
+ cleanup_thp_fs (fs_loc , created_tmp );
442
+
289
443
ksft_finished ();
444
+
445
+ return 0 ;
290
446
}
0 commit comments