page-types: make standalone pagemap/kpageflags read routines
authorWu Fengguang <fengguang.wu@intel.com>
Wed, 7 Oct 2009 23:32:30 +0000 (16:32 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 8 Oct 2009 14:36:39 +0000 (07:36 -0700)
Refactor the code to be more modular and easier to reuse.

Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Cc: Andi Kleen <andi@firstfloor.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Documentation/vm/page-types.c

index 6bdcc0632c245d97a6c87699c07ca62296a188b2..18e891a329e0fa227ba22af83fe26498678af2cb 100644 (file)
@@ -161,8 +161,6 @@ static unsigned long        pg_start[MAX_VMAS];
 static unsigned long   pg_end[MAX_VMAS];
 static unsigned long   voffset;
 
-static int             pagemap_fd;
-
 #define MAX_BIT_FILTERS        64
 static int             nr_bit_filters;
 static uint64_t                opt_mask[MAX_BIT_FILTERS];
@@ -170,7 +168,7 @@ static uint64_t             opt_bits[MAX_BIT_FILTERS];
 
 static int             page_size;
 
-#define PAGES_BATCH    (64 << 10)      /* 64k pages */
+static int             pagemap_fd;
 static int             kpageflags_fd;
 
 #define HASH_SHIFT     13
@@ -226,6 +224,62 @@ int checked_open(const char *pathname, int flags)
        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
@@ -432,79 +486,53 @@ static void add_page(unsigned long offset, uint64_t flags)
        total_pages++;
 }
 
+#define KPAGEFLAGS_BATCH       (64 << 10)      /* 64k pages */
 static void walk_pfn(unsigned long index, unsigned long count)
 {
+       uint64_t buf[KPAGEFLAGS_BATCH];
        unsigned long batch;
-       unsigned long n;
+       unsigned long pages;
        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) {
-               uint64_t kpageflags_buf[KPF_BYTES * PAGES_BATCH];
-
-               batch = min_t(unsigned long, count, PAGES_BATCH);
-               n = read(kpageflags_fd, kpageflags_buf, batch * KPF_BYTES);
-               if (n == 0)
+               batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH);
+               pages = kpageflags_read(buf, index, batch);
+               if (pages == 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]);
+               for (i = 0; i < pages; i++)
+                       add_page(index + i, buf[i]);
 
-               index += batch;
-               count -= batch;
+               index += pages;
+               count -= pages;
        }
 }
 
-
-#define PAGEMAP_BATCH  4096
-static unsigned long task_pfn(unsigned long pgoff)
+#define PAGEMAP_BATCH  (64 << 10)
+static void walk_vma(unsigned long index, unsigned long count)
 {
-       static uint64_t buf[PAGEMAP_BATCH];
-       static unsigned long start;
-       static long count;
-       uint64_t pfn;
+       uint64_t buf[PAGEMAP_BATCH];
+       unsigned long batch;
+       unsigned long pages;
+       unsigned long pfn;
+       unsigned long i;
 
-       if (pgoff < start || pgoff >= start + count) {
-               if (lseek64(pagemap_fd,
-                           (uint64_t)pgoff * PM_ENTRY_BYTES,
-                           SEEK_SET) < 0) {
-                       perror("pagemap seek");
-                       exit(EXIT_FAILURE);
-               }
-               count = read(pagemap_fd, buf, sizeof(buf));
-               if (count == 0)
-                       return 0;
-               if (count < 0) {
-                       perror("pagemap read");
-                       exit(EXIT_FAILURE);
-               }
-               if (count % PM_ENTRY_BYTES) {
-                       fatal("pagemap read not aligned.\n");
-                       exit(EXIT_FAILURE);
-               }
-               count /= PM_ENTRY_BYTES;
-               start = pgoff;
-       }
+       while (count) {
+               batch = min_t(unsigned long, count, PAGEMAP_BATCH);
+               pages = pagemap_read(buf, index, batch);
+               if (pages == 0)
+                       break;
 
-       pfn = buf[pgoff - start];
-       if (pfn & PM_PRESENT)
-               pfn = PM_PFRAME(pfn);
-       else
-               pfn = 0;
+               for (i = 0; i < pages; i++) {
+                       pfn = pagemap_pfn(buf[i]);
+                       voffset = index + i;
+                       if (pfn)
+                               walk_pfn(pfn, 1);
+               }
 
-       return pfn;
+               index += pages;
+               count -= pages;
+       }
 }
 
 static void walk_task(unsigned long index, unsigned long count)
@@ -524,11 +552,7 @@ static void walk_task(unsigned long index, unsigned long count)
                index   = min_t(unsigned long, pg_end[i], end);
 
                assert(voffset < index);
-               for (; voffset < index; voffset++) {
-                       unsigned long pfn = task_pfn(voffset);
-                       if (pfn)
-                               walk_pfn(pfn, 1);
-               }
+               walk_vma(voffset, index - voffset);
        }
 }