| 1 | |
| 2 | |
| 3 | * Generic show_mem() implementation
|
| 4 | *
|
| 5 | * Copyright (C) 2008 Johannes Weiner <[email protected]>
|
| 6 |
|
| 7 |
|
| 8 | #include <linux/blkdev.h>
|
| 9 | #include <linux/cma.h>
|
| 10 | #include <linux/cpuset.h>
|
| 11 | #include <linux/highmem.h>
|
| 12 | #include <linux/hugetlb.h>
|
| 13 | #include <linux/mm.h>
|
| 14 | #include <linux/mmzone.h>
|
| 15 | #include <linux/swap.h>
|
| 16 | #include <linux/vmstat.h>
|
| 17 |
|
| 18 | #include "internal.h"
|
| 19 | #include "page_alloc.h"
|
| 20 | #include "swap.h"
|
| 21 |
|
| 22 | atomic_long_t _totalram_pages __read_mostly;
|
| 23 | EXPORT_SYMBOL(_totalram_pages);
|
| 24 | unsigned long totalreserve_pages __read_mostly;
|
| 25 | unsigned long totalcma_pages __read_mostly;
|
| 26 |
|
| 27 | static inline void show_node(struct zone *zone)
|
| 28 | {
|
| 29 | if (IS_ENABLED(CONFIG_NUMA))
|
| 30 | printk("Node %d ", zone_to_nid(zone));
|
| 31 | }
|
| 32 |
|
| 33 | long si_mem_available(void)
|
| 34 | {
|
| 35 | long available;
|
| 36 | unsigned long pagecache;
|
| 37 | unsigned long wmark_low = 0;
|
| 38 | unsigned long reclaimable;
|
| 39 | struct zone *zone;
|
| 40 |
|
| 41 | for_each_zone(zone)
|
| 42 | wmark_low += low_wmark_pages(zone);
|
| 43 |
|
| 44 | |
| 45 | * Estimate the amount of memory available for userspace allocations,
|
| 46 | * without causing swapping or OOM.
|
| 47 |
|
| 48 | available = global_zone_page_state(NR_FREE_PAGES) - totalreserve_pages;
|
| 49 |
|
| 50 | |
| 51 | * Not all the page cache can be freed, otherwise the system will
|
| 52 | * start swapping or thrashing. Assume at least half of the page
|
| 53 | * cache, or the low watermark worth of cache, needs to stay.
|
| 54 |
|
| 55 | pagecache = global_node_page_state(NR_ACTIVE_FILE) +
|
| 56 | global_node_page_state(NR_INACTIVE_FILE);
|
| 57 | pagecache -= min(pagecache / 2, wmark_low);
|
| 58 | available += pagecache;
|
| 59 |
|
| 60 | |
| 61 | * Part of the reclaimable slab and other kernel memory consists of
|
| 62 | * items that are in use, and cannot be freed. Cap this estimate at the
|
| 63 | * low watermark.
|
| 64 |
|
| 65 | reclaimable = global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B) +
|
| 66 | global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE);
|
| 67 | reclaimable -= min(reclaimable / 2, wmark_low);
|
| 68 | available += reclaimable;
|
| 69 |
|
| 70 | if (available < 0)
|
| 71 | available = 0;
|
| 72 | return available;
|
| 73 | }
|
| 74 | EXPORT_SYMBOL_GPL(si_mem_available);
|
| 75 |
|
| 76 | void si_meminfo(struct sysinfo *val)
|
| 77 | {
|
| 78 | val->totalram = totalram_pages();
|
| 79 | val->sharedram = global_node_page_state(NR_SHMEM);
|
| 80 | val->freeram = global_zone_page_state(NR_FREE_PAGES);
|
| 81 | val->bufferram = nr_blockdev_pages();
|
| 82 | val->totalhigh = totalhigh_pages();
|
| 83 | val->freehigh = nr_free_highpages();
|
| 84 | val->mem_unit = PAGE_SIZE;
|
| 85 | }
|
| 86 |
|
| 87 | EXPORT_SYMBOL(si_meminfo);
|
| 88 |
|
| 89 | #ifdef CONFIG_NUMA
|
| 90 | void si_meminfo_node(struct sysinfo *val, int nid)
|
| 91 | {
|
| 92 | int zone_type;
|
| 93 | unsigned long managed_pages = 0;
|
| 94 | unsigned long managed_highpages = 0;
|
| 95 | unsigned long free_highpages = 0;
|
| 96 | pg_data_t *pgdat = NODE_DATA(nid);
|
| 97 |
|
| 98 | for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) {
|
| 99 | struct zone *zone = &pgdat->node_zones[zone_type];
|
| 100 | managed_pages += zone_managed_pages(zone);
|
| 101 | if (is_highmem(zone)) {
|
| 102 | managed_highpages += zone_managed_pages(zone);
|
| 103 | free_highpages += zone_page_state(zone, NR_FREE_PAGES);
|
| 104 | }
|
| 105 | }
|
| 106 |
|
| 107 | val->totalram = managed_pages;
|
| 108 | val->sharedram = node_page_state(pgdat, NR_SHMEM);
|
| 109 | val->freeram = sum_zone_node_page_state(nid, NR_FREE_PAGES);
|
| 110 | val->totalhigh = managed_highpages;
|
| 111 | val->freehigh = free_highpages;
|
| 112 | val->mem_unit = PAGE_SIZE;
|
| 113 | }
|
| 114 | #endif
|
| 115 |
|
| 116 | |
| 117 | * Determine whether the node should be displayed or not, depending on whether
|
| 118 | * SHOW_MEM_FILTER_NODES was passed to show_free_areas().
|
| 119 |
|
| 120 | static bool show_mem_node_skip(unsigned int flags, int nid,
|
| 121 | const nodemask_t *nodemask)
|
| 122 | {
|
| 123 | if (!(flags & SHOW_MEM_FILTER_NODES))
|
| 124 | return false;
|
| 125 |
|
| 126 | |
| 127 | * no node mask - aka implicit memory numa policy. Do not bother with
|
| 128 | * the synchronization - read_mems_allowed_begin - because we do not
|
| 129 | * have to be precise here.
|
| 130 |
|
| 131 | if (!nodemask)
|
| 132 | nodemask = &cpuset_current_mems_allowed;
|
| 133 |
|
| 134 | return !node_isset(nid, *nodemask);
|
| 135 | }
|
| 136 |
|
| 137 | static void show_migration_types(unsigned char type)
|
| 138 | {
|
| 139 | static const char types[MIGRATE_TYPES] = {
|
| 140 | [MIGRATE_UNMOVABLE] = 'U',
|
| 141 | [MIGRATE_MOVABLE] = 'M',
|
| 142 | [MIGRATE_RECLAIMABLE] = 'E',
|
| 143 | [MIGRATE_HIGHATOMIC] = 'H',
|
| 144 | #ifdef CONFIG_CMA
|
| 145 | [MIGRATE_CMA] = 'C',
|
| 146 | #endif
|
| 147 | #ifdef CONFIG_MEMORY_ISOLATION
|
| 148 | [MIGRATE_ISOLATE] = 'I',
|
| 149 | #endif
|
| 150 | };
|
| 151 | char tmp[MIGRATE_TYPES + 1];
|
| 152 | char *p = tmp;
|
| 153 | int i;
|
| 154 |
|
| 155 | for (i = 0; i < MIGRATE_TYPES; i++) {
|
| 156 | if (type & (1 << i))
|
| 157 | *p++ = types[i];
|
| 158 | }
|
| 159 |
|
| 160 | *p = '\0';
|
| 161 | printk(KERN_CONT "(%s) ", tmp);
|
| 162 | }
|
| 163 |
|
| 164 | static bool node_has_managed_zones(pg_data_t *pgdat, int max_zone_idx)
|
| 165 | {
|
| 166 | int zone_idx;
|
| 167 | for (zone_idx = 0; zone_idx <= max_zone_idx; zone_idx++)
|
| 168 | if (zone_managed_pages(pgdat->node_zones + zone_idx))
|
| 169 | return true;
|
| 170 | return false;
|
| 171 | }
|
| 172 |
|
| 173 | |
| 174 | * Show free area list (used inside shift_scroll-lock stuff)
|
| 175 | * We also calculate the percentage fragmentation. We do this by counting the
|
| 176 | * memory on each free list with the exception of the first item on the list.
|
| 177 | *
|
| 178 | * Bits in @filter:
|
| 179 | * SHOW_MEM_FILTER_NODES: suppress nodes that are not allowed by current's
|
| 180 | * cpuset.
|
| 181 |
|
| 182 | static void show_free_areas(unsigned int filter, const nodemask_t *nodemask,
|
| 183 | int max_zone_idx)
|
| 184 | {
|
| 185 | unsigned long free_pcp = 0;
|
| 186 | int cpu, nid;
|
| 187 | struct zone *zone;
|
| 188 | pg_data_t *pgdat;
|
| 189 |
|
| 190 | for_each_populated_zone(zone) {
|
| 191 | if (zone_idx(zone) > max_zone_idx)
|
| 192 | continue;
|
| 193 | if (show_mem_node_skip(filter, zone_to_nid(zone), nodemask))
|
| 194 | continue;
|
| 195 |
|
| 196 | for_each_online_cpu(cpu)
|
| 197 | free_pcp += per_cpu_ptr(zone->per_cpu_pageset, cpu)->count;
|
| 198 | }
|
| 199 |
|
| 200 | printk("active_anon:%lu inactive_anon:%lu isolated_anon:%lu\n"
|
| 201 | " active_file:%lu inactive_file:%lu isolated_file:%lu\n"
|
| 202 | " unevictable:%lu dirty:%lu writeback:%lu\n"
|
| 203 | " slab_reclaimable:%lu slab_unreclaimable:%lu\n"
|
| 204 | " mapped:%lu shmem:%lu pagetables:%lu\n"
|
| 205 | " sec_pagetables:%lu bounce:%lu\n"
|
| 206 | " kernel_misc_reclaimable:%lu\n"
|
| 207 | " free:%lu free_pcp:%lu free_cma:%lu\n",
|
| 208 | global_node_page_state(NR_ACTIVE_ANON),
|
| 209 | global_node_page_state(NR_INACTIVE_ANON),
|
| 210 | global_node_page_state(NR_ISOLATED_ANON),
|
| 211 | global_node_page_state(NR_ACTIVE_FILE),
|
| 212 | global_node_page_state(NR_INACTIVE_FILE),
|
| 213 | global_node_page_state(NR_ISOLATED_FILE),
|
| 214 | global_node_page_state(NR_UNEVICTABLE),
|
| 215 | global_node_page_state(NR_FILE_DIRTY),
|
| 216 | global_node_page_state(NR_WRITEBACK),
|
| 217 | global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B),
|
| 218 | global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B),
|
| 219 | global_node_page_state(NR_FILE_MAPPED),
|
| 220 | global_node_page_state(NR_SHMEM),
|
| 221 | global_node_page_state(NR_PAGETABLE),
|
| 222 | global_node_page_state(NR_SECONDARY_PAGETABLE),
|
| 223 | 0UL,
|
| 224 | global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE),
|
| 225 | global_zone_page_state(NR_FREE_PAGES),
|
| 226 | free_pcp,
|
| 227 | global_zone_page_state(NR_FREE_CMA_PAGES));
|
| 228 |
|
| 229 | for_each_online_pgdat(pgdat) {
|
| 230 | if (show_mem_node_skip(filter, pgdat->node_id, nodemask))
|
| 231 | continue;
|
| 232 | if (!node_has_managed_zones(pgdat, max_zone_idx))
|
| 233 | continue;
|
| 234 |
|
| 235 | printk("Node %d"
|
| 236 | " active_anon:%lukB"
|
| 237 | " inactive_anon:%lukB"
|
| 238 | " active_file:%lukB"
|
| 239 | " inactive_file:%lukB"
|
| 240 | " unevictable:%lukB"
|
| 241 | " isolated(anon):%lukB"
|
| 242 | " isolated(file):%lukB"
|
| 243 | " mapped:%lukB"
|
| 244 | " dirty:%lukB"
|
| 245 | " writeback:%lukB"
|
| 246 | " shmem:%lukB"
|
| 247 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
| 248 | " shmem_thp:%lukB"
|
| 249 | " shmem_pmdmapped:%lukB"
|
| 250 | " anon_thp:%lukB"
|
| 251 | #endif
|
| 252 | " kernel_stack:%lukB"
|
| 253 | #ifdef CONFIG_SHADOW_CALL_STACK
|
| 254 | " shadow_call_stack:%lukB"
|
| 255 | #endif
|
| 256 | " pagetables:%lukB"
|
| 257 | " sec_pagetables:%lukB"
|
| 258 | " all_unreclaimable? %s"
|
| 259 | " Balloon:%lukB"
|
| 260 | " gpu_active:%lukB"
|
| 261 | " gpu_reclaim:%lukB"
|
| 262 | "\n",
|
| 263 | pgdat->node_id,
|
| 264 | K(node_page_state(pgdat, NR_ACTIVE_ANON)),
|
| 265 | K(node_page_state(pgdat, NR_INACTIVE_ANON)),
|
| 266 | K(node_page_state(pgdat, NR_ACTIVE_FILE)),
|
| 267 | K(node_page_state(pgdat, NR_INACTIVE_FILE)),
|
| 268 | K(node_page_state(pgdat, NR_UNEVICTABLE)),
|
| 269 | K(node_page_state(pgdat, NR_ISOLATED_ANON)),
|
| 270 | K(node_page_state(pgdat, NR_ISOLATED_FILE)),
|
| 271 | K(node_page_state(pgdat, NR_FILE_MAPPED)),
|
| 272 | K(node_page_state(pgdat, NR_FILE_DIRTY)),
|
| 273 | K(node_page_state(pgdat, NR_WRITEBACK)),
|
| 274 | K(node_page_state(pgdat, NR_SHMEM)),
|
| 275 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
| 276 | K(node_page_state(pgdat, NR_SHMEM_THPS)),
|
| 277 | K(node_page_state(pgdat, NR_SHMEM_PMDMAPPED)),
|
| 278 | K(node_page_state(pgdat, NR_ANON_THPS)),
|
| 279 | #endif
|
| 280 | node_page_state(pgdat, NR_KERNEL_STACK_KB),
|
| 281 | #ifdef CONFIG_SHADOW_CALL_STACK
|
| 282 | node_page_state(pgdat, NR_KERNEL_SCS_KB),
|
| 283 | #endif
|
| 284 | K(node_page_state(pgdat, NR_PAGETABLE)),
|
| 285 | K(node_page_state(pgdat, NR_SECONDARY_PAGETABLE)),
|
| 286 | str_yes_no(kswapd_test_hopeless(pgdat)),
|
| 287 | K(node_page_state(pgdat, NR_BALLOON_PAGES)),
|
| 288 | K(node_page_state(pgdat, NR_GPU_ACTIVE)),
|
| 289 | K(node_page_state(pgdat, NR_GPU_RECLAIM)));
|
| 290 | }
|
| 291 |
|
| 292 | for_each_populated_zone(zone) {
|
| 293 | int i;
|
| 294 |
|
| 295 | if (zone_idx(zone) > max_zone_idx)
|
| 296 | continue;
|
| 297 | if (show_mem_node_skip(filter, zone_to_nid(zone), nodemask))
|
| 298 | continue;
|
| 299 |
|
| 300 | free_pcp = 0;
|
| 301 | for_each_online_cpu(cpu)
|
| 302 | free_pcp += per_cpu_ptr(zone->per_cpu_pageset, cpu)->count;
|
| 303 |
|
| 304 | show_node(zone);
|
| 305 | printk(KERN_CONT
|
| 306 | "%s"
|
| 307 | " free:%lukB"
|
| 308 | " boost:%lukB"
|
| 309 | " min:%lukB"
|
| 310 | " low:%lukB"
|
| 311 | " high:%lukB"
|
| 312 | " reserved_highatomic:%lukB"
|
| 313 | " free_highatomic:%lukB"
|
| 314 | " active_anon:%lukB"
|
| 315 | " inactive_anon:%lukB"
|
| 316 | " active_file:%lukB"
|
| 317 | " inactive_file:%lukB"
|
| 318 | " unevictable:%lukB"
|
| 319 | " writepending:%lukB"
|
| 320 | " zspages:%lukB"
|
| 321 | " present:%lukB"
|
| 322 | " managed:%lukB"
|
| 323 | " mlocked:%lukB"
|
| 324 | " bounce:%lukB"
|
| 325 | " free_pcp:%lukB"
|
| 326 | " local_pcp:%lukB"
|
| 327 | " free_cma:%lukB"
|
| 328 | "\n",
|
| 329 | zone->name,
|
| 330 | K(zone_page_state(zone, NR_FREE_PAGES)),
|
| 331 | K(zone->watermark_boost),
|
| 332 | K(min_wmark_pages(zone)),
|
| 333 | K(low_wmark_pages(zone)),
|
| 334 | K(high_wmark_pages(zone)),
|
| 335 | K(zone->nr_reserved_highatomic),
|
| 336 | K(zone->nr_free_highatomic),
|
| 337 | K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)),
|
| 338 | K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)),
|
| 339 | K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)),
|
| 340 | K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)),
|
| 341 | K(zone_page_state(zone, NR_ZONE_UNEVICTABLE)),
|
| 342 | K(zone_page_state(zone, NR_ZONE_WRITE_PENDING)),
|
| 343 | #if IS_ENABLED(CONFIG_ZSMALLOC)
|
| 344 | K(zone_page_state(zone, NR_ZSPAGES)),
|
| 345 | #else
|
| 346 | 0UL,
|
| 347 | #endif
|
| 348 | K(zone->present_pages),
|
| 349 | K(zone_managed_pages(zone)),
|
| 350 | K(zone_page_state(zone, NR_MLOCK)),
|
| 351 | 0UL,
|
| 352 | K(free_pcp),
|
| 353 | K((unsigned long)this_cpu_read(zone->per_cpu_pageset->count)),
|
| 354 | K(zone_page_state(zone, NR_FREE_CMA_PAGES)));
|
| 355 | printk("lowmem_reserve[]:");
|
| 356 | for (i = 0; i < MAX_NR_ZONES; i++)
|
| 357 | printk(KERN_CONT " %ld", zone->lowmem_reserve[i]);
|
| 358 | printk(KERN_CONT "\n");
|
| 359 | }
|
| 360 |
|
| 361 | for_each_populated_zone(zone) {
|
| 362 | unsigned int order;
|
| 363 | unsigned long nr[NR_PAGE_ORDERS], flags, total = 0;
|
| 364 | unsigned char types[NR_PAGE_ORDERS];
|
| 365 |
|
| 366 | if (zone_idx(zone) > max_zone_idx)
|
| 367 | continue;
|
| 368 | if (show_mem_node_skip(filter, zone_to_nid(zone), nodemask))
|
| 369 | continue;
|
| 370 | show_node(zone);
|
| 371 | printk(KERN_CONT "%s: ", zone->name);
|
| 372 |
|
| 373 | spin_lock_irqsave(&zone->lock, flags);
|
| 374 | for (order = 0; order < NR_PAGE_ORDERS; order++) {
|
| 375 | struct free_area *area = &zone->free_area[order];
|
| 376 | int type;
|
| 377 |
|
| 378 | nr[order] = area->nr_free;
|
| 379 | total += nr[order] << order;
|
| 380 |
|
| 381 | types[order] = 0;
|
| 382 | for (type = 0; type < MIGRATE_TYPES; type++) {
|
| 383 | if (!free_area_empty(area, type))
|
| 384 | types[order] |= 1 << type;
|
| 385 | }
|
| 386 | }
|
| 387 | spin_unlock_irqrestore(&zone->lock, flags);
|
| 388 | for (order = 0; order < NR_PAGE_ORDERS; order++) {
|
| 389 | printk(KERN_CONT "%lu*%lukB ",
|
| 390 | nr[order], K(1UL) << order);
|
| 391 | if (nr[order])
|
| 392 | show_migration_types(types[order]);
|
| 393 | }
|
| 394 | printk(KERN_CONT "= %lukB\n", K(total));
|
| 395 | }
|
| 396 |
|
| 397 | for_each_online_node(nid) {
|
| 398 | if (show_mem_node_skip(filter, nid, nodemask))
|
| 399 | continue;
|
| 400 | hugetlb_show_meminfo_node(nid);
|
| 401 | }
|
| 402 |
|
| 403 | printk("%lu total pagecache pages\n", global_node_page_state(NR_FILE_PAGES));
|
| 404 |
|
| 405 | show_swap_cache_info();
|
| 406 | }
|
| 407 |
|
| 408 | void __show_mem(unsigned int filter, const nodemask_t *nodemask,
|
| 409 | int max_zone_idx)
|
| 410 | {
|
| 411 | unsigned long total = 0, reserved = 0, highmem = 0;
|
| 412 | struct zone *zone;
|
| 413 |
|
| 414 | printk("Mem-Info:\n");
|
| 415 | show_free_areas(filter, nodemask, max_zone_idx);
|
| 416 |
|
| 417 | for_each_populated_zone(zone) {
|
| 418 |
|
| 419 | total += zone->present_pages;
|
| 420 | reserved += zone->present_pages - zone_managed_pages(zone);
|
| 421 |
|
| 422 | if (is_highmem(zone))
|
| 423 | highmem += zone->present_pages;
|
| 424 | }
|
| 425 |
|
| 426 | printk("%lu pages RAM\n", total);
|
| 427 | printk("%lu pages HighMem/MovableOnly\n", highmem);
|
| 428 | printk("%lu pages reserved\n", reserved);
|
| 429 | #ifdef CONFIG_CMA
|
| 430 | printk("%lu pages cma reserved\n", totalcma_pages);
|
| 431 | #endif
|
| 432 | #ifdef CONFIG_MEMORY_FAILURE
|
| 433 | printk("%ld pages hwpoisoned\n", atomic_long_read(&num_poisoned_pages));
|
| 434 | #endif
|
| 435 | #ifdef CONFIG_MEM_ALLOC_PROFILING
|
| 436 | static DEFINE_SPINLOCK(mem_alloc_profiling_spinlock);
|
| 437 |
|
| 438 | if (spin_trylock(&mem_alloc_profiling_spinlock)) {
|
| 439 | struct codetag_bytes tags[10];
|
| 440 | size_t i, nr;
|
| 441 |
|
| 442 | nr = alloc_tag_top_users(tags, ARRAY_SIZE(tags), false);
|
| 443 | if (nr) {
|
| 444 | pr_notice("Memory allocations (profiling is currently turned %s):\n",
|
| 445 | mem_alloc_profiling_enabled() ? "on" : "off");
|
| 446 | for (i = 0; i < nr; i++) {
|
| 447 | struct codetag *ct = tags[i].ct;
|
| 448 | struct alloc_tag *tag = ct_to_alloc_tag(ct);
|
| 449 | struct alloc_tag_counters counter = alloc_tag_read(tag);
|
| 450 | char bytes[10];
|
| 451 |
|
| 452 | string_get_size(counter.bytes, 1, STRING_UNITS_2, bytes, sizeof(bytes));
|
| 453 |
|
| 454 |
|
| 455 | if (ct->modname)
|
| 456 | pr_notice("%12s %8llu %s:%u [%s] func:%s\n",
|
| 457 | bytes, counter.calls, ct->filename,
|
| 458 | ct->lineno, ct->modname, ct->function);
|
| 459 | else
|
| 460 | pr_notice("%12s %8llu %s:%u func:%s\n",
|
| 461 | bytes, counter.calls, ct->filename,
|
| 462 | ct->lineno, ct->function);
|
| 463 | }
|
| 464 | }
|
| 465 | spin_unlock(&mem_alloc_profiling_spinlock);
|
| 466 | }
|
| 467 | #endif
|
| 468 | }
|