/* * page-types: Tool for querying page flags * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should find a copy of v2 of the GNU General Public License somewhere on * your Linux system; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * Copyright (C) 2009 Intel corporation * * Authors: Wu Fengguang <fengguang.wu@intel.com> */ #define _LARGEFILE64_SOURCE#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <stdint.h>#include <stdarg.h>#include <string.h>#include <getopt.h>#include <limits.h>#include <assert.h>#include <sys/types.h>#include <sys/errno.h>#include <sys/fcntl.h>#include <sys/mount.h>#include <sys/statfs.h>#include "../../include/linux/magic.h"#include "../../include/linux/kernel-page-flags.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 */ #define PM_ENTRY_BYTES sizeof(uint64_t)#define PM_STATUS_BITS 3#define PM_STATUS_OFFSET (64 - PM_STATUS_BITS)#define PM_STATUS_MASK (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET)#define PM_STATUS(nr) (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK)#define PM_PSHIFT_BITS 6#define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS)#define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET)#define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK)#define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1)#define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) #define PM_PRESENT PM_STATUS(4LL)#define PM_SWAP PM_STATUS(2LL) /* * kernel page flags */ #define KPF_BYTES 8#define PROC_KPAGEFLAGS "/proc/kpageflags" /* [32-] kernel hacking assistances */#define KPF_RESERVED 32#define KPF_MLOCKED 33#define KPF_MAPPEDTODISK 34#define KPF_PRIVATE 35#define KPF_PRIVATE_2 36#define KPF_OWNER_PRIVATE 37#define KPF_ARCH 38#define KPF_UNCACHED 39 /* [48-] take some arbitrary free slots for expanding overloaded flags * not part of kernel API */#define KPF_READAHEAD 48#define KPF_SLOB_FREE 49#define KPF_SLUB_FROZEN 50#define KPF_SLUB_DEBUG 51 #define KPF_ALL_BITS ((uint64_t)~0ULL)#define KPF_HACKERS_BITS (0xffffULL << 32)#define KPF_OVERLOADED_BITS (0xffffULL << 48)#define BIT(name) (1ULL << KPF_##name)#define BITS_COMPOUND (BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL)) static const char * const page_flag_names[] = { [KPF_LOCKED] = "L:locked", [KPF_ERROR] = "E:error", [KPF_REFERENCED] = "R:referenced", [KPF_UPTODATE] = "U:uptodate", [KPF_DIRTY] = "D:dirty", [KPF_LRU] = "l:lru", [KPF_ACTIVE] = "A:active", [KPF_SLAB] = "S:slab", [KPF_WRITEBACK] = "W:writeback", [KPF_RECLAIM] = "I:reclaim", [KPF_BUDDY] = "B:buddy", [KPF_MMAP] = "M:mmap", [KPF_ANON] = "a:anonymous", [KPF_SWAPCACHE] = "s:swapcache", [KPF_SWAPBACKED] = "b:swapbacked", [KPF_COMPOUND_HEAD] = "H:compound_head", [KPF_COMPOUND_TAIL] = "T:compound_tail", [KPF_HUGE] = "G:huge", [KPF_UNEVICTABLE] = "u:unevictable", [KPF_HWPOISON] = "X:hwpoison", [KPF_NOPAGE] = "n:nopage", [KPF_KSM] = "x:ksm", [KPF_THP] = "t:thp", [KPF_RESERVED] = "r:reserved", [KPF_MLOCKED] = "m:mlocked", [KPF_MAPPEDTODISK] = "d:mappedtodisk", [KPF_PRIVATE] = "P:private", [KPF_PRIVATE_2] = "p:private_2", [KPF_OWNER_PRIVATE] = "O:owner_private", [KPF_ARCH] = "h:arch", [KPF_UNCACHED] = "c:uncached", [KPF_READAHEAD] = "I:readahead", [KPF_SLOB_FREE] = "P:slob_free", [KPF_SLUB_FROZEN] = "A:slub_frozen", [KPF_SLUB_DEBUG] = "E:slub_debug",}; static const char * const debugfs_known_mountpoints[] = { "/sys/kernel/debug", "/debug", 0,}; /* * data structures */ static int opt_raw; /* for kernel developers */static int opt_list; /* list pages (in ranges) */static int opt_no_summary; /* don't show summary */static pid_t opt_pid; /* process to walk */ #define MAX_ADDR_RANGES 1024static int nr_addr_ranges;static unsigned long opt_offset[MAX_ADDR_RANGES];static unsigned long opt_size[MAX_ADDR_RANGES]; #define MAX_VMAS 10240static int nr_vmas;static unsigned long pg_start[MAX_VMAS];static unsigned long pg_end[MAX_VMAS]; #define MAX_BIT_FILTERS 64static int nr_bit_filters;static uint64_t opt_mask[MAX_BIT_FILTERS];static uint64_t opt_bits[MAX_BIT_FILTERS]; static int page_size; static int pagemap_fd;static int kpageflags_fd; static int opt_hwpoison;static int opt_unpoison; static char hwpoison_debug_fs[MAX_PATH+1];static int hwpoison_inject_fd;static int hwpoison_forget_fd; #define HASH_SHIFT 13#define HASH_SIZE (1 << HASH_SHIFT)#define HASH_MASK (HASH_SIZE - 1)#define HASH_KEY(flags) (flags & HASH_MASK) static unsigned long total_pages;static unsigned long nr_pages[HASH_SIZE];static uint64_t page_flags[HASH_SIZE]; /* * helper functions */ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define min_t(type, x, y) ({ \ type __min1 = (x); \ type __min2 = (y); \ __min1 < __min2 ? __min1 : __min2; }) #define max_t(type, x, y) ({ \ type __max1 = (x); \ type __max2 = (y); \ __max1 > __max2 ? __max1 : __max2; }) static unsigned long pages2mb(unsigned long pages){ return (pages * page_size) >> 20;} static void fatal(const char *x, ...){ va_list ap; va_start(ap, x); vfprintf(stderr, x, ap); va_end(ap); exit(EXIT_FAILURE);} static int checked_open(const char *pathname, int flags){ int fd = open(pathname, flags); if (fd < 0) { perror(pathname); exit(EXIT_FAILURE); } return fd;} /* * pagemap/kpageflags routines */ static unsigned long do_u64_read(int fd, char *name, uint64_t *buf, unsigned long index, unsigned long count){ long bytes; if (index > ULONG_MAX / 8) fatal("index overflow: %lu\n", index); if (lseek(fd, index * 8, SEEK_SET) < 0) { perror(name); exit(EXIT_FAILURE); } bytes = read(fd, buf, count * 8); if (bytes < 0) { perror(name); exit(EXIT_FAILURE); } if (bytes % 8) fatal("partial read: %lu bytes\n", bytes); return bytes / 8;} static unsigned long kpageflags_read(uint64_t *buf, unsigned long index, unsigned long pages){ return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages);} static unsigned long pagemap_read(uint64_t *buf, unsigned long index, unsigned long pages){ return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages);} static unsigned long pagemap_pfn(uint64_t val){ unsigned long pfn; if (val & PM_PRESENT) pfn = PM_PFRAME(val); else pfn = 0; return pfn;} /* * page flag names */ static char *page_flag_name(uint64_t flags){ static char buf[65]; int present; size_t i, j; for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) { present = (flags >> i) & 1; if (!page_flag_names[i]) { if (present) fatal("unknown flag bit %d\n", i); continue; } buf[j++] = present ? page_flag_names[i][0] : '_'; } return buf;} static char *page_flag_longname(uint64_t flags){ static char buf[1024]; size_t i, n; for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) { if (!page_flag_names[i]) continue; if ((flags >> i) & 1) n += snprintf(buf + n, sizeof(buf) - n, "%s,", page_flag_names[i] + 2); } if (n) n--; buf[n] = '\0'; return buf;} /* * page list and summary */ static void show_page_range(unsigned long voffset, unsigned long offset, uint64_t flags){ static uint64_t flags0; static unsigned long voff; static unsigned long index; static unsigned long count; if (flags == flags0 && offset == index + count && (!opt_pid || voffset == voff + count)) { count++; return; } if (count) { if (opt_pid) printf("%lx\t", voff); printf("%lx\t%lx\t%s\n", index, count, page_flag_name(flags0)); } flags0 = flags; index = offset; voff = voffset; count = 1;} static void show_page(unsigned long voffset, unsigned long offset, uint64_t flags){ if (opt_pid) printf("%lx\t", voffset); printf("%lx\t%s\n", offset, page_flag_name(flags));} static void show_summary(void){ size_t i; printf(" flags\tpage-count MB" " symbolic-flags\t\t\tlong-symbolic-flags\n"); for (i = 0; i < ARRAY_SIZE(nr_pages); i++) { if (nr_pages[i]) printf("0x%016llx\t%10lu %8lu %s\t%s\n", (unsigned long long)page_flags[i], nr_pages[i], pages2mb(nr_pages[i]), page_flag_name(page_flags[i]), page_flag_longname(page_flags[i])); } printf(" total\t%10lu %8lu\n", total_pages, pages2mb(total_pages));} /* * page flag filters */ static int bit_mask_ok(uint64_t flags){ int i; for (i = 0; i < nr_bit_filters; i++) { if (opt_bits[i] == KPF_ALL_BITS) { if ((flags & opt_mask[i]) == 0) return 0; } else { if ((flags & opt_mask[i]) != opt_bits[i]) return 0; } } return 1;} static uint64_t expand_overloaded_flags(uint64_t flags){ /* SLOB/SLUB overload several page flags */ if (flags & BIT(SLAB)) { if (flags & BIT(PRIVATE)) flags ^= BIT(PRIVATE) | BIT(SLOB_FREE); if (flags & BIT(ACTIVE)) flags ^= BIT(ACTIVE) | BIT(SLUB_FROZEN); if (flags & BIT(ERROR)) flags ^= BIT(ERROR) | BIT(SLUB_DEBUG); } /* PG_reclaim is overloaded as PG_readahead in the read path */ if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM)) flags ^= BIT(RECLAIM) | BIT(READAHEAD); return flags;} static uint64_t well_known_flags(uint64_t flags){ /* hide flags intended only for kernel hacker */ flags &= ~KPF_HACKERS_BITS; /* hide non-hugeTLB compound pages */ if ((flags & BITS_COMPOUND) && !(flags & BIT(HUGE))) flags &= ~BITS_COMPOUND; return flags;} static uint64_t kpageflags_flags(uint64_t flags){ flags = expand_overloaded_flags(flags); if (!opt_raw) flags = well_known_flags(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;Lines 1–500 of 1076. Load more
/* * page-types: Tool for querying page flags * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should find a copy of v2 of the GNU General Public License somewhere on * your Linux system; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * Copyright (C) 2009 Intel corporation * * Authors: Wu Fengguang <fengguang.wu@intel.com> */ #define _LARGEFILE64_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <stdint.h> #include <stdarg.h> #include <string.h> #include <getopt.h> #include <limits.h> #include <assert.h> #include <sys/types.h> #include <sys/errno.h> #include <sys/fcntl.h> #include <sys/mount.h> #include <sys/statfs.h> #include "../../include/linux/magic.h" #include "../../include/linux/kernel-page-flags.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 */ #define PM_ENTRY_BYTES sizeof(uint64_t) #define PM_STATUS_BITS 3 #define PM_STATUS_OFFSET (64 - PM_STATUS_BITS) #define PM_STATUS_MASK (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET) #define PM_STATUS(nr) (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK) #define PM_PSHIFT_BITS 6 #define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) #define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) #define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) #define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) #define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) #define PM_PRESENT PM_STATUS(4LL) #define PM_SWAP PM_STATUS(2LL) /* * kernel page flags */ #define KPF_BYTES 8 #define PROC_KPAGEFLAGS "/proc/kpageflags" /* [32-] kernel hacking assistances */ #define KPF_RESERVED 32 #define KPF_MLOCKED 33 #define KPF_MAPPEDTODISK 34 #define KPF_PRIVATE 35 #define KPF_PRIVATE_2 36 #define KPF_OWNER_PRIVATE 37 #define KPF_ARCH 38 #define KPF_UNCACHED 39 /* [48-] take some arbitrary free slots for expanding overloaded flags * not part of kernel API */ #define KPF_READAHEAD 48 #define KPF_SLOB_FREE 49 #define KPF_SLUB_FROZEN 50 #define KPF_SLUB_DEBUG 51 #define KPF_ALL_BITS ((uint64_t)~0ULL) #define KPF_HACKERS_BITS (0xffffULL << 32) #define KPF_OVERLOADED_BITS (0xffffULL << 48) #define BIT(name) (1ULL << KPF_##name) #define BITS_COMPOUND (BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL)) static const char * const page_flag_names[] = { [KPF_LOCKED] = "L:locked", [KPF_ERROR] = "E:error", [KPF_REFERENCED] = "R:referenced", [KPF_UPTODATE] = "U:uptodate", [KPF_DIRTY] = "D:dirty", [KPF_LRU] = "l:lru", [KPF_ACTIVE] = "A:active", [KPF_SLAB] = "S:slab", [KPF_WRITEBACK] = "W:writeback", [KPF_RECLAIM] = "I:reclaim", [KPF_BUDDY] = "B:buddy", [KPF_MMAP] = "M:mmap", [KPF_ANON] = "a:anonymous", [KPF_SWAPCACHE] = "s:swapcache", [KPF_SWAPBACKED] = "b:swapbacked", [KPF_COMPOUND_HEAD] = "H:compound_head", [KPF_COMPOUND_TAIL] = "T:compound_tail", [KPF_HUGE] = "G:huge", [KPF_UNEVICTABLE] = "u:unevictable", [KPF_HWPOISON] = "X:hwpoison", [KPF_NOPAGE] = "n:nopage", [KPF_KSM] = "x:ksm", [KPF_THP] = "t:thp", [KPF_RESERVED] = "r:reserved", [KPF_MLOCKED] = "m:mlocked", [KPF_MAPPEDTODISK] = "d:mappedtodisk", [KPF_PRIVATE] = "P:private", [KPF_PRIVATE_2] = "p:private_2", [KPF_OWNER_PRIVATE] = "O:owner_private", [KPF_ARCH] = "h:arch", [KPF_UNCACHED] = "c:uncached", [KPF_READAHEAD] = "I:readahead", [KPF_SLOB_FREE] = "P:slob_free", [KPF_SLUB_FROZEN] = "A:slub_frozen", [KPF_SLUB_DEBUG] = "E:slub_debug", }; static const char * const debugfs_known_mountpoints[] = { "/sys/kernel/debug", "/debug", 0, }; /* * data structures */ static int opt_raw; /* for kernel developers */ static int opt_list; /* list pages (in ranges) */ static int opt_no_summary; /* don't show summary */ static pid_t opt_pid; /* process to walk */ #define MAX_ADDR_RANGES 1024 static int nr_addr_ranges; static unsigned long opt_offset[MAX_ADDR_RANGES]; static unsigned long opt_size[MAX_ADDR_RANGES]; #define MAX_VMAS 10240 static int nr_vmas; static unsigned long pg_start[MAX_VMAS]; static unsigned long pg_end[MAX_VMAS]; #define MAX_BIT_FILTERS 64 static int nr_bit_filters; static uint64_t opt_mask[MAX_BIT_FILTERS]; static uint64_t opt_bits[MAX_BIT_FILTERS]; static int page_size; static int pagemap_fd; static int kpageflags_fd; static int opt_hwpoison; static int opt_unpoison; static char hwpoison_debug_fs[MAX_PATH+1]; static int hwpoison_inject_fd; static int hwpoison_forget_fd; #define HASH_SHIFT 13 #define HASH_SIZE (1 << HASH_SHIFT) #define HASH_MASK (HASH_SIZE - 1) #define HASH_KEY(flags) (flags & HASH_MASK) static unsigned long total_pages; static unsigned long nr_pages[HASH_SIZE]; static uint64_t page_flags[HASH_SIZE]; /* * helper functions */ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define min_t(type, x, y) ({ \ type __min1 = (x); \ type __min2 = (y); \ __min1 < __min2 ? __min1 : __min2; }) #define max_t(type, x, y) ({ \ type __max1 = (x); \ type __max2 = (y); \ __max1 > __max2 ? __max1 : __max2; }) static unsigned long pages2mb(unsigned long pages) { return (pages * page_size) >> 20; } static void fatal(const char *x, ...) { va_list ap; va_start(ap, x); vfprintf(stderr, x, ap); va_end(ap); exit(EXIT_FAILURE); } static int checked_open(const char *pathname, int flags) { int fd = open(pathname, flags); if (fd < 0) { perror(pathname); exit(EXIT_FAILURE); } return fd; } /* * pagemap/kpageflags routines */ static unsigned long do_u64_read(int fd, char *name, uint64_t *buf, unsigned long index, unsigned long count) { long bytes; if (index > ULONG_MAX / 8) fatal("index overflow: %lu\n", index); if (lseek(fd, index * 8, SEEK_SET) < 0) { perror(name); exit(EXIT_FAILURE); } bytes = read(fd, buf, count * 8); if (bytes < 0) { perror(name); exit(EXIT_FAILURE); } if (bytes % 8) fatal("partial read: %lu bytes\n", bytes); return bytes / 8; } static unsigned long kpageflags_read(uint64_t *buf, unsigned long index, unsigned long pages) { return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages); } static unsigned long pagemap_read(uint64_t *buf, unsigned long index, unsigned long pages) { return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages); } static unsigned long pagemap_pfn(uint64_t val) { unsigned long pfn; if (val & PM_PRESENT) pfn = PM_PFRAME(val); else pfn = 0; return pfn; } /* * page flag names */ static char *page_flag_name(uint64_t flags) { static char buf[65]; int present; size_t i, j; for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) { present = (flags >> i) & 1; if (!page_flag_names[i]) { if (present) fatal("unknown flag bit %d\n", i); continue; } buf[j++] = present ? page_flag_names[i][0] : '_'; } return buf; } static char *page_flag_longname(uint64_t flags) { static char buf[1024]; size_t i, n; for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) { if (!page_flag_names[i]) continue; if ((flags >> i) & 1) n += snprintf(buf + n, sizeof(buf) - n, "%s,", page_flag_names[i] + 2); } if (n) n--; buf[n] = '\0'; return buf; } /* * page list and summary */ static void show_page_range(unsigned long voffset, unsigned long offset, uint64_t flags) { static uint64_t flags0; static unsigned long voff; static unsigned long index; static unsigned long count; if (flags == flags0 && offset == index + count && (!opt_pid || voffset == voff + count)) { count++; return; } if (count) { if (opt_pid) printf("%lx\t", voff); printf("%lx\t%lx\t%s\n", index, count, page_flag_name(flags0)); } flags0 = flags; index = offset; voff = voffset; count = 1; } static void show_page(unsigned long voffset, unsigned long offset, uint64_t flags) { if (opt_pid) printf("%lx\t", voffset); printf("%lx\t%s\n", offset, page_flag_name(flags)); } static void show_summary(void) { size_t i; printf(" flags\tpage-count MB" " symbolic-flags\t\t\tlong-symbolic-flags\n"); for (i = 0; i < ARRAY_SIZE(nr_pages); i++) { if (nr_pages[i]) printf("0x%016llx\t%10lu %8lu %s\t%s\n", (unsigned long long)page_flags[i], nr_pages[i], pages2mb(nr_pages[i]), page_flag_name(page_flags[i]), page_flag_longname(page_flags[i])); } printf(" total\t%10lu %8lu\n", total_pages, pages2mb(total_pages)); } /* * page flag filters */ static int bit_mask_ok(uint64_t flags) { int i; for (i = 0; i < nr_bit_filters; i++) { if (opt_bits[i] == KPF_ALL_BITS) { if ((flags & opt_mask[i]) == 0) return 0; } else { if ((flags & opt_mask[i]) != opt_bits[i]) return 0; } } return 1; } static uint64_t expand_overloaded_flags(uint64_t flags) { /* SLOB/SLUB overload several page flags */ if (flags & BIT(SLAB)) { if (flags & BIT(PRIVATE)) flags ^= BIT(PRIVATE) | BIT(SLOB_FREE); if (flags & BIT(ACTIVE)) flags ^= BIT(ACTIVE) | BIT(SLUB_FROZEN); if (flags & BIT(ERROR)) flags ^= BIT(ERROR) | BIT(SLUB_DEBUG); } /* PG_reclaim is overloaded as PG_readahead in the read path */ if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM)) flags ^= BIT(RECLAIM) | BIT(READAHEAD); return flags; } static uint64_t well_known_flags(uint64_t flags) { /* hide flags intended only for kernel hacker */ flags &= ~KPF_HACKERS_BITS; /* hide non-hugeTLB compound pages */ if ((flags & BITS_COMPOUND) && !(flags & BIT(HUGE))) flags &= ~BITS_COMPOUND; return flags; } static uint64_t kpageflags_flags(uint64_t flags) { flags = expand_overloaded_flags(flags); if (!opt_raw) flags = well_known_flags(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;