diff options
Diffstat (limited to 'fs/proc/task_mmu.c')
-rw-r--r-- | fs/proc/task_mmu.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 28b4a0253a92..64e84cadfa3c 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -2,6 +2,8 @@ | |||
2 | #include <linux/hugetlb.h> | 2 | #include <linux/hugetlb.h> |
3 | #include <linux/mount.h> | 3 | #include <linux/mount.h> |
4 | #include <linux/seq_file.h> | 4 | #include <linux/seq_file.h> |
5 | #include <linux/pagemap.h> | ||
6 | #include <linux/mempolicy.h> | ||
5 | #include <asm/elf.h> | 7 | #include <asm/elf.h> |
6 | #include <asm/uaccess.h> | 8 | #include <asm/uaccess.h> |
7 | #include "internal.h" | 9 | #include "internal.h" |
@@ -233,3 +235,133 @@ struct seq_operations proc_pid_maps_op = { | |||
233 | .stop = m_stop, | 235 | .stop = m_stop, |
234 | .show = show_map | 236 | .show = show_map |
235 | }; | 237 | }; |
238 | |||
239 | #ifdef CONFIG_NUMA | ||
240 | |||
241 | struct numa_maps { | ||
242 | unsigned long pages; | ||
243 | unsigned long anon; | ||
244 | unsigned long mapped; | ||
245 | unsigned long mapcount_max; | ||
246 | unsigned long node[MAX_NUMNODES]; | ||
247 | }; | ||
248 | |||
249 | /* | ||
250 | * Calculate numa node maps for a vma | ||
251 | */ | ||
252 | static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma) | ||
253 | { | ||
254 | struct page *page; | ||
255 | unsigned long vaddr; | ||
256 | struct mm_struct *mm = vma->vm_mm; | ||
257 | int i; | ||
258 | struct numa_maps *md = kmalloc(sizeof(struct numa_maps), GFP_KERNEL); | ||
259 | |||
260 | if (!md) | ||
261 | return NULL; | ||
262 | md->pages = 0; | ||
263 | md->anon = 0; | ||
264 | md->mapped = 0; | ||
265 | md->mapcount_max = 0; | ||
266 | for_each_node(i) | ||
267 | md->node[i] =0; | ||
268 | |||
269 | spin_lock(&mm->page_table_lock); | ||
270 | for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) { | ||
271 | page = follow_page(mm, vaddr, 0); | ||
272 | if (page) { | ||
273 | int count = page_mapcount(page); | ||
274 | |||
275 | if (count) | ||
276 | md->mapped++; | ||
277 | if (count > md->mapcount_max) | ||
278 | md->mapcount_max = count; | ||
279 | md->pages++; | ||
280 | if (PageAnon(page)) | ||
281 | md->anon++; | ||
282 | md->node[page_to_nid(page)]++; | ||
283 | } | ||
284 | } | ||
285 | spin_unlock(&mm->page_table_lock); | ||
286 | return md; | ||
287 | } | ||
288 | |||
289 | static int show_numa_map(struct seq_file *m, void *v) | ||
290 | { | ||
291 | struct task_struct *task = m->private; | ||
292 | struct vm_area_struct *vma = v; | ||
293 | struct mempolicy *pol; | ||
294 | struct numa_maps *md; | ||
295 | struct zone **z; | ||
296 | int n; | ||
297 | int first; | ||
298 | |||
299 | if (!vma->vm_mm) | ||
300 | return 0; | ||
301 | |||
302 | md = get_numa_maps(vma); | ||
303 | if (!md) | ||
304 | return 0; | ||
305 | |||
306 | seq_printf(m, "%08lx", vma->vm_start); | ||
307 | pol = get_vma_policy(task, vma, vma->vm_start); | ||
308 | /* Print policy */ | ||
309 | switch (pol->policy) { | ||
310 | case MPOL_PREFERRED: | ||
311 | seq_printf(m, " prefer=%d", pol->v.preferred_node); | ||
312 | break; | ||
313 | case MPOL_BIND: | ||
314 | seq_printf(m, " bind={"); | ||
315 | first = 1; | ||
316 | for (z = pol->v.zonelist->zones; *z; z++) { | ||
317 | |||
318 | if (!first) | ||
319 | seq_putc(m, ','); | ||
320 | else | ||
321 | first = 0; | ||
322 | seq_printf(m, "%d/%s", (*z)->zone_pgdat->node_id, | ||
323 | (*z)->name); | ||
324 | } | ||
325 | seq_putc(m, '}'); | ||
326 | break; | ||
327 | case MPOL_INTERLEAVE: | ||
328 | seq_printf(m, " interleave={"); | ||
329 | first = 1; | ||
330 | for_each_node(n) { | ||
331 | if (test_bit(n, pol->v.nodes)) { | ||
332 | if (!first) | ||
333 | seq_putc(m,','); | ||
334 | else | ||
335 | first = 0; | ||
336 | seq_printf(m, "%d",n); | ||
337 | } | ||
338 | } | ||
339 | seq_putc(m, '}'); | ||
340 | break; | ||
341 | default: | ||
342 | seq_printf(m," default"); | ||
343 | break; | ||
344 | } | ||
345 | seq_printf(m, " MaxRef=%lu Pages=%lu Mapped=%lu", | ||
346 | md->mapcount_max, md->pages, md->mapped); | ||
347 | if (md->anon) | ||
348 | seq_printf(m," Anon=%lu",md->anon); | ||
349 | |||
350 | for_each_online_node(n) { | ||
351 | if (md->node[n]) | ||
352 | seq_printf(m, " N%d=%lu", n, md->node[n]); | ||
353 | } | ||
354 | seq_putc(m, '\n'); | ||
355 | kfree(md); | ||
356 | if (m->count < m->size) /* vma is copied successfully */ | ||
357 | m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | struct seq_operations proc_pid_numa_maps_op = { | ||
362 | .start = m_start, | ||
363 | .next = m_next, | ||
364 | .stop = m_stop, | ||
365 | .show = show_numa_map | ||
366 | }; | ||
367 | #endif | ||