75
75
76
76
#define KPF_BYTES 8
77
77
#define PROC_KPAGEFLAGS "/proc/kpageflags"
78
+ #define PROC_KPAGECOUNT "/proc/kpagecount"
78
79
#define PROC_KPAGECGROUP "/proc/kpagecgroup"
79
80
80
81
/* [32-] kernel hacking assistances */
@@ -173,6 +174,7 @@ static pid_t opt_pid; /* process to walk */
173
174
const char * opt_file ; /* file or directory path */
174
175
static uint64_t opt_cgroup ; /* cgroup inode */
175
176
static int opt_list_cgroup ;/* list page cgroup */
177
+ static int opt_list_mapcnt ;/* list page map count */
176
178
static const char * opt_kpageflags ;/* kpageflags file to parse */
177
179
178
180
#define MAX_ADDR_RANGES 1024
@@ -194,6 +196,7 @@ static int page_size;
194
196
195
197
static int pagemap_fd ;
196
198
static int kpageflags_fd ;
199
+ static int kpagecount_fd = -1 ;
197
200
static int kpagecgroup_fd = -1 ;
198
201
199
202
static int opt_hwpoison ;
@@ -298,6 +301,15 @@ static unsigned long kpagecgroup_read(uint64_t *buf,
298
301
return do_u64_read (kpagecgroup_fd , opt_kpageflags , buf , index , pages );
299
302
}
300
303
304
+ static unsigned long kpagecount_read (uint64_t * buf ,
305
+ unsigned long index ,
306
+ unsigned long pages )
307
+ {
308
+ return kpagecount_fd < 0 ? pages :
309
+ do_u64_read (kpagecount_fd , PROC_KPAGECOUNT ,
310
+ buf , index , pages );
311
+ }
312
+
301
313
static unsigned long pagemap_read (uint64_t * buf ,
302
314
unsigned long index ,
303
315
unsigned long pages )
@@ -370,16 +382,18 @@ static char *page_flag_longname(uint64_t flags)
370
382
*/
371
383
372
384
static void show_page_range (unsigned long voffset , unsigned long offset ,
373
- unsigned long size , uint64_t flags , uint64_t cgroup )
385
+ unsigned long size , uint64_t flags ,
386
+ uint64_t cgroup , uint64_t mapcnt )
374
387
{
375
388
static uint64_t flags0 ;
376
389
static uint64_t cgroup0 ;
390
+ static uint64_t mapcnt0 ;
377
391
static unsigned long voff ;
378
392
static unsigned long index ;
379
393
static unsigned long count ;
380
394
381
- if (flags == flags0 && cgroup == cgroup0 && offset == index + count &&
382
- size && voffset == voff + count ) {
395
+ if (flags == flags0 && cgroup == cgroup0 && mapcnt == mapcnt0 &&
396
+ offset == index + count && size && voffset == voff + count ) {
383
397
count += size ;
384
398
return ;
385
399
}
@@ -391,31 +405,37 @@ static void show_page_range(unsigned long voffset, unsigned long offset,
391
405
printf ("%lu\t" , voff );
392
406
if (opt_list_cgroup )
393
407
printf ("@%llu\t" , (unsigned long long )cgroup0 );
408
+ if (opt_list_mapcnt )
409
+ printf ("%lu\t" , mapcnt0 );
394
410
printf ("%lx\t%lx\t%s\n" ,
395
411
index , count , page_flag_name (flags0 ));
396
412
}
397
413
398
414
flags0 = flags ;
399
- cgroup0 = cgroup ;
415
+ cgroup0 = cgroup ;
416
+ mapcnt0 = mapcnt ;
400
417
index = offset ;
401
418
voff = voffset ;
402
419
count = size ;
403
420
}
404
421
405
422
static void flush_page_range (void )
406
423
{
407
- show_page_range (0 , 0 , 0 , 0 , 0 );
424
+ show_page_range (0 , 0 , 0 , 0 , 0 , 0 );
408
425
}
409
426
410
427
static void show_page (unsigned long voffset , unsigned long offset ,
411
- uint64_t flags , uint64_t cgroup )
428
+ uint64_t flags , uint64_t cgroup , uint64_t mapcnt )
412
429
{
413
430
if (opt_pid )
414
431
printf ("%lx\t" , voffset );
415
432
if (opt_file )
416
433
printf ("%lu\t" , voffset );
417
434
if (opt_list_cgroup )
418
435
printf ("@%llu\t" , (unsigned long long )cgroup );
436
+ if (opt_list_mapcnt )
437
+ printf ("%lu\t" , mapcnt );
438
+
419
439
printf ("%lx\t%s\n" , offset , page_flag_name (flags ));
420
440
}
421
441
@@ -599,7 +619,8 @@ static size_t hash_slot(uint64_t flags)
599
619
}
600
620
601
621
static void add_page (unsigned long voffset , unsigned long offset ,
602
- uint64_t flags , uint64_t cgroup , uint64_t pme )
622
+ uint64_t flags , uint64_t cgroup , uint64_t mapcnt ,
623
+ uint64_t pme )
603
624
{
604
625
flags = kpageflags_flags (flags , pme );
605
626
@@ -615,9 +636,9 @@ static void add_page(unsigned long voffset, unsigned long offset,
615
636
unpoison_page (offset );
616
637
617
638
if (opt_list == 1 )
618
- show_page_range (voffset , offset , 1 , flags , cgroup );
639
+ show_page_range (voffset , offset , 1 , flags , cgroup , mapcnt );
619
640
else if (opt_list == 2 )
620
- show_page (voffset , offset , flags , cgroup );
641
+ show_page (voffset , offset , flags , cgroup , mapcnt );
621
642
622
643
nr_pages [hash_slot (flags )]++ ;
623
644
total_pages ++ ;
@@ -631,6 +652,7 @@ static void walk_pfn(unsigned long voffset,
631
652
{
632
653
uint64_t buf [KPAGEFLAGS_BATCH ];
633
654
uint64_t cgi [KPAGEFLAGS_BATCH ];
655
+ uint64_t cnt [KPAGEFLAGS_BATCH ];
634
656
unsigned long batch ;
635
657
unsigned long pages ;
636
658
unsigned long i ;
@@ -654,8 +676,12 @@ static void walk_pfn(unsigned long voffset,
654
676
if (kpagecgroup_read (cgi , index , pages ) != pages )
655
677
fatal ("kpagecgroup returned fewer pages than expected" );
656
678
679
+ if (kpagecount_read (cnt , index , batch ) != pages )
680
+ fatal ("kpagecount returned fewer pages than expected" );
681
+
657
682
for (i = 0 ; i < pages ; i ++ )
658
- add_page (voffset + i , index + i , buf [i ], cgi [i ], pme );
683
+ add_page (voffset + i , index + i ,
684
+ buf [i ], cgi [i ], cnt [i ], pme );
659
685
660
686
index += pages ;
661
687
count -= pages ;
@@ -673,9 +699,10 @@ static void walk_swap(unsigned long voffset, uint64_t pme)
673
699
return ;
674
700
675
701
if (opt_list == 1 )
676
- show_page_range (voffset , pagemap_swap_offset (pme ), 1 , flags , 0 );
702
+ show_page_range (voffset , pagemap_swap_offset (pme ),
703
+ 1 , flags , 0 , 0 );
677
704
else if (opt_list == 2 )
678
- show_page (voffset , pagemap_swap_offset (pme ), flags , 0 );
705
+ show_page (voffset , pagemap_swap_offset (pme ), flags , 0 , 0 );
679
706
680
707
nr_pages [hash_slot (flags )]++ ;
681
708
total_pages ++ ;
@@ -789,6 +816,7 @@ static void usage(void)
789
816
" -l|--list Show page details in ranges\n"
790
817
" -L|--list-each Show page details one by one\n"
791
818
" -C|--list-cgroup Show cgroup inode for pages\n"
819
+ " -M|--list-mapcnt Show page map count\n"
792
820
" -N|--no-summary Don't show summary info\n"
793
821
" -X|--hwpoison hwpoison pages\n"
794
822
" -x|--unpoison unpoison pages\n"
@@ -925,6 +953,7 @@ static void walk_file(const char *name, const struct stat *st)
925
953
uint8_t vec [PAGEMAP_BATCH ];
926
954
uint64_t buf [PAGEMAP_BATCH ], flags ;
927
955
uint64_t cgroup = 0 ;
956
+ uint64_t mapcnt = 0 ;
928
957
unsigned long nr_pages , pfn , i ;
929
958
off_t off , end = st -> st_size ;
930
959
int fd ;
@@ -984,13 +1013,15 @@ static void walk_file(const char *name, const struct stat *st)
984
1013
continue ;
985
1014
if (!kpagecgroup_read (& cgroup , pfn , 1 ))
986
1015
fatal ("kpagecgroup_read failed" );
1016
+ if (!kpagecount_read (& mapcnt , pfn , 1 ))
1017
+ fatal ("kpagecount_read failed" );
987
1018
if (first && opt_list ) {
988
1019
first = 0 ;
989
1020
flush_page_range ();
990
1021
show_file (name , st );
991
1022
}
992
1023
add_page (off / page_size + i , pfn ,
993
- flags , cgroup , buf [i ]);
1024
+ flags , cgroup , mapcnt , buf [i ]);
994
1025
}
995
1026
}
996
1027
@@ -1193,6 +1224,7 @@ static const struct option opts[] = {
1193
1224
{ "list" , 0 , NULL , 'l' },
1194
1225
{ "list-each" , 0 , NULL , 'L' },
1195
1226
{ "list-cgroup" , 0 , NULL , 'C' },
1227
+ { "list-mapcnt" , 0 , NULL , 'M' },
1196
1228
{ "no-summary" , 0 , NULL , 'N' },
1197
1229
{ "hwpoison" , 0 , NULL , 'X' },
1198
1230
{ "unpoison" , 0 , NULL , 'x' },
@@ -1208,7 +1240,8 @@ int main(int argc, char *argv[])
1208
1240
page_size = getpagesize ();
1209
1241
1210
1242
while ((c = getopt_long (argc , argv ,
1211
- "rp:f:a:b:d:c:ClLNXxF:h" , opts , NULL )) != -1 ) {
1243
+ "rp:f:a:b:d:c:ClLMNXxF:h" ,
1244
+ opts , NULL )) != -1 ) {
1212
1245
switch (c ) {
1213
1246
case 'r' :
1214
1247
opt_raw = 1 ;
@@ -1240,6 +1273,9 @@ int main(int argc, char *argv[])
1240
1273
case 'L' :
1241
1274
opt_list = 2 ;
1242
1275
break ;
1276
+ case 'M' :
1277
+ opt_list_mapcnt = 1 ;
1278
+ break ;
1243
1279
case 'N' :
1244
1280
opt_no_summary = 1 ;
1245
1281
break ;
@@ -1269,12 +1305,18 @@ int main(int argc, char *argv[])
1269
1305
if (opt_cgroup || opt_list_cgroup )
1270
1306
kpagecgroup_fd = checked_open (PROC_KPAGECGROUP , O_RDONLY );
1271
1307
1308
+ if (opt_list && opt_list_mapcnt )
1309
+ kpagecount_fd = checked_open (PROC_KPAGECOUNT , O_RDONLY );
1310
+
1272
1311
if (opt_list && opt_pid )
1273
1312
printf ("voffset\t" );
1274
1313
if (opt_list && opt_file )
1275
1314
printf ("foffset\t" );
1276
1315
if (opt_list && opt_list_cgroup )
1277
1316
printf ("cgroup\t" );
1317
+ if (opt_list && opt_list_mapcnt )
1318
+ printf ("map-cnt\t" );
1319
+
1278
1320
if (opt_list == 1 )
1279
1321
printf ("offset\tlen\tflags\n" );
1280
1322
if (opt_list == 2 )
@@ -1296,5 +1338,8 @@ int main(int argc, char *argv[])
1296
1338
1297
1339
show_summary ();
1298
1340
1341
+ if (opt_list_mapcnt )
1342
+ close (kpagecount_fd );
1343
+
1299
1344
return 0 ;
1300
1345
}
0 commit comments