| .. | .. |
|---|
| 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 */ |
|---|