|
@@ -197,7 +197,7 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes)
|
|
|
return policy;
|
|
|
}
|
|
|
|
|
|
-static void gather_stats(struct page *, void *);
|
|
|
+static void gather_stats(struct page *, void *, int pte_dirty);
|
|
|
static void migrate_page_add(struct page *page, struct list_head *pagelist,
|
|
|
unsigned long flags);
|
|
|
|
|
@@ -239,7 +239,7 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
|
|
|
continue;
|
|
|
|
|
|
if (flags & MPOL_MF_STATS)
|
|
|
- gather_stats(page, private);
|
|
|
+ gather_stats(page, private, pte_dirty(*pte));
|
|
|
else if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
|
|
|
migrate_page_add(page, private, flags);
|
|
|
else
|
|
@@ -1753,67 +1753,137 @@ static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
|
|
|
struct numa_maps {
|
|
|
unsigned long pages;
|
|
|
unsigned long anon;
|
|
|
- unsigned long mapped;
|
|
|
+ unsigned long active;
|
|
|
+ unsigned long writeback;
|
|
|
unsigned long mapcount_max;
|
|
|
+ unsigned long dirty;
|
|
|
+ unsigned long swapcache;
|
|
|
unsigned long node[MAX_NUMNODES];
|
|
|
};
|
|
|
|
|
|
-static void gather_stats(struct page *page, void *private)
|
|
|
+static void gather_stats(struct page *page, void *private, int pte_dirty)
|
|
|
{
|
|
|
struct numa_maps *md = private;
|
|
|
int count = page_mapcount(page);
|
|
|
|
|
|
- if (count)
|
|
|
- md->mapped++;
|
|
|
+ md->pages++;
|
|
|
+ if (pte_dirty || PageDirty(page))
|
|
|
+ md->dirty++;
|
|
|
|
|
|
- if (count > md->mapcount_max)
|
|
|
- md->mapcount_max = count;
|
|
|
+ if (PageSwapCache(page))
|
|
|
+ md->swapcache++;
|
|
|
|
|
|
- md->pages++;
|
|
|
+ if (PageActive(page))
|
|
|
+ md->active++;
|
|
|
+
|
|
|
+ if (PageWriteback(page))
|
|
|
+ md->writeback++;
|
|
|
|
|
|
if (PageAnon(page))
|
|
|
md->anon++;
|
|
|
|
|
|
+ if (count > md->mapcount_max)
|
|
|
+ md->mapcount_max = count;
|
|
|
+
|
|
|
md->node[page_to_nid(page)]++;
|
|
|
cond_resched();
|
|
|
}
|
|
|
|
|
|
+static void check_huge_range(struct vm_area_struct *vma,
|
|
|
+ unsigned long start, unsigned long end,
|
|
|
+ struct numa_maps *md)
|
|
|
+{
|
|
|
+ unsigned long addr;
|
|
|
+ struct page *page;
|
|
|
+
|
|
|
+ for (addr = start; addr < end; addr += HPAGE_SIZE) {
|
|
|
+ pte_t *ptep = huge_pte_offset(vma->vm_mm, addr & HPAGE_MASK);
|
|
|
+ pte_t pte;
|
|
|
+
|
|
|
+ if (!ptep)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ pte = *ptep;
|
|
|
+ if (pte_none(pte))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ page = pte_page(pte);
|
|
|
+ if (!page)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ gather_stats(page, md, pte_dirty(*ptep));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
int show_numa_map(struct seq_file *m, void *v)
|
|
|
{
|
|
|
struct task_struct *task = m->private;
|
|
|
struct vm_area_struct *vma = v;
|
|
|
struct numa_maps *md;
|
|
|
+ struct file *file = vma->vm_file;
|
|
|
+ struct mm_struct *mm = vma->vm_mm;
|
|
|
int n;
|
|
|
char buffer[50];
|
|
|
|
|
|
- if (!vma->vm_mm)
|
|
|
+ if (!mm)
|
|
|
return 0;
|
|
|
|
|
|
md = kzalloc(sizeof(struct numa_maps), GFP_KERNEL);
|
|
|
if (!md)
|
|
|
return 0;
|
|
|
|
|
|
- if (!is_vm_hugetlb_page(vma))
|
|
|
+ mpol_to_str(buffer, sizeof(buffer),
|
|
|
+ get_vma_policy(task, vma, vma->vm_start));
|
|
|
+
|
|
|
+ seq_printf(m, "%08lx %s", vma->vm_start, buffer);
|
|
|
+
|
|
|
+ if (file) {
|
|
|
+ seq_printf(m, " file=");
|
|
|
+ seq_path(m, file->f_vfsmnt, file->f_dentry, "\n\t= ");
|
|
|
+ } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
|
|
|
+ seq_printf(m, " heap");
|
|
|
+ } else if (vma->vm_start <= mm->start_stack &&
|
|
|
+ vma->vm_end >= mm->start_stack) {
|
|
|
+ seq_printf(m, " stack");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (is_vm_hugetlb_page(vma)) {
|
|
|
+ check_huge_range(vma, vma->vm_start, vma->vm_end, md);
|
|
|
+ seq_printf(m, " huge");
|
|
|
+ } else {
|
|
|
check_pgd_range(vma, vma->vm_start, vma->vm_end,
|
|
|
- &node_online_map, MPOL_MF_STATS, md);
|
|
|
+ &node_online_map, MPOL_MF_STATS, md);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!md->pages)
|
|
|
+ goto out;
|
|
|
|
|
|
- if (md->pages) {
|
|
|
- mpol_to_str(buffer, sizeof(buffer),
|
|
|
- get_vma_policy(task, vma, vma->vm_start));
|
|
|
+ if (md->anon)
|
|
|
+ seq_printf(m," anon=%lu",md->anon);
|
|
|
|
|
|
- seq_printf(m, "%08lx %s pages=%lu mapped=%lu maxref=%lu",
|
|
|
- vma->vm_start, buffer, md->pages,
|
|
|
- md->mapped, md->mapcount_max);
|
|
|
+ if (md->dirty)
|
|
|
+ seq_printf(m," dirty=%lu",md->dirty);
|
|
|
|
|
|
- if (md->anon)
|
|
|
- seq_printf(m," anon=%lu",md->anon);
|
|
|
+ if (md->pages != md->anon && md->pages != md->dirty)
|
|
|
+ seq_printf(m, " mapped=%lu", md->pages);
|
|
|
|
|
|
- for_each_online_node(n)
|
|
|
- if (md->node[n])
|
|
|
- seq_printf(m, " N%d=%lu", n, md->node[n]);
|
|
|
+ if (md->mapcount_max > 1)
|
|
|
+ seq_printf(m, " mapmax=%lu", md->mapcount_max);
|
|
|
|
|
|
- seq_putc(m, '\n');
|
|
|
- }
|
|
|
+ if (md->swapcache)
|
|
|
+ seq_printf(m," swapcache=%lu", md->swapcache);
|
|
|
+
|
|
|
+ if (md->active < md->pages && !is_vm_hugetlb_page(vma))
|
|
|
+ seq_printf(m," active=%lu", md->active);
|
|
|
+
|
|
|
+ if (md->writeback)
|
|
|
+ seq_printf(m," writeback=%lu", md->writeback);
|
|
|
+
|
|
|
+ for_each_online_node(n)
|
|
|
+ if (md->node[n])
|
|
|
+ seq_printf(m, " N%d=%lu", n, md->node[n]);
|
|
|
+out:
|
|
|
+ seq_putc(m, '\n');
|
|
|
kfree(md);
|
|
|
|
|
|
if (m->count < m->size)
|