diff options
Diffstat (limited to 'mm/vmstat.c')
-rw-r--r-- | mm/vmstat.c | 75 |
1 files changed, 36 insertions, 39 deletions
diff --git a/mm/vmstat.c b/mm/vmstat.c index 809025ed97ea..f5fa1bd1eb16 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c | |||
@@ -954,7 +954,6 @@ const char * const vmstat_text[] = { | |||
954 | "nr_unevictable", | 954 | "nr_unevictable", |
955 | "nr_isolated_anon", | 955 | "nr_isolated_anon", |
956 | "nr_isolated_file", | 956 | "nr_isolated_file", |
957 | "nr_pages_scanned", | ||
958 | "workingset_refault", | 957 | "workingset_refault", |
959 | "workingset_activate", | 958 | "workingset_activate", |
960 | "workingset_nodereclaim", | 959 | "workingset_nodereclaim", |
@@ -992,6 +991,7 @@ const char * const vmstat_text[] = { | |||
992 | "pgfree", | 991 | "pgfree", |
993 | "pgactivate", | 992 | "pgactivate", |
994 | "pgdeactivate", | 993 | "pgdeactivate", |
994 | "pglazyfree", | ||
995 | 995 | ||
996 | "pgfault", | 996 | "pgfault", |
997 | "pgmajfault", | 997 | "pgmajfault", |
@@ -1124,8 +1124,12 @@ static void frag_stop(struct seq_file *m, void *arg) | |||
1124 | { | 1124 | { |
1125 | } | 1125 | } |
1126 | 1126 | ||
1127 | /* Walk all the zones in a node and print using a callback */ | 1127 | /* |
1128 | * Walk zones in a node and print using a callback. | ||
1129 | * If @assert_populated is true, only use callback for zones that are populated. | ||
1130 | */ | ||
1128 | static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat, | 1131 | static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat, |
1132 | bool assert_populated, | ||
1129 | void (*print)(struct seq_file *m, pg_data_t *, struct zone *)) | 1133 | void (*print)(struct seq_file *m, pg_data_t *, struct zone *)) |
1130 | { | 1134 | { |
1131 | struct zone *zone; | 1135 | struct zone *zone; |
@@ -1133,7 +1137,7 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat, | |||
1133 | unsigned long flags; | 1137 | unsigned long flags; |
1134 | 1138 | ||
1135 | for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { | 1139 | for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { |
1136 | if (!populated_zone(zone)) | 1140 | if (assert_populated && !populated_zone(zone)) |
1137 | continue; | 1141 | continue; |
1138 | 1142 | ||
1139 | spin_lock_irqsave(&zone->lock, flags); | 1143 | spin_lock_irqsave(&zone->lock, flags); |
@@ -1161,7 +1165,7 @@ static void frag_show_print(struct seq_file *m, pg_data_t *pgdat, | |||
1161 | static int frag_show(struct seq_file *m, void *arg) | 1165 | static int frag_show(struct seq_file *m, void *arg) |
1162 | { | 1166 | { |
1163 | pg_data_t *pgdat = (pg_data_t *)arg; | 1167 | pg_data_t *pgdat = (pg_data_t *)arg; |
1164 | walk_zones_in_node(m, pgdat, frag_show_print); | 1168 | walk_zones_in_node(m, pgdat, true, frag_show_print); |
1165 | return 0; | 1169 | return 0; |
1166 | } | 1170 | } |
1167 | 1171 | ||
@@ -1202,7 +1206,7 @@ static int pagetypeinfo_showfree(struct seq_file *m, void *arg) | |||
1202 | seq_printf(m, "%6d ", order); | 1206 | seq_printf(m, "%6d ", order); |
1203 | seq_putc(m, '\n'); | 1207 | seq_putc(m, '\n'); |
1204 | 1208 | ||
1205 | walk_zones_in_node(m, pgdat, pagetypeinfo_showfree_print); | 1209 | walk_zones_in_node(m, pgdat, true, pagetypeinfo_showfree_print); |
1206 | 1210 | ||
1207 | return 0; | 1211 | return 0; |
1208 | } | 1212 | } |
@@ -1254,7 +1258,7 @@ static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg) | |||
1254 | for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) | 1258 | for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) |
1255 | seq_printf(m, "%12s ", migratetype_names[mtype]); | 1259 | seq_printf(m, "%12s ", migratetype_names[mtype]); |
1256 | seq_putc(m, '\n'); | 1260 | seq_putc(m, '\n'); |
1257 | walk_zones_in_node(m, pgdat, pagetypeinfo_showblockcount_print); | 1261 | walk_zones_in_node(m, pgdat, true, pagetypeinfo_showblockcount_print); |
1258 | 1262 | ||
1259 | return 0; | 1263 | return 0; |
1260 | } | 1264 | } |
@@ -1280,7 +1284,7 @@ static void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat) | |||
1280 | seq_printf(m, "%12s ", migratetype_names[mtype]); | 1284 | seq_printf(m, "%12s ", migratetype_names[mtype]); |
1281 | seq_putc(m, '\n'); | 1285 | seq_putc(m, '\n'); |
1282 | 1286 | ||
1283 | walk_zones_in_node(m, pgdat, pagetypeinfo_showmixedcount_print); | 1287 | walk_zones_in_node(m, pgdat, true, pagetypeinfo_showmixedcount_print); |
1284 | #endif /* CONFIG_PAGE_OWNER */ | 1288 | #endif /* CONFIG_PAGE_OWNER */ |
1285 | } | 1289 | } |
1286 | 1290 | ||
@@ -1378,7 +1382,6 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, | |||
1378 | "\n min %lu" | 1382 | "\n min %lu" |
1379 | "\n low %lu" | 1383 | "\n low %lu" |
1380 | "\n high %lu" | 1384 | "\n high %lu" |
1381 | "\n node_scanned %lu" | ||
1382 | "\n spanned %lu" | 1385 | "\n spanned %lu" |
1383 | "\n present %lu" | 1386 | "\n present %lu" |
1384 | "\n managed %lu", | 1387 | "\n managed %lu", |
@@ -1386,23 +1389,28 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, | |||
1386 | min_wmark_pages(zone), | 1389 | min_wmark_pages(zone), |
1387 | low_wmark_pages(zone), | 1390 | low_wmark_pages(zone), |
1388 | high_wmark_pages(zone), | 1391 | high_wmark_pages(zone), |
1389 | node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED), | ||
1390 | zone->spanned_pages, | 1392 | zone->spanned_pages, |
1391 | zone->present_pages, | 1393 | zone->present_pages, |
1392 | zone->managed_pages); | 1394 | zone->managed_pages); |
1393 | 1395 | ||
1394 | for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) | ||
1395 | seq_printf(m, "\n %-12s %lu", vmstat_text[i], | ||
1396 | zone_page_state(zone, i)); | ||
1397 | |||
1398 | seq_printf(m, | 1396 | seq_printf(m, |
1399 | "\n protection: (%ld", | 1397 | "\n protection: (%ld", |
1400 | zone->lowmem_reserve[0]); | 1398 | zone->lowmem_reserve[0]); |
1401 | for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++) | 1399 | for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++) |
1402 | seq_printf(m, ", %ld", zone->lowmem_reserve[i]); | 1400 | seq_printf(m, ", %ld", zone->lowmem_reserve[i]); |
1403 | seq_printf(m, | 1401 | seq_putc(m, ')'); |
1404 | ")" | 1402 | |
1405 | "\n pagesets"); | 1403 | /* If unpopulated, no other information is useful */ |
1404 | if (!populated_zone(zone)) { | ||
1405 | seq_putc(m, '\n'); | ||
1406 | return; | ||
1407 | } | ||
1408 | |||
1409 | for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) | ||
1410 | seq_printf(m, "\n %-12s %lu", vmstat_text[i], | ||
1411 | zone_page_state(zone, i)); | ||
1412 | |||
1413 | seq_printf(m, "\n pagesets"); | ||
1406 | for_each_online_cpu(i) { | 1414 | for_each_online_cpu(i) { |
1407 | struct per_cpu_pageset *pageset; | 1415 | struct per_cpu_pageset *pageset; |
1408 | 1416 | ||
@@ -1425,19 +1433,22 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, | |||
1425 | "\n node_unreclaimable: %u" | 1433 | "\n node_unreclaimable: %u" |
1426 | "\n start_pfn: %lu" | 1434 | "\n start_pfn: %lu" |
1427 | "\n node_inactive_ratio: %u", | 1435 | "\n node_inactive_ratio: %u", |
1428 | !pgdat_reclaimable(zone->zone_pgdat), | 1436 | pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES, |
1429 | zone->zone_start_pfn, | 1437 | zone->zone_start_pfn, |
1430 | zone->zone_pgdat->inactive_ratio); | 1438 | zone->zone_pgdat->inactive_ratio); |
1431 | seq_putc(m, '\n'); | 1439 | seq_putc(m, '\n'); |
1432 | } | 1440 | } |
1433 | 1441 | ||
1434 | /* | 1442 | /* |
1435 | * Output information about zones in @pgdat. | 1443 | * Output information about zones in @pgdat. All zones are printed regardless |
1444 | * of whether they are populated or not: lowmem_reserve_ratio operates on the | ||
1445 | * set of all zones and userspace would not be aware of such zones if they are | ||
1446 | * suppressed here (zoneinfo displays the effect of lowmem_reserve_ratio). | ||
1436 | */ | 1447 | */ |
1437 | static int zoneinfo_show(struct seq_file *m, void *arg) | 1448 | static int zoneinfo_show(struct seq_file *m, void *arg) |
1438 | { | 1449 | { |
1439 | pg_data_t *pgdat = (pg_data_t *)arg; | 1450 | pg_data_t *pgdat = (pg_data_t *)arg; |
1440 | walk_zones_in_node(m, pgdat, zoneinfo_show_print); | 1451 | walk_zones_in_node(m, pgdat, false, zoneinfo_show_print); |
1441 | return 0; | 1452 | return 0; |
1442 | } | 1453 | } |
1443 | 1454 | ||
@@ -1586,22 +1597,9 @@ int vmstat_refresh(struct ctl_table *table, int write, | |||
1586 | for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) { | 1597 | for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) { |
1587 | val = atomic_long_read(&vm_zone_stat[i]); | 1598 | val = atomic_long_read(&vm_zone_stat[i]); |
1588 | if (val < 0) { | 1599 | if (val < 0) { |
1589 | switch (i) { | 1600 | pr_warn("%s: %s %ld\n", |
1590 | case NR_PAGES_SCANNED: | 1601 | __func__, vmstat_text[i], val); |
1591 | /* | 1602 | err = -EINVAL; |
1592 | * This is often seen to go negative in | ||
1593 | * recent kernels, but not to go permanently | ||
1594 | * negative. Whilst it would be nicer not to | ||
1595 | * have exceptions, rooting them out would be | ||
1596 | * another task, of rather low priority. | ||
1597 | */ | ||
1598 | break; | ||
1599 | default: | ||
1600 | pr_warn("%s: %s %ld\n", | ||
1601 | __func__, vmstat_text[i], val); | ||
1602 | err = -EINVAL; | ||
1603 | break; | ||
1604 | } | ||
1605 | } | 1603 | } |
1606 | } | 1604 | } |
1607 | if (err) | 1605 | if (err) |
@@ -1768,8 +1766,7 @@ void __init init_mm_internals(void) | |||
1768 | { | 1766 | { |
1769 | int ret __maybe_unused; | 1767 | int ret __maybe_unused; |
1770 | 1768 | ||
1771 | mm_percpu_wq = alloc_workqueue("mm_percpu_wq", | 1769 | mm_percpu_wq = alloc_workqueue("mm_percpu_wq", WQ_MEM_RECLAIM, 0); |
1772 | WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); | ||
1773 | 1770 | ||
1774 | #ifdef CONFIG_SMP | 1771 | #ifdef CONFIG_SMP |
1775 | ret = cpuhp_setup_state_nocalls(CPUHP_MM_VMSTAT_DEAD, "mm/vmstat:dead", | 1772 | ret = cpuhp_setup_state_nocalls(CPUHP_MM_VMSTAT_DEAD, "mm/vmstat:dead", |
@@ -1857,7 +1854,7 @@ static int unusable_show(struct seq_file *m, void *arg) | |||
1857 | if (!node_state(pgdat->node_id, N_MEMORY)) | 1854 | if (!node_state(pgdat->node_id, N_MEMORY)) |
1858 | return 0; | 1855 | return 0; |
1859 | 1856 | ||
1860 | walk_zones_in_node(m, pgdat, unusable_show_print); | 1857 | walk_zones_in_node(m, pgdat, true, unusable_show_print); |
1861 | 1858 | ||
1862 | return 0; | 1859 | return 0; |
1863 | } | 1860 | } |
@@ -1909,7 +1906,7 @@ static int extfrag_show(struct seq_file *m, void *arg) | |||
1909 | { | 1906 | { |
1910 | pg_data_t *pgdat = (pg_data_t *)arg; | 1907 | pg_data_t *pgdat = (pg_data_t *)arg; |
1911 | 1908 | ||
1912 | walk_zones_in_node(m, pgdat, extfrag_show_print); | 1909 | walk_zones_in_node(m, pgdat, true, extfrag_show_print); |
1913 | 1910 | ||
1914 | return 0; | 1911 | return 0; |
1915 | } | 1912 | } |