.. | .. |
---|
13 | 13 | #include <trace/events/mmflags.h> |
---|
14 | 14 | #include <linux/migrate.h> |
---|
15 | 15 | #include <linux/page_owner.h> |
---|
| 16 | +#include <linux/page_pinner.h> |
---|
| 17 | +#include <linux/ctype.h> |
---|
16 | 18 | |
---|
17 | 19 | #include "internal.h" |
---|
18 | 20 | |
---|
19 | | -char *migrate_reason_names[MR_TYPES] = { |
---|
| 21 | +const char *migrate_reason_names[MR_TYPES] = { |
---|
20 | 22 | "compaction", |
---|
21 | 23 | "memory_failure", |
---|
22 | 24 | "memory_hotplug", |
---|
.. | .. |
---|
43 | 45 | |
---|
44 | 46 | void __dump_page(struct page *page, const char *reason) |
---|
45 | 47 | { |
---|
| 48 | + struct page *head = compound_head(page); |
---|
| 49 | + struct address_space *mapping; |
---|
46 | 50 | bool page_poisoned = PagePoisoned(page); |
---|
| 51 | + bool compound = PageCompound(page); |
---|
| 52 | + /* |
---|
| 53 | + * Accessing the pageblock without the zone lock. It could change to |
---|
| 54 | + * "isolate" again in the meantime, but since we are just dumping the |
---|
| 55 | + * state for debugging, it should be fine to accept a bit of |
---|
| 56 | + * inaccuracy here due to racing. |
---|
| 57 | + */ |
---|
| 58 | + bool page_cma = is_migrate_cma_page(page); |
---|
47 | 59 | int mapcount; |
---|
| 60 | + char *type = ""; |
---|
48 | 61 | |
---|
49 | 62 | /* |
---|
50 | 63 | * If struct page is poisoned don't access Page*() functions as that |
---|
.. | .. |
---|
52 | 65 | * dump_page() when detected. |
---|
53 | 66 | */ |
---|
54 | 67 | if (page_poisoned) { |
---|
55 | | - pr_emerg("page:%px is uninitialized and poisoned", page); |
---|
| 68 | + pr_warn("page:%px is uninitialized and poisoned", page); |
---|
56 | 69 | goto hex_only; |
---|
| 70 | + } |
---|
| 71 | + |
---|
| 72 | + if (page < head || (page >= head + MAX_ORDER_NR_PAGES)) { |
---|
| 73 | + /* |
---|
| 74 | + * Corrupt page, so we cannot call page_mapping. Instead, do a |
---|
| 75 | + * safe subset of the steps that page_mapping() does. Caution: |
---|
| 76 | + * this will be misleading for tail pages, PageSwapCache pages, |
---|
| 77 | + * and potentially other situations. (See the page_mapping() |
---|
| 78 | + * implementation for what's missing here.) |
---|
| 79 | + */ |
---|
| 80 | + unsigned long tmp = (unsigned long)page->mapping; |
---|
| 81 | + |
---|
| 82 | + if (tmp & PAGE_MAPPING_ANON) |
---|
| 83 | + mapping = NULL; |
---|
| 84 | + else |
---|
| 85 | + mapping = (void *)(tmp & ~PAGE_MAPPING_FLAGS); |
---|
| 86 | + head = page; |
---|
| 87 | + compound = false; |
---|
| 88 | + } else { |
---|
| 89 | + mapping = page_mapping(page); |
---|
57 | 90 | } |
---|
58 | 91 | |
---|
59 | 92 | /* |
---|
.. | .. |
---|
61 | 94 | * page->_mapcount space in struct page is used by sl[aou]b pages to |
---|
62 | 95 | * encode own info. |
---|
63 | 96 | */ |
---|
64 | | - mapcount = PageSlab(page) ? 0 : page_mapcount(page); |
---|
| 97 | + mapcount = PageSlab(head) ? 0 : page_mapcount(page); |
---|
65 | 98 | |
---|
66 | | - pr_emerg("page:%px count:%d mapcount:%d mapping:%px index:%#lx", |
---|
67 | | - page, page_ref_count(page), mapcount, |
---|
68 | | - page->mapping, page_to_pgoff(page)); |
---|
69 | | - if (PageCompound(page)) |
---|
70 | | - pr_cont(" compound_mapcount: %d", compound_mapcount(page)); |
---|
71 | | - pr_cont("\n"); |
---|
| 99 | + pr_warn("page:%p refcount:%d mapcount:%d mapping:%p index:%#lx pfn:%#lx\n", |
---|
| 100 | + page, page_ref_count(head), mapcount, mapping, |
---|
| 101 | + page_to_pgoff(page), page_to_pfn(page)); |
---|
| 102 | + if (compound) { |
---|
| 103 | + if (hpage_pincount_available(page)) { |
---|
| 104 | + pr_warn("head:%p order:%u compound_mapcount:%d compound_pincount:%d\n", |
---|
| 105 | + head, compound_order(head), |
---|
| 106 | + head_compound_mapcount(head), |
---|
| 107 | + head_compound_pincount(head)); |
---|
| 108 | + } else { |
---|
| 109 | + pr_warn("head:%p order:%u compound_mapcount:%d\n", |
---|
| 110 | + head, compound_order(head), |
---|
| 111 | + head_compound_mapcount(head)); |
---|
| 112 | + } |
---|
| 113 | + } |
---|
| 114 | + if (PageKsm(page)) |
---|
| 115 | + type = "ksm "; |
---|
| 116 | + else if (PageAnon(page)) |
---|
| 117 | + type = "anon "; |
---|
| 118 | + else if (mapping) { |
---|
| 119 | + struct inode *host; |
---|
| 120 | + const struct address_space_operations *a_ops; |
---|
| 121 | + struct hlist_node *dentry_first; |
---|
| 122 | + struct dentry *dentry_ptr; |
---|
| 123 | + struct dentry dentry; |
---|
| 124 | + unsigned long ino; |
---|
| 125 | + |
---|
| 126 | + /* |
---|
| 127 | + * mapping can be invalid pointer and we don't want to crash |
---|
| 128 | + * accessing it, so probe everything depending on it carefully |
---|
| 129 | + */ |
---|
| 130 | + if (get_kernel_nofault(host, &mapping->host) || |
---|
| 131 | + get_kernel_nofault(a_ops, &mapping->a_ops)) { |
---|
| 132 | + pr_warn("failed to read mapping contents, not a valid kernel address?\n"); |
---|
| 133 | + goto out_mapping; |
---|
| 134 | + } |
---|
| 135 | + |
---|
| 136 | + if (!host) { |
---|
| 137 | + pr_warn("aops:%ps\n", a_ops); |
---|
| 138 | + goto out_mapping; |
---|
| 139 | + } |
---|
| 140 | + |
---|
| 141 | + if (get_kernel_nofault(dentry_first, &host->i_dentry.first) || |
---|
| 142 | + get_kernel_nofault(ino, &host->i_ino)) { |
---|
| 143 | + pr_warn("aops:%ps with invalid host inode %px\n", |
---|
| 144 | + a_ops, host); |
---|
| 145 | + goto out_mapping; |
---|
| 146 | + } |
---|
| 147 | + |
---|
| 148 | + if (!dentry_first) { |
---|
| 149 | + pr_warn("aops:%ps ino:%lx\n", a_ops, ino); |
---|
| 150 | + goto out_mapping; |
---|
| 151 | + } |
---|
| 152 | + |
---|
| 153 | + dentry_ptr = container_of(dentry_first, struct dentry, d_u.d_alias); |
---|
| 154 | + if (get_kernel_nofault(dentry, dentry_ptr)) { |
---|
| 155 | + pr_warn("aops:%ps ino:%lx with invalid dentry %px\n", |
---|
| 156 | + a_ops, ino, dentry_ptr); |
---|
| 157 | + } else { |
---|
| 158 | + /* |
---|
| 159 | + * if dentry is corrupted, the %pd handler may still |
---|
| 160 | + * crash, but it's unlikely that we reach here with a |
---|
| 161 | + * corrupted struct page |
---|
| 162 | + */ |
---|
| 163 | + pr_warn("aops:%ps ino:%lx dentry name:\"%pd\"\n", |
---|
| 164 | + a_ops, ino, &dentry); |
---|
| 165 | + } |
---|
| 166 | + } |
---|
| 167 | +out_mapping: |
---|
72 | 168 | BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1); |
---|
73 | 169 | |
---|
74 | | - pr_emerg("flags: %#lx(%pGp)\n", page->flags, &page->flags); |
---|
| 170 | + pr_warn("%sflags: %#lx(%pGp)%s\n", type, head->flags, &head->flags, |
---|
| 171 | + page_cma ? " CMA" : ""); |
---|
75 | 172 | |
---|
76 | 173 | hex_only: |
---|
77 | | - print_hex_dump(KERN_ALERT, "raw: ", DUMP_PREFIX_NONE, 32, |
---|
| 174 | + print_hex_dump(KERN_WARNING, "raw: ", DUMP_PREFIX_NONE, 32, |
---|
78 | 175 | sizeof(unsigned long), page, |
---|
| 176 | + sizeof(struct page), false); |
---|
| 177 | + if (head != page) |
---|
| 178 | + print_hex_dump(KERN_WARNING, "head: ", DUMP_PREFIX_NONE, 32, |
---|
| 179 | + sizeof(unsigned long), head, |
---|
79 | 180 | sizeof(struct page), false); |
---|
80 | 181 | |
---|
81 | 182 | if (reason) |
---|
82 | | - pr_alert("page dumped because: %s\n", reason); |
---|
| 183 | + pr_warn("page dumped because: %s\n", reason); |
---|
83 | 184 | |
---|
84 | 185 | #ifdef CONFIG_MEMCG |
---|
85 | 186 | if (!page_poisoned && page->mem_cgroup) |
---|
86 | | - pr_alert("page->mem_cgroup:%px\n", page->mem_cgroup); |
---|
| 187 | + pr_warn("page->mem_cgroup:%px\n", page->mem_cgroup); |
---|
87 | 188 | #endif |
---|
88 | 189 | } |
---|
89 | 190 | |
---|
.. | .. |
---|
91 | 192 | { |
---|
92 | 193 | __dump_page(page, reason); |
---|
93 | 194 | dump_page_owner(page); |
---|
| 195 | + dump_page_pinner(page); |
---|
94 | 196 | } |
---|
95 | 197 | EXPORT_SYMBOL(dump_page); |
---|
96 | 198 | |
---|
.. | .. |
---|
121 | 223 | "mmap_base %lu mmap_legacy_base %lu highest_vm_end %lu\n" |
---|
122 | 224 | "pgd %px mm_users %d mm_count %d pgtables_bytes %lu map_count %d\n" |
---|
123 | 225 | "hiwater_rss %lx hiwater_vm %lx total_vm %lx locked_vm %lx\n" |
---|
124 | | - "pinned_vm %lx data_vm %lx exec_vm %lx stack_vm %lx\n" |
---|
| 226 | + "pinned_vm %llx data_vm %lx exec_vm %lx stack_vm %lx\n" |
---|
125 | 227 | "start_code %lx end_code %lx start_data %lx end_data %lx\n" |
---|
126 | 228 | "start_brk %lx brk %lx start_stack %lx\n" |
---|
127 | 229 | "arg_start %lx arg_end %lx env_start %lx env_end %lx\n" |
---|
.. | .. |
---|
134 | 236 | #endif |
---|
135 | 237 | "exe_file %px\n" |
---|
136 | 238 | #ifdef CONFIG_MMU_NOTIFIER |
---|
137 | | - "mmu_notifier_mm %px\n" |
---|
| 239 | + "notifier_subscriptions %px\n" |
---|
138 | 240 | #endif |
---|
139 | 241 | #ifdef CONFIG_NUMA_BALANCING |
---|
140 | 242 | "numa_next_scan %lu numa_scan_offset %lu numa_scan_seq %d\n" |
---|
.. | .. |
---|
152 | 254 | mm_pgtables_bytes(mm), |
---|
153 | 255 | mm->map_count, |
---|
154 | 256 | mm->hiwater_rss, mm->hiwater_vm, mm->total_vm, mm->locked_vm, |
---|
155 | | - mm->pinned_vm, mm->data_vm, mm->exec_vm, mm->stack_vm, |
---|
| 257 | + (u64)atomic64_read(&mm->pinned_vm), |
---|
| 258 | + mm->data_vm, mm->exec_vm, mm->stack_vm, |
---|
156 | 259 | mm->start_code, mm->end_code, mm->start_data, mm->end_data, |
---|
157 | 260 | mm->start_brk, mm->brk, mm->start_stack, |
---|
158 | 261 | mm->arg_start, mm->arg_end, mm->env_start, mm->env_end, |
---|
.. | .. |
---|
165 | 268 | #endif |
---|
166 | 269 | mm->exe_file, |
---|
167 | 270 | #ifdef CONFIG_MMU_NOTIFIER |
---|
168 | | - mm->mmu_notifier_mm, |
---|
| 271 | + mm->notifier_subscriptions, |
---|
169 | 272 | #endif |
---|
170 | 273 | #ifdef CONFIG_NUMA_BALANCING |
---|
171 | 274 | mm->numa_next_scan, mm->numa_scan_offset, mm->numa_scan_seq, |
---|
.. | .. |
---|
175 | 278 | ); |
---|
176 | 279 | } |
---|
177 | 280 | |
---|
| 281 | +static bool page_init_poisoning __read_mostly = true; |
---|
| 282 | + |
---|
| 283 | +static int __init setup_vm_debug(char *str) |
---|
| 284 | +{ |
---|
| 285 | + bool __page_init_poisoning = true; |
---|
| 286 | + |
---|
| 287 | + /* |
---|
| 288 | + * Calling vm_debug with no arguments is equivalent to requesting |
---|
| 289 | + * to enable all debugging options we can control. |
---|
| 290 | + */ |
---|
| 291 | + if (*str++ != '=' || !*str) |
---|
| 292 | + goto out; |
---|
| 293 | + |
---|
| 294 | + __page_init_poisoning = false; |
---|
| 295 | + if (*str == '-') |
---|
| 296 | + goto out; |
---|
| 297 | + |
---|
| 298 | + while (*str) { |
---|
| 299 | + switch (tolower(*str)) { |
---|
| 300 | + case'p': |
---|
| 301 | + __page_init_poisoning = true; |
---|
| 302 | + break; |
---|
| 303 | + default: |
---|
| 304 | + pr_err("vm_debug option '%c' unknown. skipped\n", |
---|
| 305 | + *str); |
---|
| 306 | + } |
---|
| 307 | + |
---|
| 308 | + str++; |
---|
| 309 | + } |
---|
| 310 | +out: |
---|
| 311 | + if (page_init_poisoning && !__page_init_poisoning) |
---|
| 312 | + pr_warn("Page struct poisoning disabled by kernel command line option 'vm_debug'\n"); |
---|
| 313 | + |
---|
| 314 | + page_init_poisoning = __page_init_poisoning; |
---|
| 315 | + |
---|
| 316 | + return 1; |
---|
| 317 | +} |
---|
| 318 | +__setup("vm_debug", setup_vm_debug); |
---|
| 319 | + |
---|
| 320 | +void page_init_poison(struct page *page, size_t size) |
---|
| 321 | +{ |
---|
| 322 | + if (page_init_poisoning) |
---|
| 323 | + memset(page, PAGE_POISON_PATTERN, size); |
---|
| 324 | +} |
---|
| 325 | +EXPORT_SYMBOL_GPL(page_init_poison); |
---|
178 | 326 | #endif /* CONFIG_DEBUG_VM */ |
---|