Whamcloud - gitweb
LU-12461 contrib: Add epython scripts for crash dump analysis
[fs/lustre-release.git] / contrib / debug_tools / epython_scripts / crashlib / page.py
diff --git a/contrib/debug_tools/epython_scripts/crashlib/page.py b/contrib/debug_tools/epython_scripts/crashlib/page.py
new file mode 100644 (file)
index 0000000..ef87d05
--- /dev/null
@@ -0,0 +1,127 @@
+"""
+Constants and routines for manipulating kernel page struct.
+Copyright 2014-2017 Cray Inc.  All Rights Reserved
+"""
+
+from pykdump.API import *
+
+import crashlib.cid
+import crashlib.cid.machdep_table
+import crashlib.cid.page_flags
+import crashlib.cid.phys_mem_map
+import crashlib.memarray
+
+# --------------------------------------------------------------------------
+
+page_struct_size = getSizeOf('struct page')
+
+# --------------------------------------------------------------------------
+
+# Create a function for determining whether a page is controlled by the
+# buddy allocator.  Note that earlier kernels (< 3.0) have a page flag, while
+# later kernels use the _mapcount field.
+
+if hasattr(crashlib.cid.pgflags, 'PG_buddy'):
+    def is_buddy_page(page):
+        return page.flags & crashlib.cid.pgflags.PG_buddy.mask;
+else:
+    def is_buddy_page(page):
+        # Early implementations used -2, later use -128
+        return page._mapcount.counter == -128 or page._mapcount.counter == -2
+
+if hasattr(crashlib.cid.pgflags, 'PG_compound'):
+    def is_compound_page_head(page):
+        return (page.flags & (crashlib.cid.pgflags.PG_reclaim.mask |
+                              crashlib.cid.pgflags.PG_compound.mask)
+               ) == crashlib.cid.pgflags.PG_compound
+
+    def is_compound_page_tail(page):
+        return (page.flags & (crashlib.cid.pgflags.PG_reclaim.mask |
+                              crashlib.cid.pgflags.PG_compound.mask)
+               ) == (crashlib.cid.pgflags.PG_reclaim.mask |
+                     crashlib.cid.pgflags.PG_compound.mask)
+
+    def is_compound_page(page):
+        return page.flags & crashlib.cid.pgflags.PG_compound.mask
+
+elif hasattr(crashlib.cid.pgflags, 'PG_tail'):
+    # PG_head and PG_tail defined
+    def is_compound_page_head(page):
+        return page.flags & (crashlib.cid.pgflags.PG_head.mask)
+
+    def is_compound_page_tail(page):
+        return page.flags & (crashlib.cid.pgflags.PG_tail.mask)
+
+    def is_compound_page(page):
+        return is_compound_page_head(page) or is_compound_page_tail(page)
+
+else:
+    # Only PG_head is defined
+    def is_compound_page_head(page):
+        return page.flags & (crashlib.cid.pgflags.PG_head.mask)
+
+    def is_compound_page_tail(page):
+        return page.compound_head & 1
+
+    def is_compound_page(page):
+        return is_compound_page_head(page) or is_compound_page_tail(page)
+
+# --------------------------------------------------------------------------
+
+# Find the page order of a buddy page
+
+def buddy_order(page):
+    """Retrieve the order of a page in the buddy allocator"""
+    return page.private
+
+# --------------------------------------------------------------------------
+
+# Create a function to determine the page order of a compound page
+
+if member_offset('struct page', 'compound_order') > -1:
+    def compound_order(page):
+        """Retrieve the page order for a compound page."""
+        # A compound page is a series of contiguous pages, thus there are
+        # at least two page structs.  The second page struct (first tail page)
+        # contains the page order; the head page uses the space for a
+        # different purpose.
+        return page[1].compound_order
+
+else:
+    def compound_order(page):
+        """Retrieve the page order for a compound page."""
+        # A compound page is a series of contiguous pages, thus there are
+        # at least two page structs.  The second page struct (first tail page)
+        # contains the page order stored in the lru.prev field; the head page
+        # uses the space for a different purpose.
+        return page[1].lru.prev
+
+# --------------------------------------------------------------------------
+
+def pfn(page):
+    """Returns the pfn for the supplied page struct or page struct address."""
+    vmemmap_vaddr = crashlib.cid.mdtbl.vmemmap_vaddr
+    return (page - vmemmap_vaddr) / page_struct_size
+
+# --------------------------------------------------------------------------
+
+def page_list():
+    """Return a list-like class of page structs indexed by pfn.
+
+    This implementation assumes the kernel is configured with a virtually
+    contiguous mem_map.
+    """
+    # If the kernel doesn't have a virtually contiguous mem_map, this could
+    # be changed to return a chained list of MemCArray objects.
+
+    PAGE_SHIFT = crashlib.cid.mdtbl.pageshift
+    pfn_start  = crashlib.cid.physmap[0].start >> PAGE_SHIFT
+    pfn_end    = crashlib.cid.physmap[-1].end >> PAGE_SHIFT
+
+    # Find page map and create an array of page_struct
+    vmemmap_addr = crashlib.cid.mdtbl.vmemmap_vaddr
+
+    return crashlib.memarray.MemCArray(vmemmap_addr,
+                                        lambda a:readSU('struct page',a),
+                                        getSizeOf('struct page'),
+                                        pfn_end-pfn_start)