|
@@ -78,6 +78,8 @@
|
|
|
#define PROC_KPAGECOUNT "/proc/kpagecount"
|
|
|
#define PROC_KPAGECGROUP "/proc/kpagecgroup"
|
|
|
|
|
|
+#define SYS_KERNEL_MM_PAGE_IDLE "/sys/kernel/mm/page_idle/bitmap"
|
|
|
+
|
|
|
/* [32-] kernel hacking assistances */
|
|
|
#define KPF_RESERVED 32
|
|
|
#define KPF_MLOCKED 33
|
|
@@ -169,6 +171,7 @@ static const char * const debugfs_known_mountpoints[] = {
|
|
|
|
|
|
static int opt_raw; /* for kernel developers */
|
|
|
static int opt_list; /* list pages (in ranges) */
|
|
|
+static int opt_mark_idle; /* set accessed bit */
|
|
|
static int opt_no_summary; /* don't show summary */
|
|
|
static pid_t opt_pid; /* process to walk */
|
|
|
const char *opt_file; /* file or directory path */
|
|
@@ -198,6 +201,7 @@ static int pagemap_fd;
|
|
|
static int kpageflags_fd;
|
|
|
static int kpagecount_fd = -1;
|
|
|
static int kpagecgroup_fd = -1;
|
|
|
+static int page_idle_fd = -1;
|
|
|
|
|
|
static int opt_hwpoison;
|
|
|
static int opt_unpoison;
|
|
@@ -587,6 +591,30 @@ static int unpoison_page(unsigned long offset)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int mark_page_idle(unsigned long offset)
|
|
|
+{
|
|
|
+ static unsigned long off;
|
|
|
+ static uint64_t buf;
|
|
|
+ int len;
|
|
|
+
|
|
|
+ if ((offset / 64 == off / 64) || buf == 0) {
|
|
|
+ buf |= 1UL << (offset % 64);
|
|
|
+ off = offset;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ len = pwrite(page_idle_fd, &buf, 8, 8 * (off / 64));
|
|
|
+ if (len < 0) {
|
|
|
+ perror("mark page idle");
|
|
|
+ return len;
|
|
|
+ }
|
|
|
+
|
|
|
+ buf = 1UL << (offset % 64);
|
|
|
+ off = offset;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* page frame walker
|
|
|
*/
|
|
@@ -635,6 +663,9 @@ static void add_page(unsigned long voffset, unsigned long offset,
|
|
|
if (opt_unpoison)
|
|
|
unpoison_page(offset);
|
|
|
|
|
|
+ if (opt_mark_idle)
|
|
|
+ mark_page_idle(offset);
|
|
|
+
|
|
|
if (opt_list == 1)
|
|
|
show_page_range(voffset, offset, 1, flags, cgroup, mapcnt);
|
|
|
else if (opt_list == 2)
|
|
@@ -783,6 +814,9 @@ static void walk_addr_ranges(void)
|
|
|
else
|
|
|
walk_task(opt_offset[i], opt_size[i]);
|
|
|
|
|
|
+ if (opt_mark_idle)
|
|
|
+ mark_page_idle(0);
|
|
|
+
|
|
|
close(kpageflags_fd);
|
|
|
}
|
|
|
|
|
@@ -813,6 +847,7 @@ static void usage(void)
|
|
|
" -c|--cgroup path|@inode Walk pages within memory cgroup\n"
|
|
|
" -p|--pid pid Walk process address space\n"
|
|
|
" -f|--file filename Walk file address space\n"
|
|
|
+" -i|--mark-idle Mark pages idle\n"
|
|
|
" -l|--list Show page details in ranges\n"
|
|
|
" -L|--list-each Show page details one by one\n"
|
|
|
" -C|--list-cgroup Show cgroup inode for pages\n"
|
|
@@ -1221,6 +1256,7 @@ static const struct option opts[] = {
|
|
|
{ "bits" , 1, NULL, 'b' },
|
|
|
{ "cgroup" , 1, NULL, 'c' },
|
|
|
{ "describe" , 1, NULL, 'd' },
|
|
|
+ { "mark-idle" , 0, NULL, 'i' },
|
|
|
{ "list" , 0, NULL, 'l' },
|
|
|
{ "list-each" , 0, NULL, 'L' },
|
|
|
{ "list-cgroup", 0, NULL, 'C' },
|
|
@@ -1240,7 +1276,7 @@ int main(int argc, char *argv[])
|
|
|
page_size = getpagesize();
|
|
|
|
|
|
while ((c = getopt_long(argc, argv,
|
|
|
- "rp:f:a:b:d:c:ClLMNXxF:h",
|
|
|
+ "rp:f:a:b:d:c:CilLMNXxF:h",
|
|
|
opts, NULL)) != -1) {
|
|
|
switch (c) {
|
|
|
case 'r':
|
|
@@ -1267,6 +1303,9 @@ int main(int argc, char *argv[])
|
|
|
case 'd':
|
|
|
describe_flags(optarg);
|
|
|
exit(0);
|
|
|
+ case 'i':
|
|
|
+ opt_mark_idle = 1;
|
|
|
+ break;
|
|
|
case 'l':
|
|
|
opt_list = 1;
|
|
|
break;
|
|
@@ -1308,6 +1347,9 @@ int main(int argc, char *argv[])
|
|
|
if (opt_list && opt_list_mapcnt)
|
|
|
kpagecount_fd = checked_open(PROC_KPAGECOUNT, O_RDONLY);
|
|
|
|
|
|
+ if (opt_mark_idle && opt_file)
|
|
|
+ page_idle_fd = checked_open(SYS_KERNEL_MM_PAGE_IDLE, O_RDWR);
|
|
|
+
|
|
|
if (opt_list && opt_pid)
|
|
|
printf("voffset\t");
|
|
|
if (opt_list && opt_file)
|
|
@@ -1341,5 +1383,8 @@ int main(int argc, char *argv[])
|
|
|
if (opt_list_mapcnt)
|
|
|
close(kpagecount_fd);
|
|
|
|
|
|
+ if (page_idle_fd >= 0)
|
|
|
+ close(page_idle_fd);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|