Whamcloud - gitweb
LU-12461 contrib: Add epython scripts for crash dump analysis
[fs/lustre-release.git] / contrib / debug_tools / epython_scripts / crashlib / page.py
1 """
2 Constants and routines for manipulating kernel page struct.
3 Copyright 2014-2017 Cray Inc.  All Rights Reserved
4 """
5
6 from pykdump.API import *
7
8 import crashlib.cid
9 import crashlib.cid.machdep_table
10 import crashlib.cid.page_flags
11 import crashlib.cid.phys_mem_map
12 import crashlib.memarray
13
14 # --------------------------------------------------------------------------
15
16 page_struct_size = getSizeOf('struct page')
17
18 # --------------------------------------------------------------------------
19
20 # Create a function for determining whether a page is controlled by the
21 # buddy allocator.  Note that earlier kernels (< 3.0) have a page flag, while
22 # later kernels use the _mapcount field.
23
24 if hasattr(crashlib.cid.pgflags, 'PG_buddy'):
25     def is_buddy_page(page):
26         return page.flags & crashlib.cid.pgflags.PG_buddy.mask;
27 else:
28     def is_buddy_page(page):
29         # Early implementations used -2, later use -128
30         return page._mapcount.counter == -128 or page._mapcount.counter == -2
31
32 if hasattr(crashlib.cid.pgflags, 'PG_compound'):
33     def is_compound_page_head(page):
34         return (page.flags & (crashlib.cid.pgflags.PG_reclaim.mask |
35                               crashlib.cid.pgflags.PG_compound.mask)
36                ) == crashlib.cid.pgflags.PG_compound
37
38     def is_compound_page_tail(page):
39         return (page.flags & (crashlib.cid.pgflags.PG_reclaim.mask |
40                               crashlib.cid.pgflags.PG_compound.mask)
41                ) == (crashlib.cid.pgflags.PG_reclaim.mask |
42                      crashlib.cid.pgflags.PG_compound.mask)
43
44     def is_compound_page(page):
45         return page.flags & crashlib.cid.pgflags.PG_compound.mask
46
47 elif hasattr(crashlib.cid.pgflags, 'PG_tail'):
48     # PG_head and PG_tail defined
49     def is_compound_page_head(page):
50         return page.flags & (crashlib.cid.pgflags.PG_head.mask)
51
52     def is_compound_page_tail(page):
53         return page.flags & (crashlib.cid.pgflags.PG_tail.mask)
54
55     def is_compound_page(page):
56         return is_compound_page_head(page) or is_compound_page_tail(page)
57
58 else:
59     # Only PG_head is defined
60     def is_compound_page_head(page):
61         return page.flags & (crashlib.cid.pgflags.PG_head.mask)
62
63     def is_compound_page_tail(page):
64         return page.compound_head & 1
65
66     def is_compound_page(page):
67         return is_compound_page_head(page) or is_compound_page_tail(page)
68
69 # --------------------------------------------------------------------------
70
71 # Find the page order of a buddy page
72
73 def buddy_order(page):
74     """Retrieve the order of a page in the buddy allocator"""
75     return page.private
76
77 # --------------------------------------------------------------------------
78
79 # Create a function to determine the page order of a compound page
80
81 if member_offset('struct page', 'compound_order') > -1:
82     def compound_order(page):
83         """Retrieve the page order for a compound page."""
84         # A compound page is a series of contiguous pages, thus there are
85         # at least two page structs.  The second page struct (first tail page)
86         # contains the page order; the head page uses the space for a
87         # different purpose.
88         return page[1].compound_order
89
90 else:
91     def compound_order(page):
92         """Retrieve the page order for a compound page."""
93         # A compound page is a series of contiguous pages, thus there are
94         # at least two page structs.  The second page struct (first tail page)
95         # contains the page order stored in the lru.prev field; the head page
96         # uses the space for a different purpose.
97         return page[1].lru.prev
98
99 # --------------------------------------------------------------------------
100
101 def pfn(page):
102     """Returns the pfn for the supplied page struct or page struct address."""
103     vmemmap_vaddr = crashlib.cid.mdtbl.vmemmap_vaddr
104     return (page - vmemmap_vaddr) / page_struct_size
105
106 # --------------------------------------------------------------------------
107
108 def page_list():
109     """Return a list-like class of page structs indexed by pfn.
110
111     This implementation assumes the kernel is configured with a virtually
112     contiguous mem_map.
113     """
114     # If the kernel doesn't have a virtually contiguous mem_map, this could
115     # be changed to return a chained list of MemCArray objects.
116
117     PAGE_SHIFT = crashlib.cid.mdtbl.pageshift
118     pfn_start  = crashlib.cid.physmap[0].start >> PAGE_SHIFT
119     pfn_end    = crashlib.cid.physmap[-1].end >> PAGE_SHIFT
120
121     # Find page map and create an array of page_struct
122     vmemmap_addr = crashlib.cid.mdtbl.vmemmap_vaddr
123
124     return crashlib.memarray.MemCArray(vmemmap_addr,
125                                         lambda a:readSU('struct page',a),
126                                         getSizeOf('struct page'),
127                                         pfn_end-pfn_start)