From: Martin Hicks Add page_state info to the per-node meminfo file in sysfs. This is mostly just for informational purposes. The lack of this information was brought up recently during a discussion regarding pagecache clearing, and I put this patch together to test out one of the suggestions. It seems like interesting info to have, so I'm submitting the patch. Signed-off-by: Martin Hicks Signed-off-by: Andrew Morton --- drivers/base/node.c | 24 ++++++++++++++++++++++-- include/linux/page-flags.h | 1 + mm/page_alloc.c | 25 ++++++++++++++++++++----- 3 files changed, 43 insertions(+), 7 deletions(-) diff -puN drivers/base/node.c~vm-add-page_state-info-to-per-node-meminfo drivers/base/node.c --- 25/drivers/base/node.c~vm-add-page_state-info-to-per-node-meminfo Wed Aug 17 16:27:07 2005 +++ 25-akpm/drivers/base/node.c Wed Aug 17 16:27:07 2005 @@ -39,13 +39,25 @@ static ssize_t node_read_meminfo(struct int n; int nid = dev->id; struct sysinfo i; + struct page_state ps; unsigned long inactive; unsigned long active; unsigned long free; si_meminfo_node(&i, nid); + get_page_state_node(&ps, nid); __get_zone_counts(&active, &inactive, &free, NODE_DATA(nid)); + /* Check for negative values in these approximate counters */ + if ((long)ps.nr_dirty < 0) + ps.nr_dirty = 0; + if ((long)ps.nr_writeback < 0) + ps.nr_writeback = 0; + if ((long)ps.nr_mapped < 0) + ps.nr_mapped = 0; + if ((long)ps.nr_slab < 0) + ps.nr_slab = 0; + n = sprintf(buf, "\n" "Node %d MemTotal: %8lu kB\n" "Node %d MemFree: %8lu kB\n" @@ -55,7 +67,11 @@ static ssize_t node_read_meminfo(struct "Node %d HighTotal: %8lu kB\n" "Node %d HighFree: %8lu kB\n" "Node %d LowTotal: %8lu kB\n" - "Node %d LowFree: %8lu kB\n", + "Node %d LowFree: %8lu kB\n" + "Node %d Dirty: %8lu kB\n" + "Node %d Writeback: %8lu kB\n" + "Node %d Mapped: %8lu kB\n" + "Node %d Slab: %8lu kB\n", nid, K(i.totalram), nid, K(i.freeram), nid, K(i.totalram - i.freeram), @@ -64,7 +80,11 @@ static ssize_t node_read_meminfo(struct nid, K(i.totalhigh), nid, K(i.freehigh), nid, K(i.totalram - i.totalhigh), - nid, K(i.freeram - i.freehigh)); + nid, K(i.freeram - i.freehigh), + nid, K(ps.nr_dirty), + nid, K(ps.nr_writeback), + nid, K(ps.nr_mapped), + nid, K(ps.nr_slab)); n += hugetlb_report_node_meminfo(nid, buf + n); return n; } diff -puN include/linux/page-flags.h~vm-add-page_state-info-to-per-node-meminfo include/linux/page-flags.h --- 25/include/linux/page-flags.h~vm-add-page_state-info-to-per-node-meminfo Wed Aug 17 16:27:07 2005 +++ 25-akpm/include/linux/page-flags.h Wed Aug 17 16:27:07 2005 @@ -140,6 +140,7 @@ struct page_state { }; extern void get_page_state(struct page_state *ret); +extern void get_page_state_node(struct page_state *ret, int node); extern void get_full_page_state(struct page_state *ret); extern unsigned long __read_page_state(unsigned long offset); extern void __mod_page_state(unsigned long offset, unsigned long delta); diff -puN mm/page_alloc.c~vm-add-page_state-info-to-per-node-meminfo mm/page_alloc.c --- 25/mm/page_alloc.c~vm-add-page_state-info-to-per-node-meminfo Wed Aug 17 16:27:07 2005 +++ 25-akpm/mm/page_alloc.c Wed Aug 17 16:27:07 2005 @@ -1130,19 +1130,20 @@ EXPORT_SYMBOL(nr_pagecache); DEFINE_PER_CPU(long, nr_pagecache_local) = 0; #endif -void __get_page_state(struct page_state *ret, int nr) +void __get_page_state(struct page_state *ret, int nr, cpumask_t *cpumask) { int cpu = 0; memset(ret, 0, sizeof(*ret)); + cpus_and(*cpumask, *cpumask, cpu_online_map); - cpu = first_cpu(cpu_online_map); + cpu = first_cpu(*cpumask); while (cpu < NR_CPUS) { unsigned long *in, *out, off; in = (unsigned long *)&per_cpu(page_states, cpu); - cpu = next_cpu(cpu, cpu_online_map); + cpu = next_cpu(cpu, *cpumask); if (cpu < NR_CPUS) prefetch(&per_cpu(page_states, cpu)); @@ -1153,19 +1154,33 @@ void __get_page_state(struct page_state } } +void get_page_state_node(struct page_state *ret, int node) +{ + int nr; + cpumask_t mask = node_to_cpumask(node); + + nr = offsetof(struct page_state, GET_PAGE_STATE_LAST); + nr /= sizeof(unsigned long); + + __get_page_state(ret, nr+1, &mask); +} + void get_page_state(struct page_state *ret) { int nr; + cpumask_t mask = CPU_MASK_ALL; nr = offsetof(struct page_state, GET_PAGE_STATE_LAST); nr /= sizeof(unsigned long); - __get_page_state(ret, nr + 1); + __get_page_state(ret, nr + 1, &mask); } void get_full_page_state(struct page_state *ret) { - __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long)); + cpumask_t mask = CPU_MASK_ALL; + + __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long), &mask); } unsigned long __read_page_state(unsigned long offset) _