|
57 | 57 | #include <linux/lockdep.h> |
58 | 58 | #include <linux/file.h> |
59 | 59 | #include <linux/tracehook.h> |
| 60 | +#include <linux/seq_buf.h> |
60 | 61 | #include "internal.h" |
61 | 62 | #include <net/sock.h> |
62 | 63 | #include <net/ip.h> |
@@ -1356,27 +1357,114 @@ static bool mem_cgroup_wait_acct_move(struct mem_cgroup *memcg) |
1356 | 1357 | return false; |
1357 | 1358 | } |
1358 | 1359 |
|
1359 | | -static const unsigned int memcg1_stats[] = { |
1360 | | - MEMCG_CACHE, |
1361 | | - MEMCG_RSS, |
1362 | | - MEMCG_RSS_HUGE, |
1363 | | - NR_SHMEM, |
1364 | | - NR_FILE_MAPPED, |
1365 | | - NR_FILE_DIRTY, |
1366 | | - NR_WRITEBACK, |
1367 | | - MEMCG_SWAP, |
1368 | | -}; |
| 1360 | +static char *memory_stat_format(struct mem_cgroup *memcg) |
| 1361 | +{ |
| 1362 | + struct seq_buf s; |
| 1363 | + int i; |
1369 | 1364 |
|
1370 | | -static const char *const memcg1_stat_names[] = { |
1371 | | - "cache", |
1372 | | - "rss", |
1373 | | - "rss_huge", |
1374 | | - "shmem", |
1375 | | - "mapped_file", |
1376 | | - "dirty", |
1377 | | - "writeback", |
1378 | | - "swap", |
1379 | | -}; |
| 1365 | + seq_buf_init(&s, kmalloc(PAGE_SIZE, GFP_KERNEL), PAGE_SIZE); |
| 1366 | + if (!s.buffer) |
| 1367 | + return NULL; |
| 1368 | + |
| 1369 | + /* |
| 1370 | + * Provide statistics on the state of the memory subsystem as |
| 1371 | + * well as cumulative event counters that show past behavior. |
| 1372 | + * |
| 1373 | + * This list is ordered following a combination of these gradients: |
| 1374 | + * 1) generic big picture -> specifics and details |
| 1375 | + * 2) reflecting userspace activity -> reflecting kernel heuristics |
| 1376 | + * |
| 1377 | + * Current memory state: |
| 1378 | + */ |
| 1379 | + |
| 1380 | + seq_buf_printf(&s, "anon %llu\n", |
| 1381 | + (u64)memcg_page_state(memcg, MEMCG_RSS) * |
| 1382 | + PAGE_SIZE); |
| 1383 | + seq_buf_printf(&s, "file %llu\n", |
| 1384 | + (u64)memcg_page_state(memcg, MEMCG_CACHE) * |
| 1385 | + PAGE_SIZE); |
| 1386 | + seq_buf_printf(&s, "kernel_stack %llu\n", |
| 1387 | + (u64)memcg_page_state(memcg, MEMCG_KERNEL_STACK_KB) * |
| 1388 | + 1024); |
| 1389 | + seq_buf_printf(&s, "slab %llu\n", |
| 1390 | + (u64)(memcg_page_state(memcg, NR_SLAB_RECLAIMABLE) + |
| 1391 | + memcg_page_state(memcg, NR_SLAB_UNRECLAIMABLE)) * |
| 1392 | + PAGE_SIZE); |
| 1393 | + seq_buf_printf(&s, "sock %llu\n", |
| 1394 | + (u64)memcg_page_state(memcg, MEMCG_SOCK) * |
| 1395 | + PAGE_SIZE); |
| 1396 | + |
| 1397 | + seq_buf_printf(&s, "shmem %llu\n", |
| 1398 | + (u64)memcg_page_state(memcg, NR_SHMEM) * |
| 1399 | + PAGE_SIZE); |
| 1400 | + seq_buf_printf(&s, "file_mapped %llu\n", |
| 1401 | + (u64)memcg_page_state(memcg, NR_FILE_MAPPED) * |
| 1402 | + PAGE_SIZE); |
| 1403 | + seq_buf_printf(&s, "file_dirty %llu\n", |
| 1404 | + (u64)memcg_page_state(memcg, NR_FILE_DIRTY) * |
| 1405 | + PAGE_SIZE); |
| 1406 | + seq_buf_printf(&s, "file_writeback %llu\n", |
| 1407 | + (u64)memcg_page_state(memcg, NR_WRITEBACK) * |
| 1408 | + PAGE_SIZE); |
| 1409 | + |
| 1410 | + /* |
| 1411 | + * TODO: We should eventually replace our own MEMCG_RSS_HUGE counter |
| 1412 | + * with the NR_ANON_THP vm counter, but right now it's a pain in the |
| 1413 | + * arse because it requires migrating the work out of rmap to a place |
| 1414 | + * where the page->mem_cgroup is set up and stable. |
| 1415 | + */ |
| 1416 | + seq_buf_printf(&s, "anon_thp %llu\n", |
| 1417 | + (u64)memcg_page_state(memcg, MEMCG_RSS_HUGE) * |
| 1418 | + PAGE_SIZE); |
| 1419 | + |
| 1420 | + for (i = 0; i < NR_LRU_LISTS; i++) |
| 1421 | + seq_buf_printf(&s, "%s %llu\n", mem_cgroup_lru_names[i], |
| 1422 | + (u64)memcg_page_state(memcg, NR_LRU_BASE + i) * |
| 1423 | + PAGE_SIZE); |
| 1424 | + |
| 1425 | + seq_buf_printf(&s, "slab_reclaimable %llu\n", |
| 1426 | + (u64)memcg_page_state(memcg, NR_SLAB_RECLAIMABLE) * |
| 1427 | + PAGE_SIZE); |
| 1428 | + seq_buf_printf(&s, "slab_unreclaimable %llu\n", |
| 1429 | + (u64)memcg_page_state(memcg, NR_SLAB_UNRECLAIMABLE) * |
| 1430 | + PAGE_SIZE); |
| 1431 | + |
| 1432 | + /* Accumulated memory events */ |
| 1433 | + |
| 1434 | + seq_buf_printf(&s, "pgfault %lu\n", memcg_events(memcg, PGFAULT)); |
| 1435 | + seq_buf_printf(&s, "pgmajfault %lu\n", memcg_events(memcg, PGMAJFAULT)); |
| 1436 | + |
| 1437 | + seq_buf_printf(&s, "workingset_refault %lu\n", |
| 1438 | + memcg_page_state(memcg, WORKINGSET_REFAULT)); |
| 1439 | + seq_buf_printf(&s, "workingset_activate %lu\n", |
| 1440 | + memcg_page_state(memcg, WORKINGSET_ACTIVATE)); |
| 1441 | + seq_buf_printf(&s, "workingset_nodereclaim %lu\n", |
| 1442 | + memcg_page_state(memcg, WORKINGSET_NODERECLAIM)); |
| 1443 | + |
| 1444 | + seq_buf_printf(&s, "pgrefill %lu\n", memcg_events(memcg, PGREFILL)); |
| 1445 | + seq_buf_printf(&s, "pgscan %lu\n", |
| 1446 | + memcg_events(memcg, PGSCAN_KSWAPD) + |
| 1447 | + memcg_events(memcg, PGSCAN_DIRECT)); |
| 1448 | + seq_buf_printf(&s, "pgsteal %lu\n", |
| 1449 | + memcg_events(memcg, PGSTEAL_KSWAPD) + |
| 1450 | + memcg_events(memcg, PGSTEAL_DIRECT)); |
| 1451 | + seq_buf_printf(&s, "pgactivate %lu\n", memcg_events(memcg, PGACTIVATE)); |
| 1452 | + seq_buf_printf(&s, "pgdeactivate %lu\n", memcg_events(memcg, PGDEACTIVATE)); |
| 1453 | + seq_buf_printf(&s, "pglazyfree %lu\n", memcg_events(memcg, PGLAZYFREE)); |
| 1454 | + seq_buf_printf(&s, "pglazyfreed %lu\n", memcg_events(memcg, PGLAZYFREED)); |
| 1455 | + |
| 1456 | +#ifdef CONFIG_TRANSPARENT_HUGEPAGE |
| 1457 | + seq_buf_printf(&s, "thp_fault_alloc %lu\n", |
| 1458 | + memcg_events(memcg, THP_FAULT_ALLOC)); |
| 1459 | + seq_buf_printf(&s, "thp_collapse_alloc %lu\n", |
| 1460 | + memcg_events(memcg, THP_COLLAPSE_ALLOC)); |
| 1461 | +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ |
| 1462 | + |
| 1463 | + /* The above should easily fit into one page */ |
| 1464 | + WARN_ON_ONCE(seq_buf_has_overflowed(&s)); |
| 1465 | + |
| 1466 | + return s.buffer; |
| 1467 | +} |
1380 | 1468 |
|
1381 | 1469 | #define K(x) ((x) << (PAGE_SHIFT-10)) |
1382 | 1470 | /** |
@@ -1411,39 +1499,32 @@ void mem_cgroup_print_oom_context(struct mem_cgroup *memcg, struct task_struct * |
1411 | 1499 | */ |
1412 | 1500 | void mem_cgroup_print_oom_meminfo(struct mem_cgroup *memcg) |
1413 | 1501 | { |
1414 | | - struct mem_cgroup *iter; |
1415 | | - unsigned int i; |
| 1502 | + char *buf; |
1416 | 1503 |
|
1417 | 1504 | pr_info("memory: usage %llukB, limit %llukB, failcnt %lu\n", |
1418 | 1505 | K((u64)page_counter_read(&memcg->memory)), |
1419 | 1506 | K((u64)memcg->memory.max), memcg->memory.failcnt); |
1420 | | - pr_info("memory+swap: usage %llukB, limit %llukB, failcnt %lu\n", |
1421 | | - K((u64)page_counter_read(&memcg->memsw)), |
1422 | | - K((u64)memcg->memsw.max), memcg->memsw.failcnt); |
1423 | | - pr_info("kmem: usage %llukB, limit %llukB, failcnt %lu\n", |
1424 | | - K((u64)page_counter_read(&memcg->kmem)), |
1425 | | - K((u64)memcg->kmem.max), memcg->kmem.failcnt); |
1426 | | - |
1427 | | - for_each_mem_cgroup_tree(iter, memcg) { |
1428 | | - pr_info("Memory cgroup stats for "); |
1429 | | - pr_cont_cgroup_path(iter->css.cgroup); |
1430 | | - pr_cont(":"); |
1431 | | - |
1432 | | - for (i = 0; i < ARRAY_SIZE(memcg1_stats); i++) { |
1433 | | - if (memcg1_stats[i] == MEMCG_SWAP && !do_swap_account) |
1434 | | - continue; |
1435 | | - pr_cont(" %s:%luKB", memcg1_stat_names[i], |
1436 | | - K(memcg_page_state_local(iter, |
1437 | | - memcg1_stats[i]))); |
1438 | | - } |
1439 | | - |
1440 | | - for (i = 0; i < NR_LRU_LISTS; i++) |
1441 | | - pr_cont(" %s:%luKB", mem_cgroup_lru_names[i], |
1442 | | - K(memcg_page_state_local(iter, |
1443 | | - NR_LRU_BASE + i))); |
1444 | | - |
1445 | | - pr_cont("\n"); |
| 1507 | + if (cgroup_subsys_on_dfl(memory_cgrp_subsys)) |
| 1508 | + pr_info("swap: usage %llukB, limit %llukB, failcnt %lu\n", |
| 1509 | + K((u64)page_counter_read(&memcg->swap)), |
| 1510 | + K((u64)memcg->swap.max), memcg->swap.failcnt); |
| 1511 | + else { |
| 1512 | + pr_info("memory+swap: usage %llukB, limit %llukB, failcnt %lu\n", |
| 1513 | + K((u64)page_counter_read(&memcg->memsw)), |
| 1514 | + K((u64)memcg->memsw.max), memcg->memsw.failcnt); |
| 1515 | + pr_info("kmem: usage %llukB, limit %llukB, failcnt %lu\n", |
| 1516 | + K((u64)page_counter_read(&memcg->kmem)), |
| 1517 | + K((u64)memcg->kmem.max), memcg->kmem.failcnt); |
1446 | 1518 | } |
| 1519 | + |
| 1520 | + pr_info("Memory cgroup stats for "); |
| 1521 | + pr_cont_cgroup_path(memcg->css.cgroup); |
| 1522 | + pr_cont(":"); |
| 1523 | + buf = memory_stat_format(memcg); |
| 1524 | + if (!buf) |
| 1525 | + return; |
| 1526 | + pr_info("%s", buf); |
| 1527 | + kfree(buf); |
1447 | 1528 | } |
1448 | 1529 |
|
1449 | 1530 | /* |
@@ -3470,6 +3551,28 @@ static int memcg_numa_stat_show(struct seq_file *m, void *v) |
3470 | 3551 | } |
3471 | 3552 | #endif /* CONFIG_NUMA */ |
3472 | 3553 |
|
| 3554 | +static const unsigned int memcg1_stats[] = { |
| 3555 | + MEMCG_CACHE, |
| 3556 | + MEMCG_RSS, |
| 3557 | + MEMCG_RSS_HUGE, |
| 3558 | + NR_SHMEM, |
| 3559 | + NR_FILE_MAPPED, |
| 3560 | + NR_FILE_DIRTY, |
| 3561 | + NR_WRITEBACK, |
| 3562 | + MEMCG_SWAP, |
| 3563 | +}; |
| 3564 | + |
| 3565 | +static const char *const memcg1_stat_names[] = { |
| 3566 | + "cache", |
| 3567 | + "rss", |
| 3568 | + "rss_huge", |
| 3569 | + "shmem", |
| 3570 | + "mapped_file", |
| 3571 | + "dirty", |
| 3572 | + "writeback", |
| 3573 | + "swap", |
| 3574 | +}; |
| 3575 | + |
3473 | 3576 | /* Universal VM events cgroup1 shows, original sort order */ |
3474 | 3577 | static const unsigned int memcg1_events[] = { |
3475 | 3578 | PGPGIN, |
@@ -5653,91 +5756,13 @@ static int memory_events_local_show(struct seq_file *m, void *v) |
5653 | 5756 | static int memory_stat_show(struct seq_file *m, void *v) |
5654 | 5757 | { |
5655 | 5758 | struct mem_cgroup *memcg = mem_cgroup_from_seq(m); |
5656 | | - int i; |
5657 | | - |
5658 | | - /* |
5659 | | - * Provide statistics on the state of the memory subsystem as |
5660 | | - * well as cumulative event counters that show past behavior. |
5661 | | - * |
5662 | | - * This list is ordered following a combination of these gradients: |
5663 | | - * 1) generic big picture -> specifics and details |
5664 | | - * 2) reflecting userspace activity -> reflecting kernel heuristics |
5665 | | - * |
5666 | | - * Current memory state: |
5667 | | - */ |
5668 | | - |
5669 | | - seq_printf(m, "anon %llu\n", |
5670 | | - (u64)memcg_page_state(memcg, MEMCG_RSS) * PAGE_SIZE); |
5671 | | - seq_printf(m, "file %llu\n", |
5672 | | - (u64)memcg_page_state(memcg, MEMCG_CACHE) * PAGE_SIZE); |
5673 | | - seq_printf(m, "kernel_stack %llu\n", |
5674 | | - (u64)memcg_page_state(memcg, MEMCG_KERNEL_STACK_KB) * 1024); |
5675 | | - seq_printf(m, "slab %llu\n", |
5676 | | - (u64)(memcg_page_state(memcg, NR_SLAB_RECLAIMABLE) + |
5677 | | - memcg_page_state(memcg, NR_SLAB_UNRECLAIMABLE)) * |
5678 | | - PAGE_SIZE); |
5679 | | - seq_printf(m, "sock %llu\n", |
5680 | | - (u64)memcg_page_state(memcg, MEMCG_SOCK) * PAGE_SIZE); |
5681 | | - |
5682 | | - seq_printf(m, "shmem %llu\n", |
5683 | | - (u64)memcg_page_state(memcg, NR_SHMEM) * PAGE_SIZE); |
5684 | | - seq_printf(m, "file_mapped %llu\n", |
5685 | | - (u64)memcg_page_state(memcg, NR_FILE_MAPPED) * PAGE_SIZE); |
5686 | | - seq_printf(m, "file_dirty %llu\n", |
5687 | | - (u64)memcg_page_state(memcg, NR_FILE_DIRTY) * PAGE_SIZE); |
5688 | | - seq_printf(m, "file_writeback %llu\n", |
5689 | | - (u64)memcg_page_state(memcg, NR_WRITEBACK) * PAGE_SIZE); |
5690 | | - |
5691 | | - /* |
5692 | | - * TODO: We should eventually replace our own MEMCG_RSS_HUGE counter |
5693 | | - * with the NR_ANON_THP vm counter, but right now it's a pain in the |
5694 | | - * arse because it requires migrating the work out of rmap to a place |
5695 | | - * where the page->mem_cgroup is set up and stable. |
5696 | | - */ |
5697 | | - seq_printf(m, "anon_thp %llu\n", |
5698 | | - (u64)memcg_page_state(memcg, MEMCG_RSS_HUGE) * PAGE_SIZE); |
5699 | | - |
5700 | | - for (i = 0; i < NR_LRU_LISTS; i++) |
5701 | | - seq_printf(m, "%s %llu\n", mem_cgroup_lru_names[i], |
5702 | | - (u64)memcg_page_state(memcg, NR_LRU_BASE + i) * |
5703 | | - PAGE_SIZE); |
5704 | | - |
5705 | | - seq_printf(m, "slab_reclaimable %llu\n", |
5706 | | - (u64)memcg_page_state(memcg, NR_SLAB_RECLAIMABLE) * |
5707 | | - PAGE_SIZE); |
5708 | | - seq_printf(m, "slab_unreclaimable %llu\n", |
5709 | | - (u64)memcg_page_state(memcg, NR_SLAB_UNRECLAIMABLE) * |
5710 | | - PAGE_SIZE); |
5711 | | - |
5712 | | - /* Accumulated memory events */ |
5713 | | - |
5714 | | - seq_printf(m, "pgfault %lu\n", memcg_events(memcg, PGFAULT)); |
5715 | | - seq_printf(m, "pgmajfault %lu\n", memcg_events(memcg, PGMAJFAULT)); |
5716 | | - |
5717 | | - seq_printf(m, "workingset_refault %lu\n", |
5718 | | - memcg_page_state(memcg, WORKINGSET_REFAULT)); |
5719 | | - seq_printf(m, "workingset_activate %lu\n", |
5720 | | - memcg_page_state(memcg, WORKINGSET_ACTIVATE)); |
5721 | | - seq_printf(m, "workingset_nodereclaim %lu\n", |
5722 | | - memcg_page_state(memcg, WORKINGSET_NODERECLAIM)); |
5723 | | - |
5724 | | - seq_printf(m, "pgrefill %lu\n", memcg_events(memcg, PGREFILL)); |
5725 | | - seq_printf(m, "pgscan %lu\n", memcg_events(memcg, PGSCAN_KSWAPD) + |
5726 | | - memcg_events(memcg, PGSCAN_DIRECT)); |
5727 | | - seq_printf(m, "pgsteal %lu\n", memcg_events(memcg, PGSTEAL_KSWAPD) + |
5728 | | - memcg_events(memcg, PGSTEAL_DIRECT)); |
5729 | | - seq_printf(m, "pgactivate %lu\n", memcg_events(memcg, PGACTIVATE)); |
5730 | | - seq_printf(m, "pgdeactivate %lu\n", memcg_events(memcg, PGDEACTIVATE)); |
5731 | | - seq_printf(m, "pglazyfree %lu\n", memcg_events(memcg, PGLAZYFREE)); |
5732 | | - seq_printf(m, "pglazyfreed %lu\n", memcg_events(memcg, PGLAZYFREED)); |
5733 | | - |
5734 | | -#ifdef CONFIG_TRANSPARENT_HUGEPAGE |
5735 | | - seq_printf(m, "thp_fault_alloc %lu\n", |
5736 | | - memcg_events(memcg, THP_FAULT_ALLOC)); |
5737 | | - seq_printf(m, "thp_collapse_alloc %lu\n", |
5738 | | - memcg_events(memcg, THP_COLLAPSE_ALLOC)); |
5739 | | -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ |
| 5759 | + char *buf; |
5740 | 5760 |
|
| 5761 | + buf = memory_stat_format(memcg); |
| 5762 | + if (!buf) |
| 5763 | + return -ENOMEM; |
| 5764 | + seq_puts(m, buf); |
| 5765 | + kfree(buf); |
5741 | 5766 | return 0; |
5742 | 5767 | } |
5743 | 5768 |
|
|
0 commit comments