summaryrefslogtreecommitdiffstats
path: root/tools/vm
diff options
context:
space:
mode:
authorKonstantin Khlebnikov <koct9i@gmail.com>2016-03-17 17:18:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-17 18:09:34 -0400
commit075db1502ffd4ff8c58020167484a6e123ae01a3 (patch)
tree34e01d7a4e1f7ab95658ba7932a0c06b582ae616 /tools/vm
parentaccf62422b3a67fce8ce086aa81c8300ddbf42be (diff)
tools/vm/page-types.c: add memory cgroup dumping and filtering
This adds two command line keys: -c|--cgroup path|@inode Walk only pages owned by this memory cgroup -C|--list-cgroup Show memory cgroup inodes [vdavydov@virtuozzo.com: opt_cgroup should be uint64_t. Fix conflicts with "tools/vm/page-types.c: support swap entry"] Signed-off-by: Konstantin Khlebnikov <koct9i@gmail.com> Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Reviewed-by: Vladimir Davydov <vdavydov@virtuozzo.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'tools/vm')
-rw-r--r--tools/vm/page-types.c99
1 files changed, 84 insertions, 15 deletions
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index ec62ab4d8b55..dab61c377f54 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -75,6 +75,7 @@
75 75
76#define KPF_BYTES 8 76#define KPF_BYTES 8
77#define PROC_KPAGEFLAGS "/proc/kpageflags" 77#define PROC_KPAGEFLAGS "/proc/kpageflags"
78#define PROC_KPAGECGROUP "/proc/kpagecgroup"
78 79
79/* [32-] kernel hacking assistances */ 80/* [32-] kernel hacking assistances */
80#define KPF_RESERVED 32 81#define KPF_RESERVED 32
@@ -168,7 +169,9 @@ static int opt_raw; /* for kernel developers */
168static int opt_list; /* list pages (in ranges) */ 169static int opt_list; /* list pages (in ranges) */
169static int opt_no_summary; /* don't show summary */ 170static int opt_no_summary; /* don't show summary */
170static pid_t opt_pid; /* process to walk */ 171static pid_t opt_pid; /* process to walk */
171const char * opt_file; 172const char * opt_file; /* file or directory path */
173static uint64_t opt_cgroup; /* cgroup inode */
174static int opt_list_cgroup;/* list page cgroup */
172 175
173#define MAX_ADDR_RANGES 1024 176#define MAX_ADDR_RANGES 1024
174static int nr_addr_ranges; 177static int nr_addr_ranges;
@@ -189,6 +192,7 @@ static int page_size;
189 192
190static int pagemap_fd; 193static int pagemap_fd;
191static int kpageflags_fd; 194static int kpageflags_fd;
195static int kpagecgroup_fd = -1;
192 196
193static int opt_hwpoison; 197static int opt_hwpoison;
194static int opt_unpoison; 198static int opt_unpoison;
@@ -282,6 +286,16 @@ static unsigned long kpageflags_read(uint64_t *buf,
282 return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages); 286 return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages);
283} 287}
284 288
289static unsigned long kpagecgroup_read(uint64_t *buf,
290 unsigned long index,
291 unsigned long pages)
292{
293 if (kpagecgroup_fd < 0)
294 return pages;
295
296 return do_u64_read(kpagecgroup_fd, PROC_KPAGEFLAGS, buf, index, pages);
297}
298
285static unsigned long pagemap_read(uint64_t *buf, 299static unsigned long pagemap_read(uint64_t *buf,
286 unsigned long index, 300 unsigned long index,
287 unsigned long pages) 301 unsigned long pages)
@@ -354,14 +368,15 @@ static char *page_flag_longname(uint64_t flags)
354 */ 368 */
355 369
356static void show_page_range(unsigned long voffset, unsigned long offset, 370static void show_page_range(unsigned long voffset, unsigned long offset,
357 unsigned long size, uint64_t flags) 371 unsigned long size, uint64_t flags, uint64_t cgroup)
358{ 372{
359 static uint64_t flags0; 373 static uint64_t flags0;
374 static uint64_t cgroup0;
360 static unsigned long voff; 375 static unsigned long voff;
361 static unsigned long index; 376 static unsigned long index;
362 static unsigned long count; 377 static unsigned long count;
363 378
364 if (flags == flags0 && offset == index + count && 379 if (flags == flags0 && cgroup == cgroup0 && offset == index + count &&
365 size && voffset == voff + count) { 380 size && voffset == voff + count) {
366 count += size; 381 count += size;
367 return; 382 return;
@@ -372,11 +387,14 @@ static void show_page_range(unsigned long voffset, unsigned long offset,
372 printf("%lx\t", voff); 387 printf("%lx\t", voff);
373 if (opt_file) 388 if (opt_file)
374 printf("%lu\t", voff); 389 printf("%lu\t", voff);
390 if (opt_list_cgroup)
391 printf("@%llu\t", (unsigned long long)cgroup0);
375 printf("%lx\t%lx\t%s\n", 392 printf("%lx\t%lx\t%s\n",
376 index, count, page_flag_name(flags0)); 393 index, count, page_flag_name(flags0));
377 } 394 }
378 395
379 flags0 = flags; 396 flags0 = flags;
397 cgroup0= cgroup;
380 index = offset; 398 index = offset;
381 voff = voffset; 399 voff = voffset;
382 count = size; 400 count = size;
@@ -384,16 +402,18 @@ static void show_page_range(unsigned long voffset, unsigned long offset,
384 402
385static void flush_page_range(void) 403static void flush_page_range(void)
386{ 404{
387 show_page_range(0, 0, 0, 0); 405 show_page_range(0, 0, 0, 0, 0);
388} 406}
389 407
390static void show_page(unsigned long voffset, 408static void show_page(unsigned long voffset, unsigned long offset,
391 unsigned long offset, uint64_t flags) 409 uint64_t flags, uint64_t cgroup)
392{ 410{
393 if (opt_pid) 411 if (opt_pid)
394 printf("%lx\t", voffset); 412 printf("%lx\t", voffset);
395 if (opt_file) 413 if (opt_file)
396 printf("%lu\t", voffset); 414 printf("%lu\t", voffset);
415 if (opt_list_cgroup)
416 printf("@%llu\t", (unsigned long long)cgroup);
397 printf("%lx\t%s\n", offset, page_flag_name(flags)); 417 printf("%lx\t%s\n", offset, page_flag_name(flags));
398} 418}
399 419
@@ -576,23 +596,26 @@ static size_t hash_slot(uint64_t flags)
576 exit(EXIT_FAILURE); 596 exit(EXIT_FAILURE);
577} 597}
578 598
579static void add_page(unsigned long voffset, 599static void add_page(unsigned long voffset, unsigned long offset,
580 unsigned long offset, uint64_t flags, uint64_t pme) 600 uint64_t flags, uint64_t cgroup, uint64_t pme)
581{ 601{
582 flags = kpageflags_flags(flags, pme); 602 flags = kpageflags_flags(flags, pme);
583 603
584 if (!bit_mask_ok(flags)) 604 if (!bit_mask_ok(flags))
585 return; 605 return;
586 606
607 if (opt_cgroup && cgroup != (uint64_t)opt_cgroup)
608 return;
609
587 if (opt_hwpoison) 610 if (opt_hwpoison)
588 hwpoison_page(offset); 611 hwpoison_page(offset);
589 if (opt_unpoison) 612 if (opt_unpoison)
590 unpoison_page(offset); 613 unpoison_page(offset);
591 614
592 if (opt_list == 1) 615 if (opt_list == 1)
593 show_page_range(voffset, offset, 1, flags); 616 show_page_range(voffset, offset, 1, flags, cgroup);
594 else if (opt_list == 2) 617 else if (opt_list == 2)
595 show_page(voffset, offset, flags); 618 show_page(voffset, offset, flags, cgroup);
596 619
597 nr_pages[hash_slot(flags)]++; 620 nr_pages[hash_slot(flags)]++;
598 total_pages++; 621 total_pages++;
@@ -605,18 +628,24 @@ static void walk_pfn(unsigned long voffset,
605 uint64_t pme) 628 uint64_t pme)
606{ 629{
607 uint64_t buf[KPAGEFLAGS_BATCH]; 630 uint64_t buf[KPAGEFLAGS_BATCH];
631 uint64_t cgi[KPAGEFLAGS_BATCH];
608 unsigned long batch; 632 unsigned long batch;
609 unsigned long pages; 633 unsigned long pages;
610 unsigned long i; 634 unsigned long i;
611 635
636 memset(cgi, 0, sizeof cgi);
637
612 while (count) { 638 while (count) {
613 batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH); 639 batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH);
614 pages = kpageflags_read(buf, index, batch); 640 pages = kpageflags_read(buf, index, batch);
615 if (pages == 0) 641 if (pages == 0)
616 break; 642 break;
617 643
644 if (kpagecgroup_read(cgi, index, pages) != pages)
645 fatal("kpagecgroup returned fewer pages than expected");
646
618 for (i = 0; i < pages; i++) 647 for (i = 0; i < pages; i++)
619 add_page(voffset + i, index + i, buf[i], pme); 648 add_page(voffset + i, index + i, buf[i], cgi[i], pme);
620 649
621 index += pages; 650 index += pages;
622 count -= pages; 651 count -= pages;
@@ -630,10 +659,13 @@ static void walk_swap(unsigned long voffset, uint64_t pme)
630 if (!bit_mask_ok(flags)) 659 if (!bit_mask_ok(flags))
631 return; 660 return;
632 661
662 if (opt_cgroup)
663 return;
664
633 if (opt_list == 1) 665 if (opt_list == 1)
634 show_page_range(voffset, pagemap_swap_offset(pme), 1, flags); 666 show_page_range(voffset, pagemap_swap_offset(pme), 1, flags, 0);
635 else if (opt_list == 2) 667 else if (opt_list == 2)
636 show_page(voffset, pagemap_swap_offset(pme), flags); 668 show_page(voffset, pagemap_swap_offset(pme), flags, 0);
637 669
638 nr_pages[hash_slot(flags)]++; 670 nr_pages[hash_slot(flags)]++;
639 total_pages++; 671 total_pages++;
@@ -741,10 +773,12 @@ static void usage(void)
741" -d|--describe flags Describe flags\n" 773" -d|--describe flags Describe flags\n"
742" -a|--addr addr-spec Walk a range of pages\n" 774" -a|--addr addr-spec Walk a range of pages\n"
743" -b|--bits bits-spec Walk pages with specified bits\n" 775" -b|--bits bits-spec Walk pages with specified bits\n"
776" -c|--cgroup path|@inode Walk pages within memory cgroup\n"
744" -p|--pid pid Walk process address space\n" 777" -p|--pid pid Walk process address space\n"
745" -f|--file filename Walk file address space\n" 778" -f|--file filename Walk file address space\n"
746" -l|--list Show page details in ranges\n" 779" -l|--list Show page details in ranges\n"
747" -L|--list-each Show page details one by one\n" 780" -L|--list-each Show page details one by one\n"
781" -C|--list-cgroup Show cgroup inode for pages\n"
748" -N|--no-summary Don't show summary info\n" 782" -N|--no-summary Don't show summary info\n"
749" -X|--hwpoison hwpoison pages\n" 783" -X|--hwpoison hwpoison pages\n"
750" -x|--unpoison unpoison pages\n" 784" -x|--unpoison unpoison pages\n"
@@ -879,6 +913,7 @@ static void walk_file(const char *name, const struct stat *st)
879{ 913{
880 uint8_t vec[PAGEMAP_BATCH]; 914 uint8_t vec[PAGEMAP_BATCH];
881 uint64_t buf[PAGEMAP_BATCH], flags; 915 uint64_t buf[PAGEMAP_BATCH], flags;
916 uint64_t cgroup = 0;
882 unsigned long nr_pages, pfn, i; 917 unsigned long nr_pages, pfn, i;
883 off_t off, end = st->st_size; 918 off_t off, end = st->st_size;
884 int fd; 919 int fd;
@@ -936,12 +971,15 @@ got_sigbus:
936 continue; 971 continue;
937 if (!kpageflags_read(&flags, pfn, 1)) 972 if (!kpageflags_read(&flags, pfn, 1))
938 continue; 973 continue;
974 if (!kpagecgroup_read(&cgroup, pfn, 1))
975 fatal("kpagecgroup_read failed");
939 if (first && opt_list) { 976 if (first && opt_list) {
940 first = 0; 977 first = 0;
941 flush_page_range(); 978 flush_page_range();
942 show_file(name, st); 979 show_file(name, st);
943 } 980 }
944 add_page(off / page_size + i, pfn, flags, buf[i]); 981 add_page(off / page_size + i, pfn,
982 flags, cgroup, buf[i]);
945 } 983 }
946 } 984 }
947 985
@@ -993,6 +1031,24 @@ static void parse_file(const char *name)
993 opt_file = name; 1031 opt_file = name;
994} 1032}
995 1033
1034static void parse_cgroup(const char *path)
1035{
1036 if (path[0] == '@') {
1037 opt_cgroup = parse_number(path + 1);
1038 return;
1039 }
1040
1041 struct stat st;
1042
1043 if (stat(path, &st))
1044 fatal("stat failed: %s: %m\n", path);
1045
1046 if (!S_ISDIR(st.st_mode))
1047 fatal("cgroup supposed to be a directory: %s\n", path);
1048
1049 opt_cgroup = st.st_ino;
1050}
1051
996static void parse_addr_range(const char *optarg) 1052static void parse_addr_range(const char *optarg)
997{ 1053{
998 unsigned long offset; 1054 unsigned long offset;
@@ -1116,9 +1172,11 @@ static const struct option opts[] = {
1116 { "file" , 1, NULL, 'f' }, 1172 { "file" , 1, NULL, 'f' },
1117 { "addr" , 1, NULL, 'a' }, 1173 { "addr" , 1, NULL, 'a' },
1118 { "bits" , 1, NULL, 'b' }, 1174 { "bits" , 1, NULL, 'b' },
1175 { "cgroup" , 1, NULL, 'c' },
1119 { "describe" , 1, NULL, 'd' }, 1176 { "describe" , 1, NULL, 'd' },
1120 { "list" , 0, NULL, 'l' }, 1177 { "list" , 0, NULL, 'l' },
1121 { "list-each" , 0, NULL, 'L' }, 1178 { "list-each" , 0, NULL, 'L' },
1179 { "list-cgroup", 0, NULL, 'C' },
1122 { "no-summary", 0, NULL, 'N' }, 1180 { "no-summary", 0, NULL, 'N' },
1123 { "hwpoison" , 0, NULL, 'X' }, 1181 { "hwpoison" , 0, NULL, 'X' },
1124 { "unpoison" , 0, NULL, 'x' }, 1182 { "unpoison" , 0, NULL, 'x' },
@@ -1133,7 +1191,7 @@ int main(int argc, char *argv[])
1133 page_size = getpagesize(); 1191 page_size = getpagesize();
1134 1192
1135 while ((c = getopt_long(argc, argv, 1193 while ((c = getopt_long(argc, argv,
1136 "rp:f:a:b:d:lLNXxh", opts, NULL)) != -1) { 1194 "rp:f:a:b:d:c:ClLNXxh", opts, NULL)) != -1) {
1137 switch (c) { 1195 switch (c) {
1138 case 'r': 1196 case 'r':
1139 opt_raw = 1; 1197 opt_raw = 1;
@@ -1150,6 +1208,12 @@ int main(int argc, char *argv[])
1150 case 'b': 1208 case 'b':
1151 parse_bits_mask(optarg); 1209 parse_bits_mask(optarg);
1152 break; 1210 break;
1211 case 'c':
1212 parse_cgroup(optarg);
1213 break;
1214 case 'C':
1215 opt_list_cgroup = 1;
1216 break;
1153 case 'd': 1217 case 'd':
1154 describe_flags(optarg); 1218 describe_flags(optarg);
1155 exit(0); 1219 exit(0);
@@ -1179,10 +1243,15 @@ int main(int argc, char *argv[])
1179 } 1243 }
1180 } 1244 }
1181 1245
1246 if (opt_cgroup || opt_list_cgroup)
1247 kpagecgroup_fd = checked_open(PROC_KPAGECGROUP, O_RDONLY);
1248
1182 if (opt_list && opt_pid) 1249 if (opt_list && opt_pid)
1183 printf("voffset\t"); 1250 printf("voffset\t");
1184 if (opt_list && opt_file) 1251 if (opt_list && opt_file)
1185 printf("foffset\t"); 1252 printf("foffset\t");
1253 if (opt_list && opt_list_cgroup)
1254 printf("cgroup\t");
1186 if (opt_list == 1) 1255 if (opt_list == 1)
1187 printf("offset\tlen\tflags\n"); 1256 printf("offset\tlen\tflags\n");
1188 if (opt_list == 2) 1257 if (opt_list == 2)