lkml.org 
[lkml]   [2009]   [Sep]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[RFC][PATCH 1/4] page-types: move from Documentation/vm/ to tools/vm/

    CC: Andi Kleen <andi@firstfloor.org>
    CC: Josh Triplett <josh@joshtriplett.org>
    Acked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
    Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
    ---
    Documentation/vm/.gitignore | 1
    Documentation/vm/Makefile | 2
    Documentation/vm/page-types.c | 698 --------------------------------
    Documentation/vm/pagemap.txt | 4
    tools/vm/.gitignore | 1
    tools/vm/Makefile | 5
    tools/vm/page-types.c | 698 ++++++++++++++++++++++++++++++++
    7 files changed, 708 insertions(+), 701 deletions(-)

    --- linux-mm.orig/Documentation/vm/page-types.c 2009-08-31 14:00:34.000000000 +0800
    +++ /dev/null 1970-01-01 00:00:00.000000000 +0000
    @@ -1,698 +0,0 @@
    -/*
    - * page-types: Tool for querying page flags
    - *
    - * Copyright (C) 2009 Intel corporation
    - * Copyright (C) 2009 Wu Fengguang <fengguang.wu@intel.com>
    - */
    -
    -#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 <sys/types.h>
    -#include <sys/errno.h>
    -#include <sys/fcntl.h>
    -
    -
    -/*
    - * kernel page flags
    - */
    -
    -#define KPF_BYTES 8
    -#define PROC_KPAGEFLAGS "/proc/kpageflags"
    -
    -/* copied from kpageflags_read() */
    -#define KPF_LOCKED 0
    -#define KPF_ERROR 1
    -#define KPF_REFERENCED 2
    -#define KPF_UPTODATE 3
    -#define KPF_DIRTY 4
    -#define KPF_LRU 5
    -#define KPF_ACTIVE 6
    -#define KPF_SLAB 7
    -#define KPF_WRITEBACK 8
    -#define KPF_RECLAIM 9
    -#define KPF_BUDDY 10
    -
    -/* [11-20] new additions in 2.6.31 */
    -#define KPF_MMAP 11
    -#define KPF_ANON 12
    -#define KPF_SWAPCACHE 13
    -#define KPF_SWAPBACKED 14
    -#define KPF_COMPOUND_HEAD 15
    -#define KPF_COMPOUND_TAIL 16
    -#define KPF_HUGE 17
    -#define KPF_UNEVICTABLE 18
    -#define KPF_NOPAGE 20
    -
    -/* [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 char *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_NOPAGE] = "n:nopage",
    -
    - [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",
    -};
    -
    -
    -/*
    - * 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_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;
    -
    -#define PAGES_BATCH (64 << 10) /* 64k pages */
    -static int kpageflags_fd;
    -static uint64_t kpageflags_buf[KPF_BYTES * PAGES_BATCH];
    -
    -#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; })
    -
    -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);
    -}
    -
    -
    -/*
    - * page flag names
    - */
    -
    -static char *page_flag_name(uint64_t flags)
    -{
    - static char buf[65];
    - int present;
    - int 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("unkown 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];
    - int 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 offset, uint64_t flags)
    -{
    - static uint64_t flags0;
    - static unsigned long index;
    - static unsigned long count;
    -
    - if (flags == flags0 && offset == index + count) {
    - count++;
    - return;
    - }
    -
    - if (count)
    - printf("%lu\t%lu\t%s\n",
    - index, count, page_flag_name(flags0));
    -
    - flags0 = flags;
    - index = offset;
    - count = 1;
    -}
    -
    -static void show_page(unsigned long offset, uint64_t flags)
    -{
    - printf("%lu\t%s\n", offset, page_flag_name(flags));
    -}
    -
    -static void show_summary(void)
    -{
    - int 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;
    -}
    -
    -
    -/*
    - * page frame walker
    - */
    -
    -static int hash_slot(uint64_t flags)
    -{
    - int k = HASH_KEY(flags);
    - int i;
    -
    - /* Explicitly reserve slot 0 for flags 0: the following logic
    - * cannot distinguish an unoccupied slot from slot (flags==0).
    - */
    - if (flags == 0)
    - return 0;
    -
    - /* search through the remaining (HASH_SIZE-1) slots */
    - for (i = 1; i < ARRAY_SIZE(page_flags); i++, k++) {
    - if (!k || k >= ARRAY_SIZE(page_flags))
    - k = 1;
    - if (page_flags[k] == 0) {
    - page_flags[k] = flags;
    - return k;
    - }
    - if (page_flags[k] == flags)
    - return k;
    - }
    -
    - fatal("hash table full: bump up HASH_SHIFT?\n");
    - exit(EXIT_FAILURE);
    -}
    -
    -static void add_page(unsigned long offset, uint64_t flags)
    -{
    - flags = expand_overloaded_flags(flags);
    -
    - if (!opt_raw)
    - flags = well_known_flags(flags);
    -
    - if (!bit_mask_ok(flags))
    - return;
    -
    - if (opt_list == 1)
    - show_page_range(offset, flags);
    - else if (opt_list == 2)
    - show_page(offset, flags);
    -
    - nr_pages[hash_slot(flags)]++;
    - total_pages++;
    -}
    -
    -static void walk_pfn(unsigned long index, unsigned long count)
    -{
    - unsigned long batch;
    - unsigned long n;
    - unsigned long i;
    -
    - if (index > ULONG_MAX / KPF_BYTES)
    - fatal("index overflow: %lu\n", index);
    -
    - lseek(kpageflags_fd, index * KPF_BYTES, SEEK_SET);
    -
    - while (count) {
    - batch = min_t(unsigned long, count, PAGES_BATCH);
    - n = read(kpageflags_fd, kpageflags_buf, batch * KPF_BYTES);
    - if (n == 0)
    - break;
    - if (n < 0) {
    - perror(PROC_KPAGEFLAGS);
    - exit(EXIT_FAILURE);
    - }
    -
    - if (n % KPF_BYTES != 0)
    - fatal("partial read: %lu bytes\n", n);
    - n = n / KPF_BYTES;
    -
    - for (i = 0; i < n; i++)
    - add_page(index + i, kpageflags_buf[i]);
    -
    - index += batch;
    - count -= batch;
    - }
    -}
    -
    -static void walk_addr_ranges(void)
    -{
    - int i;
    -
    - kpageflags_fd = open(PROC_KPAGEFLAGS, O_RDONLY);
    - if (kpageflags_fd < 0) {
    - perror(PROC_KPAGEFLAGS);
    - exit(EXIT_FAILURE);
    - }
    -
    - if (!nr_addr_ranges)
    - walk_pfn(0, ULONG_MAX);
    -
    - for (i = 0; i < nr_addr_ranges; i++)
    - walk_pfn(opt_offset[i], opt_size[i]);
    -
    - close(kpageflags_fd);
    -}
    -
    -
    -/*
    - * user interface
    - */
    -
    -static const char *page_flag_type(uint64_t flag)
    -{
    - if (flag & KPF_HACKERS_BITS)
    - return "(r)";
    - if (flag & KPF_OVERLOADED_BITS)
    - return "(o)";
    - return " ";
    -}
    -
    -static void usage(void)
    -{
    - int i, j;
    -
    - printf(
    -"page-types [options]\n"
    -" -r|--raw Raw mode, for kernel developers\n"
    -" -a|--addr addr-spec Walk a range of pages\n"
    -" -b|--bits bits-spec Walk pages with specified bits\n"
    -#if 0 /* planned features */
    -" -p|--pid pid Walk process address space\n"
    -" -f|--file filename Walk file address space\n"
    -#endif
    -" -l|--list Show page details in ranges\n"
    -" -L|--list-each Show page details one by one\n"
    -" -N|--no-summary Don't show summay info\n"
    -" -h|--help Show this usage message\n"
    -"addr-spec:\n"
    -" N one page at offset N (unit: pages)\n"
    -" N+M pages range from N to N+M-1\n"
    -" N,M pages range from N to M-1\n"
    -" N, pages range from N to end\n"
    -" ,M pages range from 0 to M\n"
    -"bits-spec:\n"
    -" bit1,bit2 (flags & (bit1|bit2)) != 0\n"
    -" bit1,bit2=bit1 (flags & (bit1|bit2)) == bit1\n"
    -" bit1,~bit2 (flags & (bit1|bit2)) == bit1\n"
    -" =bit1,bit2 flags == (bit1|bit2)\n"
    -"bit-names:\n"
    - );
    -
    - for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
    - if (!page_flag_names[i])
    - continue;
    - printf("%16s%s", page_flag_names[i] + 2,
    - page_flag_type(1ULL << i));
    - if (++j > 3) {
    - j = 0;
    - putchar('\n');
    - }
    - }
    - printf("\n "
    - "(r) raw mode bits (o) overloaded bits\n");
    -}
    -
    -static unsigned long long parse_number(const char *str)
    -{
    - unsigned long long n;
    -
    - n = strtoll(str, NULL, 0);
    -
    - if (n == 0 && str[0] != '0')
    - fatal("invalid name or number: %s\n", str);
    -
    - return n;
    -}
    -
    -static void parse_pid(const char *str)
    -{
    - opt_pid = parse_number(str);
    -}
    -
    -static void parse_file(const char *name)
    -{
    -}
    -
    -static void add_addr_range(unsigned long offset, unsigned long size)
    -{
    - if (nr_addr_ranges >= MAX_ADDR_RANGES)
    - fatal("too much addr ranges\n");
    -
    - opt_offset[nr_addr_ranges] = offset;
    - opt_size[nr_addr_ranges] = size;
    - nr_addr_ranges++;
    -}
    -
    -static void parse_addr_range(const char *optarg)
    -{
    - unsigned long offset;
    - unsigned long size;
    - char *p;
    -
    - p = strchr(optarg, ',');
    - if (!p)
    - p = strchr(optarg, '+');
    -
    - if (p == optarg) {
    - offset = 0;
    - size = parse_number(p + 1);
    - } else if (p) {
    - offset = parse_number(optarg);
    - if (p[1] == '\0')
    - size = ULONG_MAX;
    - else {
    - size = parse_number(p + 1);
    - if (*p == ',') {
    - if (size < offset)
    - fatal("invalid range: %lu,%lu\n",
    - offset, size);
    - size -= offset;
    - }
    - }
    - } else {
    - offset = parse_number(optarg);
    - size = 1;
    - }
    -
    - add_addr_range(offset, size);
    -}
    -
    -static void add_bits_filter(uint64_t mask, uint64_t bits)
    -{
    - if (nr_bit_filters >= MAX_BIT_FILTERS)
    - fatal("too much bit filters\n");
    -
    - opt_mask[nr_bit_filters] = mask;
    - opt_bits[nr_bit_filters] = bits;
    - nr_bit_filters++;
    -}
    -
    -static uint64_t parse_flag_name(const char *str, int len)
    -{
    - int i;
    -
    - if (!*str || !len)
    - return 0;
    -
    - if (len <= 8 && !strncmp(str, "compound", len))
    - return BITS_COMPOUND;
    -
    - for (i = 0; i < ARRAY_SIZE(page_flag_names); i++) {
    - if (!page_flag_names[i])
    - continue;
    - if (!strncmp(str, page_flag_names[i] + 2, len))
    - return 1ULL << i;
    - }
    -
    - return parse_number(str);
    -}
    -
    -static uint64_t parse_flag_names(const char *str, int all)
    -{
    - const char *p = str;
    - uint64_t flags = 0;
    -
    - while (1) {
    - if (*p == ',' || *p == '=' || *p == '\0') {
    - if ((*str != '~') || (*str == '~' && all && *++str))
    - flags |= parse_flag_name(str, p - str);
    - if (*p != ',')
    - break;
    - str = p + 1;
    - }
    - p++;
    - }
    -
    - return flags;
    -}
    -
    -static void parse_bits_mask(const char *optarg)
    -{
    - uint64_t mask;
    - uint64_t bits;
    - const char *p;
    -
    - p = strchr(optarg, '=');
    - if (p == optarg) {
    - mask = KPF_ALL_BITS;
    - bits = parse_flag_names(p + 1, 0);
    - } else if (p) {
    - mask = parse_flag_names(optarg, 0);
    - bits = parse_flag_names(p + 1, 0);
    - } else if (strchr(optarg, '~')) {
    - mask = parse_flag_names(optarg, 1);
    - bits = parse_flag_names(optarg, 0);
    - } else {
    - mask = parse_flag_names(optarg, 0);
    - bits = KPF_ALL_BITS;
    - }
    -
    - add_bits_filter(mask, bits);
    -}
    -
    -
    -static struct option opts[] = {
    - { "raw" , 0, NULL, 'r' },
    - { "pid" , 1, NULL, 'p' },
    - { "file" , 1, NULL, 'f' },
    - { "addr" , 1, NULL, 'a' },
    - { "bits" , 1, NULL, 'b' },
    - { "list" , 0, NULL, 'l' },
    - { "list-each" , 0, NULL, 'L' },
    - { "no-summary", 0, NULL, 'N' },
    - { "help" , 0, NULL, 'h' },
    - { NULL , 0, NULL, 0 }
    -};
    -
    -int main(int argc, char *argv[])
    -{
    - int c;
    -
    - page_size = getpagesize();
    -
    - while ((c = getopt_long(argc, argv,
    - "rp:f:a:b:lLNh", opts, NULL)) != -1) {
    - switch (c) {
    - case 'r':
    - opt_raw = 1;
    - break;
    - case 'p':
    - parse_pid(optarg);
    - break;
    - case 'f':
    - parse_file(optarg);
    - break;
    - case 'a':
    - parse_addr_range(optarg);
    - break;
    - case 'b':
    - parse_bits_mask(optarg);
    - break;
    - case 'l':
    - opt_list = 1;
    - break;
    - case 'L':
    - opt_list = 2;
    - break;
    - case 'N':
    - opt_no_summary = 1;
    - break;
    - case 'h':
    - usage();
    - exit(0);
    - default:
    - usage();
    - exit(1);
    - }
    - }
    -
    - if (opt_list == 1)
    - printf("offset\tcount\tflags\n");
    - if (opt_list == 2)
    - printf("offset\tflags\n");
    -
    - walk_addr_ranges();
    -
    - if (opt_list == 1)
    - show_page_range(0, 0); /* drain the buffer */
    -
    - if (opt_no_summary)
    - return 0;
    -
    - if (opt_list)
    - printf("\n\n");
    -
    - show_summary();
    -
    - return 0;
    -}
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-mm/tools/vm/page-types.c 2009-09-02 11:09:39.000000000 +0800
    @@ -0,0 +1,698 @@
    +/*
    + * page-types: Tool for querying page flags
    + *
    + * Copyright (C) 2009 Intel corporation
    + * Copyright (C) 2009 Wu Fengguang <fengguang.wu@intel.com>
    + */
    +
    +#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 <sys/types.h>
    +#include <sys/errno.h>
    +#include <sys/fcntl.h>
    +
    +
    +/*
    + * kernel page flags
    + */
    +
    +#define KPF_BYTES 8
    +#define PROC_KPAGEFLAGS "/proc/kpageflags"
    +
    +/* copied from kpageflags_read() */
    +#define KPF_LOCKED 0
    +#define KPF_ERROR 1
    +#define KPF_REFERENCED 2
    +#define KPF_UPTODATE 3
    +#define KPF_DIRTY 4
    +#define KPF_LRU 5
    +#define KPF_ACTIVE 6
    +#define KPF_SLAB 7
    +#define KPF_WRITEBACK 8
    +#define KPF_RECLAIM 9
    +#define KPF_BUDDY 10
    +
    +/* [11-20] new additions in 2.6.31 */
    +#define KPF_MMAP 11
    +#define KPF_ANON 12
    +#define KPF_SWAPCACHE 13
    +#define KPF_SWAPBACKED 14
    +#define KPF_COMPOUND_HEAD 15
    +#define KPF_COMPOUND_TAIL 16
    +#define KPF_HUGE 17
    +#define KPF_UNEVICTABLE 18
    +#define KPF_NOPAGE 20
    +
    +/* [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 char *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_NOPAGE] = "n:nopage",
    +
    + [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",
    +};
    +
    +
    +/*
    + * 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_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;
    +
    +#define PAGES_BATCH (64 << 10) /* 64k pages */
    +static int kpageflags_fd;
    +static uint64_t kpageflags_buf[KPF_BYTES * PAGES_BATCH];
    +
    +#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; })
    +
    +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);
    +}
    +
    +
    +/*
    + * page flag names
    + */
    +
    +static char *page_flag_name(uint64_t flags)
    +{
    + static char buf[65];
    + int present;
    + int 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("unkown 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];
    + int 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 offset, uint64_t flags)
    +{
    + static uint64_t flags0;
    + static unsigned long index;
    + static unsigned long count;
    +
    + if (flags == flags0 && offset == index + count) {
    + count++;
    + return;
    + }
    +
    + if (count)
    + printf("%lu\t%lu\t%s\n",
    + index, count, page_flag_name(flags0));
    +
    + flags0 = flags;
    + index = offset;
    + count = 1;
    +}
    +
    +static void show_page(unsigned long offset, uint64_t flags)
    +{
    + printf("%lu\t%s\n", offset, page_flag_name(flags));
    +}
    +
    +static void show_summary(void)
    +{
    + int 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;
    +}
    +
    +
    +/*
    + * page frame walker
    + */
    +
    +static int hash_slot(uint64_t flags)
    +{
    + int k = HASH_KEY(flags);
    + int i;
    +
    + /* Explicitly reserve slot 0 for flags 0: the following logic
    + * cannot distinguish an unoccupied slot from slot (flags==0).
    + */
    + if (flags == 0)
    + return 0;
    +
    + /* search through the remaining (HASH_SIZE-1) slots */
    + for (i = 1; i < ARRAY_SIZE(page_flags); i++, k++) {
    + if (!k || k >= ARRAY_SIZE(page_flags))
    + k = 1;
    + if (page_flags[k] == 0) {
    + page_flags[k] = flags;
    + return k;
    + }
    + if (page_flags[k] == flags)
    + return k;
    + }
    +
    + fatal("hash table full: bump up HASH_SHIFT?\n");
    + exit(EXIT_FAILURE);
    +}
    +
    +static void add_page(unsigned long offset, uint64_t flags)
    +{
    + flags = expand_overloaded_flags(flags);
    +
    + if (!opt_raw)
    + flags = well_known_flags(flags);
    +
    + if (!bit_mask_ok(flags))
    + return;
    +
    + if (opt_list == 1)
    + show_page_range(offset, flags);
    + else if (opt_list == 2)
    + show_page(offset, flags);
    +
    + nr_pages[hash_slot(flags)]++;
    + total_pages++;
    +}
    +
    +static void walk_pfn(unsigned long index, unsigned long count)
    +{
    + unsigned long batch;
    + unsigned long n;
    + unsigned long i;
    +
    + if (index > ULONG_MAX / KPF_BYTES)
    + fatal("index overflow: %lu\n", index);
    +
    + lseek(kpageflags_fd, index * KPF_BYTES, SEEK_SET);
    +
    + while (count) {
    + batch = min_t(unsigned long, count, PAGES_BATCH);
    + n = read(kpageflags_fd, kpageflags_buf, batch * KPF_BYTES);
    + if (n == 0)
    + break;
    + if (n < 0) {
    + perror(PROC_KPAGEFLAGS);
    + exit(EXIT_FAILURE);
    + }
    +
    + if (n % KPF_BYTES != 0)
    + fatal("partial read: %lu bytes\n", n);
    + n = n / KPF_BYTES;
    +
    + for (i = 0; i < n; i++)
    + add_page(index + i, kpageflags_buf[i]);
    +
    + index += batch;
    + count -= batch;
    + }
    +}
    +
    +static void walk_addr_ranges(void)
    +{
    + int i;
    +
    + kpageflags_fd = open(PROC_KPAGEFLAGS, O_RDONLY);
    + if (kpageflags_fd < 0) {
    + perror(PROC_KPAGEFLAGS);
    + exit(EXIT_FAILURE);
    + }
    +
    + if (!nr_addr_ranges)
    + walk_pfn(0, ULONG_MAX);
    +
    + for (i = 0; i < nr_addr_ranges; i++)
    + walk_pfn(opt_offset[i], opt_size[i]);
    +
    + close(kpageflags_fd);
    +}
    +
    +
    +/*
    + * user interface
    + */
    +
    +static const char *page_flag_type(uint64_t flag)
    +{
    + if (flag & KPF_HACKERS_BITS)
    + return "(r)";
    + if (flag & KPF_OVERLOADED_BITS)
    + return "(o)";
    + return " ";
    +}
    +
    +static void usage(void)
    +{
    + int i, j;
    +
    + printf(
    +"page-types [options]\n"
    +" -r|--raw Raw mode, for kernel developers\n"
    +" -a|--addr addr-spec Walk a range of pages\n"
    +" -b|--bits bits-spec Walk pages with specified bits\n"
    +#if 0 /* planned features */
    +" -p|--pid pid Walk process address space\n"
    +" -f|--file filename Walk file address space\n"
    +#endif
    +" -l|--list Show page details in ranges\n"
    +" -L|--list-each Show page details one by one\n"
    +" -N|--no-summary Don't show summay info\n"
    +" -h|--help Show this usage message\n"
    +"addr-spec:\n"
    +" N one page at offset N (unit: pages)\n"
    +" N+M pages range from N to N+M-1\n"
    +" N,M pages range from N to M-1\n"
    +" N, pages range from N to end\n"
    +" ,M pages range from 0 to M\n"
    +"bits-spec:\n"
    +" bit1,bit2 (flags & (bit1|bit2)) != 0\n"
    +" bit1,bit2=bit1 (flags & (bit1|bit2)) == bit1\n"
    +" bit1,~bit2 (flags & (bit1|bit2)) == bit1\n"
    +" =bit1,bit2 flags == (bit1|bit2)\n"
    +"bit-names:\n"
    + );
    +
    + for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
    + if (!page_flag_names[i])
    + continue;
    + printf("%16s%s", page_flag_names[i] + 2,
    + page_flag_type(1ULL << i));
    + if (++j > 3) {
    + j = 0;
    + putchar('\n');
    + }
    + }
    + printf("\n "
    + "(r) raw mode bits (o) overloaded bits\n");
    +}
    +
    +static unsigned long long parse_number(const char *str)
    +{
    + unsigned long long n;
    +
    + n = strtoll(str, NULL, 0);
    +
    + if (n == 0 && str[0] != '0')
    + fatal("invalid name or number: %s\n", str);
    +
    + return n;
    +}
    +
    +static void parse_pid(const char *str)
    +{
    + opt_pid = parse_number(str);
    +}
    +
    +static void parse_file(const char *name)
    +{
    +}
    +
    +static void add_addr_range(unsigned long offset, unsigned long size)
    +{
    + if (nr_addr_ranges >= MAX_ADDR_RANGES)
    + fatal("too much addr ranges\n");
    +
    + opt_offset[nr_addr_ranges] = offset;
    + opt_size[nr_addr_ranges] = size;
    + nr_addr_ranges++;
    +}
    +
    +static void parse_addr_range(const char *optarg)
    +{
    + unsigned long offset;
    + unsigned long size;
    + char *p;
    +
    + p = strchr(optarg, ',');
    + if (!p)
    + p = strchr(optarg, '+');
    +
    + if (p == optarg) {
    + offset = 0;
    + size = parse_number(p + 1);
    + } else if (p) {
    + offset = parse_number(optarg);
    + if (p[1] == '\0')
    + size = ULONG_MAX;
    + else {
    + size = parse_number(p + 1);
    + if (*p == ',') {
    + if (size < offset)
    + fatal("invalid range: %lu,%lu\n",
    + offset, size);
    + size -= offset;
    + }
    + }
    + } else {
    + offset = parse_number(optarg);
    + size = 1;
    + }
    +
    + add_addr_range(offset, size);
    +}
    +
    +static void add_bits_filter(uint64_t mask, uint64_t bits)
    +{
    + if (nr_bit_filters >= MAX_BIT_FILTERS)
    + fatal("too much bit filters\n");
    +
    + opt_mask[nr_bit_filters] = mask;
    + opt_bits[nr_bit_filters] = bits;
    + nr_bit_filters++;
    +}
    +
    +static uint64_t parse_flag_name(const char *str, int len)
    +{
    + int i;
    +
    + if (!*str || !len)
    + return 0;
    +
    + if (len <= 8 && !strncmp(str, "compound", len))
    + return BITS_COMPOUND;
    +
    + for (i = 0; i < ARRAY_SIZE(page_flag_names); i++) {
    + if (!page_flag_names[i])
    + continue;
    + if (!strncmp(str, page_flag_names[i] + 2, len))
    + return 1ULL << i;
    + }
    +
    + return parse_number(str);
    +}
    +
    +static uint64_t parse_flag_names(const char *str, int all)
    +{
    + const char *p = str;
    + uint64_t flags = 0;
    +
    + while (1) {
    + if (*p == ',' || *p == '=' || *p == '\0') {
    + if ((*str != '~') || (*str == '~' && all && *++str))
    + flags |= parse_flag_name(str, p - str);
    + if (*p != ',')
    + break;
    + str = p + 1;
    + }
    + p++;
    + }
    +
    + return flags;
    +}
    +
    +static void parse_bits_mask(const char *optarg)
    +{
    + uint64_t mask;
    + uint64_t bits;
    + const char *p;
    +
    + p = strchr(optarg, '=');
    + if (p == optarg) {
    + mask = KPF_ALL_BITS;
    + bits = parse_flag_names(p + 1, 0);
    + } else if (p) {
    + mask = parse_flag_names(optarg, 0);
    + bits = parse_flag_names(p + 1, 0);
    + } else if (strchr(optarg, '~')) {
    + mask = parse_flag_names(optarg, 1);
    + bits = parse_flag_names(optarg, 0);
    + } else {
    + mask = parse_flag_names(optarg, 0);
    + bits = KPF_ALL_BITS;
    + }
    +
    + add_bits_filter(mask, bits);
    +}
    +
    +
    +static struct option opts[] = {
    + { "raw" , 0, NULL, 'r' },
    + { "pid" , 1, NULL, 'p' },
    + { "file" , 1, NULL, 'f' },
    + { "addr" , 1, NULL, 'a' },
    + { "bits" , 1, NULL, 'b' },
    + { "list" , 0, NULL, 'l' },
    + { "list-each" , 0, NULL, 'L' },
    + { "no-summary", 0, NULL, 'N' },
    + { "help" , 0, NULL, 'h' },
    + { NULL , 0, NULL, 0 }
    +};
    +
    +int main(int argc, char *argv[])
    +{
    + int c;
    +
    + page_size = getpagesize();
    +
    + while ((c = getopt_long(argc, argv,
    + "rp:f:a:b:lLNh", opts, NULL)) != -1) {
    + switch (c) {
    + case 'r':
    + opt_raw = 1;
    + break;
    + case 'p':
    + parse_pid(optarg);
    + break;
    + case 'f':
    + parse_file(optarg);
    + break;
    + case 'a':
    + parse_addr_range(optarg);
    + break;
    + case 'b':
    + parse_bits_mask(optarg);
    + break;
    + case 'l':
    + opt_list = 1;
    + break;
    + case 'L':
    + opt_list = 2;
    + break;
    + case 'N':
    + opt_no_summary = 1;
    + break;
    + case 'h':
    + usage();
    + exit(0);
    + default:
    + usage();
    + exit(1);
    + }
    + }
    +
    + if (opt_list == 1)
    + printf("offset\tcount\tflags\n");
    + if (opt_list == 2)
    + printf("offset\tflags\n");
    +
    + walk_addr_ranges();
    +
    + if (opt_list == 1)
    + show_page_range(0, 0); /* drain the buffer */
    +
    + if (opt_no_summary)
    + return 0;
    +
    + if (opt_list)
    + printf("\n\n");
    +
    + show_summary();
    +
    + return 0;
    +}
    --- linux-mm.orig/Documentation/vm/.gitignore 2009-08-31 14:10:15.000000000 +0800
    +++ linux-mm/Documentation/vm/.gitignore 2009-09-02 11:32:08.000000000 +0800
    @@ -1,2 +1 @@
    -page-types
    slabinfo
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-mm/tools/vm/.gitignore 2009-09-02 11:32:08.000000000 +0800
    @@ -0,0 +1 @@
    +page-types
    --- linux-mm.orig/Documentation/vm/Makefile 2009-08-31 14:40:44.000000000 +0800
    +++ linux-mm/Documentation/vm/Makefile 2009-09-02 11:32:08.000000000 +0800
    @@ -2,7 +2,7 @@
    obj- := dummy.o

    # List of programs to build
    -hostprogs-y := slabinfo page-types
    +hostprogs-y := slabinfo

    # Tell kbuild to always build the programs
    always := $(hostprogs-y)
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-mm/tools/vm/Makefile 2009-09-02 11:32:08.000000000 +0800
    @@ -0,0 +1,5 @@
    +# List of programs to build
    +hostprogs-y := page-types
    +
    +# Tell kbuild to always build the programs
    +always := $(hostprogs-y)
    --- linux-mm.orig/Documentation/vm/pagemap.txt 2009-09-02 11:33:25.000000000 +0800
    +++ linux-mm/Documentation/vm/pagemap.txt 2009-09-02 11:35:07.000000000 +0800
    @@ -110,7 +110,9 @@ Short descriptions to the page flags:
    13. SWAPCACHE page is mapped to swap space, ie. has an associated swap entry
    14. SWAPBACKED page is backed by swap/RAM

    -The page-types tool in this directory can be used to query the above flags.
    +The page-types tool can be used to query the above flags:
    +
    + gcc -o page-types tools/vm/page-types.c

    Using pagemap to do something useful:

    --



    \
     
     \ /
      Last update: 2009-09-02 06:05    [W:0.095 / U:1.192 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site