#ifdef AS_MODULE #include #endif #include #include #include #include #include #include #include #include /* Offsets into the range list array */ #define COW_PAGE NR_CPUS #define NOT_PRESENT (NR_CPUS + 1) static inline int page2node(struct page *page) { struct zone *zone = page_zone(page); return zone->zone_pgdat->node_id; } int pagemap_show(struct seq_file *s, void *v) { struct task_struct *task = s->private; struct vm_area_struct *vma; pgd_t *pgd; pmd_t *pmd; pte_t *ptep, pte; unsigned long pga; int n, i, vmac; long node_pgc[NOT_PRESENT + 1]; down_read(&task->active_mm->mmap_sem); vmac = 0; /* For each VMA, translate each page it spans to a node number */ for (vma = task->active_mm->mmap; vma; vma = vma->vm_next) { seq_printf(s, "VMA %d start %lx end %lx\n", vmac, vma->vm_start, vma->vm_end); for (pga = PAGE_ALIGN(vma->vm_start); pga < vma->vm_end; pga += PAGE_SIZE) { n = NOT_PRESENT; pgd = pgd_offset(task->active_mm, pga); if (pgd_none(*pgd) || pgd_bad(*pgd)) goto out; pmd = pmd_offset(pgd, pga); if (pmd_none(*pmd) || pmd_bad(*pmd)) goto out; ptep = pte_offset_map(pmd, pga); if (!ptep) goto out; pte = *ptep; pte_unmap(ptep); n = page2node(pte_page(pte)); /* COW-page? Check if mapped to the zero page */ if (!pte_write(pte) && (vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_WRITE)) { seq_printf(s, "%08lx-%08lx node %d COW\n", pga, pga + PAGE_SIZE - 1, n); } else { if (n == NOT_PRESENT) seq_printf(s, "%08lx-%08lx node %d not present\n", pga, pga + PAGE_SIZE - 1, n); else seq_printf(s, "%08lx-%08lx node %d \n", pga, pga + PAGE_SIZE - 1, n); } out: } vmac++; } up_read(&task->active_mm->mmap_sem); return 0; }