1f6ac2354SChristoph Lameter /* 2f6ac2354SChristoph Lameter * linux/mm/vmstat.c 3f6ac2354SChristoph Lameter * 4f6ac2354SChristoph Lameter * Manages VM statistics 5f6ac2354SChristoph Lameter * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds 6*2244b95aSChristoph Lameter * 7*2244b95aSChristoph Lameter * zoned VM statistics 8*2244b95aSChristoph Lameter * Copyright (C) 2006 Silicon Graphics, Inc., 9*2244b95aSChristoph Lameter * Christoph Lameter <christoph@lameter.com> 10f6ac2354SChristoph Lameter */ 11f6ac2354SChristoph Lameter 12f6ac2354SChristoph Lameter #include <linux/config.h> 13f6ac2354SChristoph Lameter #include <linux/mm.h> 14*2244b95aSChristoph Lameter #include <linux/module.h> 15f6ac2354SChristoph Lameter 16f6ac2354SChristoph Lameter /* 17f6ac2354SChristoph Lameter * Accumulate the page_state information across all CPUs. 18f6ac2354SChristoph Lameter * The result is unavoidably approximate - it can change 19f6ac2354SChristoph Lameter * during and after execution of this function. 20f6ac2354SChristoph Lameter */ 21f6ac2354SChristoph Lameter DEFINE_PER_CPU(struct page_state, page_states) = {0}; 22f6ac2354SChristoph Lameter 23f6ac2354SChristoph Lameter atomic_t nr_pagecache = ATOMIC_INIT(0); 24f6ac2354SChristoph Lameter EXPORT_SYMBOL(nr_pagecache); 25f6ac2354SChristoph Lameter #ifdef CONFIG_SMP 26f6ac2354SChristoph Lameter DEFINE_PER_CPU(long, nr_pagecache_local) = 0; 27f6ac2354SChristoph Lameter #endif 28f6ac2354SChristoph Lameter 29f6ac2354SChristoph Lameter static void __get_page_state(struct page_state *ret, int nr, cpumask_t *cpumask) 30f6ac2354SChristoph Lameter { 31f6ac2354SChristoph Lameter unsigned cpu; 32f6ac2354SChristoph Lameter 33f6ac2354SChristoph Lameter memset(ret, 0, nr * sizeof(unsigned long)); 34f6ac2354SChristoph Lameter cpus_and(*cpumask, *cpumask, cpu_online_map); 35f6ac2354SChristoph Lameter 36f6ac2354SChristoph Lameter for_each_cpu_mask(cpu, *cpumask) { 37f6ac2354SChristoph Lameter unsigned long *in; 38f6ac2354SChristoph Lameter unsigned long *out; 39f6ac2354SChristoph Lameter unsigned off; 40f6ac2354SChristoph Lameter unsigned next_cpu; 41f6ac2354SChristoph Lameter 42f6ac2354SChristoph Lameter in = (unsigned long *)&per_cpu(page_states, cpu); 43f6ac2354SChristoph Lameter 44f6ac2354SChristoph Lameter next_cpu = next_cpu(cpu, *cpumask); 45f6ac2354SChristoph Lameter if (likely(next_cpu < NR_CPUS)) 46f6ac2354SChristoph Lameter prefetch(&per_cpu(page_states, next_cpu)); 47f6ac2354SChristoph Lameter 48f6ac2354SChristoph Lameter out = (unsigned long *)ret; 49f6ac2354SChristoph Lameter for (off = 0; off < nr; off++) 50f6ac2354SChristoph Lameter *out++ += *in++; 51f6ac2354SChristoph Lameter } 52f6ac2354SChristoph Lameter } 53f6ac2354SChristoph Lameter 54f6ac2354SChristoph Lameter void get_page_state_node(struct page_state *ret, int node) 55f6ac2354SChristoph Lameter { 56f6ac2354SChristoph Lameter int nr; 57f6ac2354SChristoph Lameter cpumask_t mask = node_to_cpumask(node); 58f6ac2354SChristoph Lameter 59f6ac2354SChristoph Lameter nr = offsetof(struct page_state, GET_PAGE_STATE_LAST); 60f6ac2354SChristoph Lameter nr /= sizeof(unsigned long); 61f6ac2354SChristoph Lameter 62f6ac2354SChristoph Lameter __get_page_state(ret, nr+1, &mask); 63f6ac2354SChristoph Lameter } 64f6ac2354SChristoph Lameter 65f6ac2354SChristoph Lameter void get_page_state(struct page_state *ret) 66f6ac2354SChristoph Lameter { 67f6ac2354SChristoph Lameter int nr; 68f6ac2354SChristoph Lameter cpumask_t mask = CPU_MASK_ALL; 69f6ac2354SChristoph Lameter 70f6ac2354SChristoph Lameter nr = offsetof(struct page_state, GET_PAGE_STATE_LAST); 71f6ac2354SChristoph Lameter nr /= sizeof(unsigned long); 72f6ac2354SChristoph Lameter 73f6ac2354SChristoph Lameter __get_page_state(ret, nr + 1, &mask); 74f6ac2354SChristoph Lameter } 75f6ac2354SChristoph Lameter 76f6ac2354SChristoph Lameter void get_full_page_state(struct page_state *ret) 77f6ac2354SChristoph Lameter { 78f6ac2354SChristoph Lameter cpumask_t mask = CPU_MASK_ALL; 79f6ac2354SChristoph Lameter 80f6ac2354SChristoph Lameter __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long), &mask); 81f6ac2354SChristoph Lameter } 82f6ac2354SChristoph Lameter 83f6ac2354SChristoph Lameter unsigned long read_page_state_offset(unsigned long offset) 84f6ac2354SChristoph Lameter { 85f6ac2354SChristoph Lameter unsigned long ret = 0; 86f6ac2354SChristoph Lameter int cpu; 87f6ac2354SChristoph Lameter 88f6ac2354SChristoph Lameter for_each_online_cpu(cpu) { 89f6ac2354SChristoph Lameter unsigned long in; 90f6ac2354SChristoph Lameter 91f6ac2354SChristoph Lameter in = (unsigned long)&per_cpu(page_states, cpu) + offset; 92f6ac2354SChristoph Lameter ret += *((unsigned long *)in); 93f6ac2354SChristoph Lameter } 94f6ac2354SChristoph Lameter return ret; 95f6ac2354SChristoph Lameter } 96f6ac2354SChristoph Lameter 97f6ac2354SChristoph Lameter void __mod_page_state_offset(unsigned long offset, unsigned long delta) 98f6ac2354SChristoph Lameter { 99f6ac2354SChristoph Lameter void *ptr; 100f6ac2354SChristoph Lameter 101f6ac2354SChristoph Lameter ptr = &__get_cpu_var(page_states); 102f6ac2354SChristoph Lameter *(unsigned long *)(ptr + offset) += delta; 103f6ac2354SChristoph Lameter } 104f6ac2354SChristoph Lameter EXPORT_SYMBOL(__mod_page_state_offset); 105f6ac2354SChristoph Lameter 106f6ac2354SChristoph Lameter void mod_page_state_offset(unsigned long offset, unsigned long delta) 107f6ac2354SChristoph Lameter { 108f6ac2354SChristoph Lameter unsigned long flags; 109f6ac2354SChristoph Lameter void *ptr; 110f6ac2354SChristoph Lameter 111f6ac2354SChristoph Lameter local_irq_save(flags); 112f6ac2354SChristoph Lameter ptr = &__get_cpu_var(page_states); 113f6ac2354SChristoph Lameter *(unsigned long *)(ptr + offset) += delta; 114f6ac2354SChristoph Lameter local_irq_restore(flags); 115f6ac2354SChristoph Lameter } 116f6ac2354SChristoph Lameter EXPORT_SYMBOL(mod_page_state_offset); 117f6ac2354SChristoph Lameter 118f6ac2354SChristoph Lameter void __get_zone_counts(unsigned long *active, unsigned long *inactive, 119f6ac2354SChristoph Lameter unsigned long *free, struct pglist_data *pgdat) 120f6ac2354SChristoph Lameter { 121f6ac2354SChristoph Lameter struct zone *zones = pgdat->node_zones; 122f6ac2354SChristoph Lameter int i; 123f6ac2354SChristoph Lameter 124f6ac2354SChristoph Lameter *active = 0; 125f6ac2354SChristoph Lameter *inactive = 0; 126f6ac2354SChristoph Lameter *free = 0; 127f6ac2354SChristoph Lameter for (i = 0; i < MAX_NR_ZONES; i++) { 128f6ac2354SChristoph Lameter *active += zones[i].nr_active; 129f6ac2354SChristoph Lameter *inactive += zones[i].nr_inactive; 130f6ac2354SChristoph Lameter *free += zones[i].free_pages; 131f6ac2354SChristoph Lameter } 132f6ac2354SChristoph Lameter } 133f6ac2354SChristoph Lameter 134f6ac2354SChristoph Lameter void get_zone_counts(unsigned long *active, 135f6ac2354SChristoph Lameter unsigned long *inactive, unsigned long *free) 136f6ac2354SChristoph Lameter { 137f6ac2354SChristoph Lameter struct pglist_data *pgdat; 138f6ac2354SChristoph Lameter 139f6ac2354SChristoph Lameter *active = 0; 140f6ac2354SChristoph Lameter *inactive = 0; 141f6ac2354SChristoph Lameter *free = 0; 142f6ac2354SChristoph Lameter for_each_online_pgdat(pgdat) { 143f6ac2354SChristoph Lameter unsigned long l, m, n; 144f6ac2354SChristoph Lameter __get_zone_counts(&l, &m, &n, pgdat); 145f6ac2354SChristoph Lameter *active += l; 146f6ac2354SChristoph Lameter *inactive += m; 147f6ac2354SChristoph Lameter *free += n; 148f6ac2354SChristoph Lameter } 149f6ac2354SChristoph Lameter } 150f6ac2354SChristoph Lameter 151*2244b95aSChristoph Lameter /* 152*2244b95aSChristoph Lameter * Manage combined zone based / global counters 153*2244b95aSChristoph Lameter * 154*2244b95aSChristoph Lameter * vm_stat contains the global counters 155*2244b95aSChristoph Lameter */ 156*2244b95aSChristoph Lameter atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS]; 157*2244b95aSChristoph Lameter EXPORT_SYMBOL(vm_stat); 158*2244b95aSChristoph Lameter 159*2244b95aSChristoph Lameter #ifdef CONFIG_SMP 160*2244b95aSChristoph Lameter 161*2244b95aSChristoph Lameter #define STAT_THRESHOLD 32 162*2244b95aSChristoph Lameter 163*2244b95aSChristoph Lameter /* 164*2244b95aSChristoph Lameter * Determine pointer to currently valid differential byte given a zone and 165*2244b95aSChristoph Lameter * the item number. 166*2244b95aSChristoph Lameter * 167*2244b95aSChristoph Lameter * Preemption must be off 168*2244b95aSChristoph Lameter */ 169*2244b95aSChristoph Lameter static inline s8 *diff_pointer(struct zone *zone, enum zone_stat_item item) 170*2244b95aSChristoph Lameter { 171*2244b95aSChristoph Lameter return &zone_pcp(zone, smp_processor_id())->vm_stat_diff[item]; 172*2244b95aSChristoph Lameter } 173*2244b95aSChristoph Lameter 174*2244b95aSChristoph Lameter /* 175*2244b95aSChristoph Lameter * For use when we know that interrupts are disabled. 176*2244b95aSChristoph Lameter */ 177*2244b95aSChristoph Lameter void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item, 178*2244b95aSChristoph Lameter int delta) 179*2244b95aSChristoph Lameter { 180*2244b95aSChristoph Lameter s8 *p; 181*2244b95aSChristoph Lameter long x; 182*2244b95aSChristoph Lameter 183*2244b95aSChristoph Lameter p = diff_pointer(zone, item); 184*2244b95aSChristoph Lameter x = delta + *p; 185*2244b95aSChristoph Lameter 186*2244b95aSChristoph Lameter if (unlikely(x > STAT_THRESHOLD || x < -STAT_THRESHOLD)) { 187*2244b95aSChristoph Lameter zone_page_state_add(x, zone, item); 188*2244b95aSChristoph Lameter x = 0; 189*2244b95aSChristoph Lameter } 190*2244b95aSChristoph Lameter 191*2244b95aSChristoph Lameter *p = x; 192*2244b95aSChristoph Lameter } 193*2244b95aSChristoph Lameter EXPORT_SYMBOL(__mod_zone_page_state); 194*2244b95aSChristoph Lameter 195*2244b95aSChristoph Lameter /* 196*2244b95aSChristoph Lameter * For an unknown interrupt state 197*2244b95aSChristoph Lameter */ 198*2244b95aSChristoph Lameter void mod_zone_page_state(struct zone *zone, enum zone_stat_item item, 199*2244b95aSChristoph Lameter int delta) 200*2244b95aSChristoph Lameter { 201*2244b95aSChristoph Lameter unsigned long flags; 202*2244b95aSChristoph Lameter 203*2244b95aSChristoph Lameter local_irq_save(flags); 204*2244b95aSChristoph Lameter __mod_zone_page_state(zone, item, delta); 205*2244b95aSChristoph Lameter local_irq_restore(flags); 206*2244b95aSChristoph Lameter } 207*2244b95aSChristoph Lameter EXPORT_SYMBOL(mod_zone_page_state); 208*2244b95aSChristoph Lameter 209*2244b95aSChristoph Lameter /* 210*2244b95aSChristoph Lameter * Optimized increment and decrement functions. 211*2244b95aSChristoph Lameter * 212*2244b95aSChristoph Lameter * These are only for a single page and therefore can take a struct page * 213*2244b95aSChristoph Lameter * argument instead of struct zone *. This allows the inclusion of the code 214*2244b95aSChristoph Lameter * generated for page_zone(page) into the optimized functions. 215*2244b95aSChristoph Lameter * 216*2244b95aSChristoph Lameter * No overflow check is necessary and therefore the differential can be 217*2244b95aSChristoph Lameter * incremented or decremented in place which may allow the compilers to 218*2244b95aSChristoph Lameter * generate better code. 219*2244b95aSChristoph Lameter * 220*2244b95aSChristoph Lameter * The increment or decrement is known and therefore one boundary check can 221*2244b95aSChristoph Lameter * be omitted. 222*2244b95aSChristoph Lameter * 223*2244b95aSChristoph Lameter * Some processors have inc/dec instructions that are atomic vs an interrupt. 224*2244b95aSChristoph Lameter * However, the code must first determine the differential location in a zone 225*2244b95aSChristoph Lameter * based on the processor number and then inc/dec the counter. There is no 226*2244b95aSChristoph Lameter * guarantee without disabling preemption that the processor will not change 227*2244b95aSChristoph Lameter * in between and therefore the atomicity vs. interrupt cannot be exploited 228*2244b95aSChristoph Lameter * in a useful way here. 229*2244b95aSChristoph Lameter */ 230*2244b95aSChristoph Lameter void __inc_zone_page_state(struct page *page, enum zone_stat_item item) 231*2244b95aSChristoph Lameter { 232*2244b95aSChristoph Lameter struct zone *zone = page_zone(page); 233*2244b95aSChristoph Lameter s8 *p = diff_pointer(zone, item); 234*2244b95aSChristoph Lameter 235*2244b95aSChristoph Lameter (*p)++; 236*2244b95aSChristoph Lameter 237*2244b95aSChristoph Lameter if (unlikely(*p > STAT_THRESHOLD)) { 238*2244b95aSChristoph Lameter zone_page_state_add(*p, zone, item); 239*2244b95aSChristoph Lameter *p = 0; 240*2244b95aSChristoph Lameter } 241*2244b95aSChristoph Lameter } 242*2244b95aSChristoph Lameter EXPORT_SYMBOL(__inc_zone_page_state); 243*2244b95aSChristoph Lameter 244*2244b95aSChristoph Lameter void __dec_zone_page_state(struct page *page, enum zone_stat_item item) 245*2244b95aSChristoph Lameter { 246*2244b95aSChristoph Lameter struct zone *zone = page_zone(page); 247*2244b95aSChristoph Lameter s8 *p = diff_pointer(zone, item); 248*2244b95aSChristoph Lameter 249*2244b95aSChristoph Lameter (*p)--; 250*2244b95aSChristoph Lameter 251*2244b95aSChristoph Lameter if (unlikely(*p < -STAT_THRESHOLD)) { 252*2244b95aSChristoph Lameter zone_page_state_add(*p, zone, item); 253*2244b95aSChristoph Lameter *p = 0; 254*2244b95aSChristoph Lameter } 255*2244b95aSChristoph Lameter } 256*2244b95aSChristoph Lameter EXPORT_SYMBOL(__dec_zone_page_state); 257*2244b95aSChristoph Lameter 258*2244b95aSChristoph Lameter void inc_zone_page_state(struct page *page, enum zone_stat_item item) 259*2244b95aSChristoph Lameter { 260*2244b95aSChristoph Lameter unsigned long flags; 261*2244b95aSChristoph Lameter struct zone *zone; 262*2244b95aSChristoph Lameter s8 *p; 263*2244b95aSChristoph Lameter 264*2244b95aSChristoph Lameter zone = page_zone(page); 265*2244b95aSChristoph Lameter local_irq_save(flags); 266*2244b95aSChristoph Lameter p = diff_pointer(zone, item); 267*2244b95aSChristoph Lameter 268*2244b95aSChristoph Lameter (*p)++; 269*2244b95aSChristoph Lameter 270*2244b95aSChristoph Lameter if (unlikely(*p > STAT_THRESHOLD)) { 271*2244b95aSChristoph Lameter zone_page_state_add(*p, zone, item); 272*2244b95aSChristoph Lameter *p = 0; 273*2244b95aSChristoph Lameter } 274*2244b95aSChristoph Lameter local_irq_restore(flags); 275*2244b95aSChristoph Lameter } 276*2244b95aSChristoph Lameter EXPORT_SYMBOL(inc_zone_page_state); 277*2244b95aSChristoph Lameter 278*2244b95aSChristoph Lameter void dec_zone_page_state(struct page *page, enum zone_stat_item item) 279*2244b95aSChristoph Lameter { 280*2244b95aSChristoph Lameter unsigned long flags; 281*2244b95aSChristoph Lameter struct zone *zone; 282*2244b95aSChristoph Lameter s8 *p; 283*2244b95aSChristoph Lameter 284*2244b95aSChristoph Lameter zone = page_zone(page); 285*2244b95aSChristoph Lameter local_irq_save(flags); 286*2244b95aSChristoph Lameter p = diff_pointer(zone, item); 287*2244b95aSChristoph Lameter 288*2244b95aSChristoph Lameter (*p)--; 289*2244b95aSChristoph Lameter 290*2244b95aSChristoph Lameter if (unlikely(*p < -STAT_THRESHOLD)) { 291*2244b95aSChristoph Lameter zone_page_state_add(*p, zone, item); 292*2244b95aSChristoph Lameter *p = 0; 293*2244b95aSChristoph Lameter } 294*2244b95aSChristoph Lameter local_irq_restore(flags); 295*2244b95aSChristoph Lameter } 296*2244b95aSChristoph Lameter EXPORT_SYMBOL(dec_zone_page_state); 297*2244b95aSChristoph Lameter 298*2244b95aSChristoph Lameter /* 299*2244b95aSChristoph Lameter * Update the zone counters for one cpu. 300*2244b95aSChristoph Lameter */ 301*2244b95aSChristoph Lameter void refresh_cpu_vm_stats(int cpu) 302*2244b95aSChristoph Lameter { 303*2244b95aSChristoph Lameter struct zone *zone; 304*2244b95aSChristoph Lameter int i; 305*2244b95aSChristoph Lameter unsigned long flags; 306*2244b95aSChristoph Lameter 307*2244b95aSChristoph Lameter for_each_zone(zone) { 308*2244b95aSChristoph Lameter struct per_cpu_pageset *pcp; 309*2244b95aSChristoph Lameter 310*2244b95aSChristoph Lameter pcp = zone_pcp(zone, cpu); 311*2244b95aSChristoph Lameter 312*2244b95aSChristoph Lameter for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) 313*2244b95aSChristoph Lameter if (pcp->vm_stat_diff[i]) { 314*2244b95aSChristoph Lameter local_irq_save(flags); 315*2244b95aSChristoph Lameter zone_page_state_add(pcp->vm_stat_diff[i], 316*2244b95aSChristoph Lameter zone, i); 317*2244b95aSChristoph Lameter pcp->vm_stat_diff[i] = 0; 318*2244b95aSChristoph Lameter local_irq_restore(flags); 319*2244b95aSChristoph Lameter } 320*2244b95aSChristoph Lameter } 321*2244b95aSChristoph Lameter } 322*2244b95aSChristoph Lameter 323*2244b95aSChristoph Lameter static void __refresh_cpu_vm_stats(void *dummy) 324*2244b95aSChristoph Lameter { 325*2244b95aSChristoph Lameter refresh_cpu_vm_stats(smp_processor_id()); 326*2244b95aSChristoph Lameter } 327*2244b95aSChristoph Lameter 328*2244b95aSChristoph Lameter /* 329*2244b95aSChristoph Lameter * Consolidate all counters. 330*2244b95aSChristoph Lameter * 331*2244b95aSChristoph Lameter * Note that the result is less inaccurate but still inaccurate 332*2244b95aSChristoph Lameter * if concurrent processes are allowed to run. 333*2244b95aSChristoph Lameter */ 334*2244b95aSChristoph Lameter void refresh_vm_stats(void) 335*2244b95aSChristoph Lameter { 336*2244b95aSChristoph Lameter on_each_cpu(__refresh_cpu_vm_stats, NULL, 0, 1); 337*2244b95aSChristoph Lameter } 338*2244b95aSChristoph Lameter EXPORT_SYMBOL(refresh_vm_stats); 339*2244b95aSChristoph Lameter 340*2244b95aSChristoph Lameter #endif 341*2244b95aSChristoph Lameter 342f6ac2354SChristoph Lameter #ifdef CONFIG_PROC_FS 343f6ac2354SChristoph Lameter 344f6ac2354SChristoph Lameter #include <linux/seq_file.h> 345f6ac2354SChristoph Lameter 346f6ac2354SChristoph Lameter static void *frag_start(struct seq_file *m, loff_t *pos) 347f6ac2354SChristoph Lameter { 348f6ac2354SChristoph Lameter pg_data_t *pgdat; 349f6ac2354SChristoph Lameter loff_t node = *pos; 350f6ac2354SChristoph Lameter for (pgdat = first_online_pgdat(); 351f6ac2354SChristoph Lameter pgdat && node; 352f6ac2354SChristoph Lameter pgdat = next_online_pgdat(pgdat)) 353f6ac2354SChristoph Lameter --node; 354f6ac2354SChristoph Lameter 355f6ac2354SChristoph Lameter return pgdat; 356f6ac2354SChristoph Lameter } 357f6ac2354SChristoph Lameter 358f6ac2354SChristoph Lameter static void *frag_next(struct seq_file *m, void *arg, loff_t *pos) 359f6ac2354SChristoph Lameter { 360f6ac2354SChristoph Lameter pg_data_t *pgdat = (pg_data_t *)arg; 361f6ac2354SChristoph Lameter 362f6ac2354SChristoph Lameter (*pos)++; 363f6ac2354SChristoph Lameter return next_online_pgdat(pgdat); 364f6ac2354SChristoph Lameter } 365f6ac2354SChristoph Lameter 366f6ac2354SChristoph Lameter static void frag_stop(struct seq_file *m, void *arg) 367f6ac2354SChristoph Lameter { 368f6ac2354SChristoph Lameter } 369f6ac2354SChristoph Lameter 370f6ac2354SChristoph Lameter /* 371f6ac2354SChristoph Lameter * This walks the free areas for each zone. 372f6ac2354SChristoph Lameter */ 373f6ac2354SChristoph Lameter static int frag_show(struct seq_file *m, void *arg) 374f6ac2354SChristoph Lameter { 375f6ac2354SChristoph Lameter pg_data_t *pgdat = (pg_data_t *)arg; 376f6ac2354SChristoph Lameter struct zone *zone; 377f6ac2354SChristoph Lameter struct zone *node_zones = pgdat->node_zones; 378f6ac2354SChristoph Lameter unsigned long flags; 379f6ac2354SChristoph Lameter int order; 380f6ac2354SChristoph Lameter 381f6ac2354SChristoph Lameter for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { 382f6ac2354SChristoph Lameter if (!populated_zone(zone)) 383f6ac2354SChristoph Lameter continue; 384f6ac2354SChristoph Lameter 385f6ac2354SChristoph Lameter spin_lock_irqsave(&zone->lock, flags); 386f6ac2354SChristoph Lameter seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name); 387f6ac2354SChristoph Lameter for (order = 0; order < MAX_ORDER; ++order) 388f6ac2354SChristoph Lameter seq_printf(m, "%6lu ", zone->free_area[order].nr_free); 389f6ac2354SChristoph Lameter spin_unlock_irqrestore(&zone->lock, flags); 390f6ac2354SChristoph Lameter seq_putc(m, '\n'); 391f6ac2354SChristoph Lameter } 392f6ac2354SChristoph Lameter return 0; 393f6ac2354SChristoph Lameter } 394f6ac2354SChristoph Lameter 395f6ac2354SChristoph Lameter struct seq_operations fragmentation_op = { 396f6ac2354SChristoph Lameter .start = frag_start, 397f6ac2354SChristoph Lameter .next = frag_next, 398f6ac2354SChristoph Lameter .stop = frag_stop, 399f6ac2354SChristoph Lameter .show = frag_show, 400f6ac2354SChristoph Lameter }; 401f6ac2354SChristoph Lameter 402f6ac2354SChristoph Lameter static char *vmstat_text[] = { 403*2244b95aSChristoph Lameter /* Zoned VM counters */ 404*2244b95aSChristoph Lameter 405*2244b95aSChristoph Lameter /* Page state */ 406f6ac2354SChristoph Lameter "nr_dirty", 407f6ac2354SChristoph Lameter "nr_writeback", 408f6ac2354SChristoph Lameter "nr_unstable", 409f6ac2354SChristoph Lameter "nr_page_table_pages", 410f6ac2354SChristoph Lameter "nr_mapped", 411f6ac2354SChristoph Lameter "nr_slab", 412f6ac2354SChristoph Lameter 413f6ac2354SChristoph Lameter "pgpgin", 414f6ac2354SChristoph Lameter "pgpgout", 415f6ac2354SChristoph Lameter "pswpin", 416f6ac2354SChristoph Lameter "pswpout", 417f6ac2354SChristoph Lameter 418f6ac2354SChristoph Lameter "pgalloc_high", 419f6ac2354SChristoph Lameter "pgalloc_normal", 420f6ac2354SChristoph Lameter "pgalloc_dma32", 421f6ac2354SChristoph Lameter "pgalloc_dma", 422f6ac2354SChristoph Lameter 423f6ac2354SChristoph Lameter "pgfree", 424f6ac2354SChristoph Lameter "pgactivate", 425f6ac2354SChristoph Lameter "pgdeactivate", 426f6ac2354SChristoph Lameter 427f6ac2354SChristoph Lameter "pgfault", 428f6ac2354SChristoph Lameter "pgmajfault", 429f6ac2354SChristoph Lameter 430f6ac2354SChristoph Lameter "pgrefill_high", 431f6ac2354SChristoph Lameter "pgrefill_normal", 432f6ac2354SChristoph Lameter "pgrefill_dma32", 433f6ac2354SChristoph Lameter "pgrefill_dma", 434f6ac2354SChristoph Lameter 435f6ac2354SChristoph Lameter "pgsteal_high", 436f6ac2354SChristoph Lameter "pgsteal_normal", 437f6ac2354SChristoph Lameter "pgsteal_dma32", 438f6ac2354SChristoph Lameter "pgsteal_dma", 439f6ac2354SChristoph Lameter 440f6ac2354SChristoph Lameter "pgscan_kswapd_high", 441f6ac2354SChristoph Lameter "pgscan_kswapd_normal", 442f6ac2354SChristoph Lameter "pgscan_kswapd_dma32", 443f6ac2354SChristoph Lameter "pgscan_kswapd_dma", 444f6ac2354SChristoph Lameter 445f6ac2354SChristoph Lameter "pgscan_direct_high", 446f6ac2354SChristoph Lameter "pgscan_direct_normal", 447f6ac2354SChristoph Lameter "pgscan_direct_dma32", 448f6ac2354SChristoph Lameter "pgscan_direct_dma", 449f6ac2354SChristoph Lameter 450f6ac2354SChristoph Lameter "pginodesteal", 451f6ac2354SChristoph Lameter "slabs_scanned", 452f6ac2354SChristoph Lameter "kswapd_steal", 453f6ac2354SChristoph Lameter "kswapd_inodesteal", 454f6ac2354SChristoph Lameter "pageoutrun", 455f6ac2354SChristoph Lameter "allocstall", 456f6ac2354SChristoph Lameter 457f6ac2354SChristoph Lameter "pgrotated", 458f6ac2354SChristoph Lameter "nr_bounce", 459f6ac2354SChristoph Lameter }; 460f6ac2354SChristoph Lameter 461f6ac2354SChristoph Lameter /* 462f6ac2354SChristoph Lameter * Output information about zones in @pgdat. 463f6ac2354SChristoph Lameter */ 464f6ac2354SChristoph Lameter static int zoneinfo_show(struct seq_file *m, void *arg) 465f6ac2354SChristoph Lameter { 466f6ac2354SChristoph Lameter pg_data_t *pgdat = arg; 467f6ac2354SChristoph Lameter struct zone *zone; 468f6ac2354SChristoph Lameter struct zone *node_zones = pgdat->node_zones; 469f6ac2354SChristoph Lameter unsigned long flags; 470f6ac2354SChristoph Lameter 471f6ac2354SChristoph Lameter for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; zone++) { 472f6ac2354SChristoph Lameter int i; 473f6ac2354SChristoph Lameter 474f6ac2354SChristoph Lameter if (!populated_zone(zone)) 475f6ac2354SChristoph Lameter continue; 476f6ac2354SChristoph Lameter 477f6ac2354SChristoph Lameter spin_lock_irqsave(&zone->lock, flags); 478f6ac2354SChristoph Lameter seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name); 479f6ac2354SChristoph Lameter seq_printf(m, 480f6ac2354SChristoph Lameter "\n pages free %lu" 481f6ac2354SChristoph Lameter "\n min %lu" 482f6ac2354SChristoph Lameter "\n low %lu" 483f6ac2354SChristoph Lameter "\n high %lu" 484f6ac2354SChristoph Lameter "\n active %lu" 485f6ac2354SChristoph Lameter "\n inactive %lu" 486f6ac2354SChristoph Lameter "\n scanned %lu (a: %lu i: %lu)" 487f6ac2354SChristoph Lameter "\n spanned %lu" 488f6ac2354SChristoph Lameter "\n present %lu", 489f6ac2354SChristoph Lameter zone->free_pages, 490f6ac2354SChristoph Lameter zone->pages_min, 491f6ac2354SChristoph Lameter zone->pages_low, 492f6ac2354SChristoph Lameter zone->pages_high, 493f6ac2354SChristoph Lameter zone->nr_active, 494f6ac2354SChristoph Lameter zone->nr_inactive, 495f6ac2354SChristoph Lameter zone->pages_scanned, 496f6ac2354SChristoph Lameter zone->nr_scan_active, zone->nr_scan_inactive, 497f6ac2354SChristoph Lameter zone->spanned_pages, 498f6ac2354SChristoph Lameter zone->present_pages); 499*2244b95aSChristoph Lameter 500*2244b95aSChristoph Lameter for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) 501*2244b95aSChristoph Lameter seq_printf(m, "\n %-12s %lu", vmstat_text[i], 502*2244b95aSChristoph Lameter zone_page_state(zone, i)); 503*2244b95aSChristoph Lameter 504f6ac2354SChristoph Lameter seq_printf(m, 505f6ac2354SChristoph Lameter "\n protection: (%lu", 506f6ac2354SChristoph Lameter zone->lowmem_reserve[0]); 507f6ac2354SChristoph Lameter for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++) 508f6ac2354SChristoph Lameter seq_printf(m, ", %lu", zone->lowmem_reserve[i]); 509f6ac2354SChristoph Lameter seq_printf(m, 510f6ac2354SChristoph Lameter ")" 511f6ac2354SChristoph Lameter "\n pagesets"); 512f6ac2354SChristoph Lameter for_each_online_cpu(i) { 513f6ac2354SChristoph Lameter struct per_cpu_pageset *pageset; 514f6ac2354SChristoph Lameter int j; 515f6ac2354SChristoph Lameter 516f6ac2354SChristoph Lameter pageset = zone_pcp(zone, i); 517f6ac2354SChristoph Lameter for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) { 518f6ac2354SChristoph Lameter if (pageset->pcp[j].count) 519f6ac2354SChristoph Lameter break; 520f6ac2354SChristoph Lameter } 521f6ac2354SChristoph Lameter if (j == ARRAY_SIZE(pageset->pcp)) 522f6ac2354SChristoph Lameter continue; 523f6ac2354SChristoph Lameter for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) { 524f6ac2354SChristoph Lameter seq_printf(m, 525f6ac2354SChristoph Lameter "\n cpu: %i pcp: %i" 526f6ac2354SChristoph Lameter "\n count: %i" 527f6ac2354SChristoph Lameter "\n high: %i" 528f6ac2354SChristoph Lameter "\n batch: %i", 529f6ac2354SChristoph Lameter i, j, 530f6ac2354SChristoph Lameter pageset->pcp[j].count, 531f6ac2354SChristoph Lameter pageset->pcp[j].high, 532f6ac2354SChristoph Lameter pageset->pcp[j].batch); 533f6ac2354SChristoph Lameter } 534f6ac2354SChristoph Lameter #ifdef CONFIG_NUMA 535f6ac2354SChristoph Lameter seq_printf(m, 536f6ac2354SChristoph Lameter "\n numa_hit: %lu" 537f6ac2354SChristoph Lameter "\n numa_miss: %lu" 538f6ac2354SChristoph Lameter "\n numa_foreign: %lu" 539f6ac2354SChristoph Lameter "\n interleave_hit: %lu" 540f6ac2354SChristoph Lameter "\n local_node: %lu" 541f6ac2354SChristoph Lameter "\n other_node: %lu", 542f6ac2354SChristoph Lameter pageset->numa_hit, 543f6ac2354SChristoph Lameter pageset->numa_miss, 544f6ac2354SChristoph Lameter pageset->numa_foreign, 545f6ac2354SChristoph Lameter pageset->interleave_hit, 546f6ac2354SChristoph Lameter pageset->local_node, 547f6ac2354SChristoph Lameter pageset->other_node); 548f6ac2354SChristoph Lameter #endif 549f6ac2354SChristoph Lameter } 550f6ac2354SChristoph Lameter seq_printf(m, 551f6ac2354SChristoph Lameter "\n all_unreclaimable: %u" 552f6ac2354SChristoph Lameter "\n prev_priority: %i" 553f6ac2354SChristoph Lameter "\n temp_priority: %i" 554f6ac2354SChristoph Lameter "\n start_pfn: %lu", 555f6ac2354SChristoph Lameter zone->all_unreclaimable, 556f6ac2354SChristoph Lameter zone->prev_priority, 557f6ac2354SChristoph Lameter zone->temp_priority, 558f6ac2354SChristoph Lameter zone->zone_start_pfn); 559f6ac2354SChristoph Lameter spin_unlock_irqrestore(&zone->lock, flags); 560f6ac2354SChristoph Lameter seq_putc(m, '\n'); 561f6ac2354SChristoph Lameter } 562f6ac2354SChristoph Lameter return 0; 563f6ac2354SChristoph Lameter } 564f6ac2354SChristoph Lameter 565f6ac2354SChristoph Lameter struct seq_operations zoneinfo_op = { 566f6ac2354SChristoph Lameter .start = frag_start, /* iterate over all zones. The same as in 567f6ac2354SChristoph Lameter * fragmentation. */ 568f6ac2354SChristoph Lameter .next = frag_next, 569f6ac2354SChristoph Lameter .stop = frag_stop, 570f6ac2354SChristoph Lameter .show = zoneinfo_show, 571f6ac2354SChristoph Lameter }; 572f6ac2354SChristoph Lameter 573f6ac2354SChristoph Lameter static void *vmstat_start(struct seq_file *m, loff_t *pos) 574f6ac2354SChristoph Lameter { 575*2244b95aSChristoph Lameter unsigned long *v; 576f6ac2354SChristoph Lameter struct page_state *ps; 577*2244b95aSChristoph Lameter int i; 578f6ac2354SChristoph Lameter 579f6ac2354SChristoph Lameter if (*pos >= ARRAY_SIZE(vmstat_text)) 580f6ac2354SChristoph Lameter return NULL; 581f6ac2354SChristoph Lameter 582*2244b95aSChristoph Lameter v = kmalloc(NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long) 583*2244b95aSChristoph Lameter + sizeof(*ps), GFP_KERNEL); 584*2244b95aSChristoph Lameter m->private = v; 585*2244b95aSChristoph Lameter if (!v) 586f6ac2354SChristoph Lameter return ERR_PTR(-ENOMEM); 587*2244b95aSChristoph Lameter for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) 588*2244b95aSChristoph Lameter v[i] = global_page_state(i); 589*2244b95aSChristoph Lameter ps = (struct page_state *)(v + NR_VM_ZONE_STAT_ITEMS); 590f6ac2354SChristoph Lameter get_full_page_state(ps); 591f6ac2354SChristoph Lameter ps->pgpgin /= 2; /* sectors -> kbytes */ 592f6ac2354SChristoph Lameter ps->pgpgout /= 2; 593*2244b95aSChristoph Lameter return v + *pos; 594f6ac2354SChristoph Lameter } 595f6ac2354SChristoph Lameter 596f6ac2354SChristoph Lameter static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos) 597f6ac2354SChristoph Lameter { 598f6ac2354SChristoph Lameter (*pos)++; 599f6ac2354SChristoph Lameter if (*pos >= ARRAY_SIZE(vmstat_text)) 600f6ac2354SChristoph Lameter return NULL; 601f6ac2354SChristoph Lameter return (unsigned long *)m->private + *pos; 602f6ac2354SChristoph Lameter } 603f6ac2354SChristoph Lameter 604f6ac2354SChristoph Lameter static int vmstat_show(struct seq_file *m, void *arg) 605f6ac2354SChristoph Lameter { 606f6ac2354SChristoph Lameter unsigned long *l = arg; 607f6ac2354SChristoph Lameter unsigned long off = l - (unsigned long *)m->private; 608f6ac2354SChristoph Lameter 609f6ac2354SChristoph Lameter seq_printf(m, "%s %lu\n", vmstat_text[off], *l); 610f6ac2354SChristoph Lameter return 0; 611f6ac2354SChristoph Lameter } 612f6ac2354SChristoph Lameter 613f6ac2354SChristoph Lameter static void vmstat_stop(struct seq_file *m, void *arg) 614f6ac2354SChristoph Lameter { 615f6ac2354SChristoph Lameter kfree(m->private); 616f6ac2354SChristoph Lameter m->private = NULL; 617f6ac2354SChristoph Lameter } 618f6ac2354SChristoph Lameter 619f6ac2354SChristoph Lameter struct seq_operations vmstat_op = { 620f6ac2354SChristoph Lameter .start = vmstat_start, 621f6ac2354SChristoph Lameter .next = vmstat_next, 622f6ac2354SChristoph Lameter .stop = vmstat_stop, 623f6ac2354SChristoph Lameter .show = vmstat_show, 624f6ac2354SChristoph Lameter }; 625f6ac2354SChristoph Lameter 626f6ac2354SChristoph Lameter #endif /* CONFIG_PROC_FS */ 627f6ac2354SChristoph Lameter 628