aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChen Gong <gong.chen@linux.intel.com>2013-02-04 02:48:37 -0500
committerChen Gong <gong.chen@linux.intel.com>2013-02-04 03:09:36 -0500
commit8765dc6a73b9ebf5c14a5abf0c15c485d3bce06f (patch)
tree83f4a244631dfe669ce76768419859e990b944a4
parentc3b3b0c102ea6c9473bd8311fd44b5b557f5560d (diff)
downloadmce-test-8765dc6a73b9ebf5c14a5abf0c15c485d3bce06f.tar.gz
Update page-types tool
New page-types fixes some bugs and support THP, so update this tool for mce-test. Signed-off-by: Chen Gong <gong.chen@linux.intel.com>
-rw-r--r--tools/page-types/page-types.c131
1 files changed, 116 insertions, 15 deletions
diff --git a/tools/page-types/page-types.c b/tools/page-types/page-types.c
index cc96ee2..35f5769 100644
--- a/tools/page-types/page-types.c
+++ b/tools/page-types/page-types.c
@@ -32,8 +32,19 @@
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
+#include <sys/mount.h>
+#include <sys/statfs.h>
+#ifndef MAX_PATH
+# define MAX_PATH 256
+#endif
+
+#ifndef STR
+# define _STR(x) #x
+# define STR(x) _STR(x)
+#endif
+
/*
* pagemap kernel ABI bits
*/
@@ -86,6 +97,7 @@
#define KPF_HWPOISON 19
#define KPF_NOPAGE 20
#define KPF_KSM 21
+#define KPF_THP 22
/* [32-] kernel hacking assistances */
#define KPF_RESERVED 32
@@ -111,7 +123,10 @@
#define BIT(name) (1ULL << KPF_##name)
#define BITS_COMPOUND (BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL))
-static const char *page_flag_names[] = {
+/* copied from include/uapi/linux/magic.h */
+#define DEBUGFS_MAGIC 0x64626720
+
+static const char * const page_flag_names[] = {
[KPF_LOCKED] = "L:locked",
[KPF_ERROR] = "E:error",
[KPF_REFERENCED] = "R:referenced",
@@ -135,6 +150,7 @@ static const char *page_flag_names[] = {
[KPF_HWPOISON] = "X:hwpoison",
[KPF_NOPAGE] = "n:nopage",
[KPF_KSM] = "x:ksm",
+ [KPF_THP] = "t:thp",
[KPF_RESERVED] = "r:reserved",
[KPF_MLOCKED] = "m:mlocked",
@@ -152,6 +168,12 @@ static const char *page_flag_names[] = {
};
+static const char * const debugfs_known_mountpoints[] = {
+ "/sys/kernel/debug",
+ "/debug",
+ 0,
+};
+
/*
* data structures
*/
@@ -184,7 +206,7 @@ static int kpageflags_fd;
static int opt_hwpoison;
static int opt_unpoison;
-static const char hwpoison_debug_fs[] = "/debug/hwpoison";
+static char hwpoison_debug_fs[MAX_PATH+1];
static int hwpoison_inject_fd;
static int hwpoison_forget_fd;
@@ -195,7 +217,7 @@ static int hwpoison_forget_fd;
static unsigned long total_pages;
static unsigned long nr_pages[HASH_SIZE];
-static uint64_t page_flags[HASH_SIZE];
+static uint64_t page_flags[HASH_SIZE];
/*
@@ -306,7 +328,7 @@ static char *page_flag_name(uint64_t flags)
{
static char buf[65];
int present;
- int i, j;
+ size_t i, j;
for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
present = (flags >> i) & 1;
@@ -324,7 +346,7 @@ static char *page_flag_name(uint64_t flags)
static char *page_flag_longname(uint64_t flags)
{
static char buf[1024];
- int i, n;
+ size_t i, n;
for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) {
if (!page_flag_names[i])
@@ -382,7 +404,7 @@ static void show_page(unsigned long voffset,
static void show_summary(void)
{
- int i;
+ size_t i;
printf(" flags\tpage-count MB"
" symbolic-flags\t\t\tlong-symbolic-flags\n");
@@ -464,21 +486,100 @@ static uint64_t kpageflags_flags(uint64_t flags)
return flags;
}
+/* verify that a mountpoint is actually a debugfs instance */
+static int debugfs_valid_mountpoint(const char *debugfs)
+{
+ struct statfs st_fs;
+
+ if (statfs(debugfs, &st_fs) < 0)
+ return -ENOENT;
+ else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
+ return -ENOENT;
+
+ return 0;
+}
+
+/* find the path to the mounted debugfs */
+static const char *debugfs_find_mountpoint(void)
+{
+ const char *const *ptr;
+ char type[100];
+ FILE *fp;
+
+ ptr = debugfs_known_mountpoints;
+ while (*ptr) {
+ if (debugfs_valid_mountpoint(*ptr) == 0) {
+ strcpy(hwpoison_debug_fs, *ptr);
+ return hwpoison_debug_fs;
+ }
+ ptr++;
+ }
+
+ /* give up and parse /proc/mounts */
+ fp = fopen("/proc/mounts", "r");
+ if (fp == NULL)
+ perror("Can't open /proc/mounts for read");
+
+ while (fscanf(fp, "%*s %"
+ STR(MAX_PATH)
+ "s %99s %*s %*d %*d\n",
+ hwpoison_debug_fs, type) == 2) {
+ if (strcmp(type, "debugfs") == 0)
+ break;
+ }
+ fclose(fp);
+
+ if (strcmp(type, "debugfs") != 0)
+ return NULL;
+
+ return hwpoison_debug_fs;
+}
+
+/* mount the debugfs somewhere if it's not mounted */
+
+static void debugfs_mount(void)
+{
+ const char *const *ptr;
+
+ /* see if it's already mounted */
+ if (debugfs_find_mountpoint())
+ return;
+
+ ptr = debugfs_known_mountpoints;
+ while (*ptr) {
+ if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) {
+ /* save the mountpoint */
+ strcpy(hwpoison_debug_fs, *ptr);
+ break;
+ }
+ ptr++;
+ }
+
+ if (*ptr == NULL) {
+ perror("mount debugfs");
+ exit(EXIT_FAILURE);
+ }
+}
+
/*
* page actions
*/
static void prepare_hwpoison_fd(void)
{
- char buf[100];
+ char buf[MAX_PATH + 1];
+
+ debugfs_mount();
if (opt_hwpoison && !hwpoison_inject_fd) {
- sprintf(buf, "%s/corrupt-pfn", hwpoison_debug_fs);
+ snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn",
+ hwpoison_debug_fs);
hwpoison_inject_fd = checked_open(buf, O_WRONLY);
}
if (opt_unpoison && !hwpoison_forget_fd) {
- sprintf(buf, "%s/unpoison-pfn", hwpoison_debug_fs);
+ snprintf(buf, MAX_PATH, "%s/hwpoison/unpoison-pfn",
+ hwpoison_debug_fs);
hwpoison_forget_fd = checked_open(buf, O_WRONLY);
}
}
@@ -515,10 +616,10 @@ static int unpoison_page(unsigned long offset)
* page frame walker
*/
-static int hash_slot(uint64_t flags)
+static size_t hash_slot(uint64_t flags)
{
- int k = HASH_KEY(flags);
- int i;
+ size_t k = HASH_KEY(flags);
+ size_t i;
/* Explicitly reserve slot 0 for flags 0: the following logic
* cannot distinguish an unoccupied slot from slot (flags==0).
@@ -571,7 +672,7 @@ static void walk_pfn(unsigned long voffset,
{
uint64_t buf[KPAGEFLAGS_BATCH];
unsigned long batch;
- long pages;
+ unsigned long pages;
unsigned long i;
while (count) {
@@ -680,7 +781,7 @@ static const char *page_flag_type(uint64_t flag)
static void usage(void)
{
- int i, j;
+ size_t i, j;
printf(
"page-types [options]\n"
@@ -839,7 +940,7 @@ static void add_bits_filter(uint64_t mask, uint64_t bits)
static uint64_t parse_flag_name(const char *str, int len)
{
- int i;
+ size_t i;
if (!*str || !len)
return 0;