diff options
Diffstat (limited to 'mm/mempolicy.c')
-rw-r--r-- | mm/mempolicy.c | 138 |
1 files changed, 137 insertions, 1 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 270e9a39ec15..44b9d69900bc 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -84,6 +84,8 @@ | |||
84 | #include <linux/compat.h> | 84 | #include <linux/compat.h> |
85 | #include <linux/mempolicy.h> | 85 | #include <linux/mempolicy.h> |
86 | #include <linux/swap.h> | 86 | #include <linux/swap.h> |
87 | #include <linux/seq_file.h> | ||
88 | #include <linux/proc_fs.h> | ||
87 | 89 | ||
88 | #include <asm/tlbflush.h> | 90 | #include <asm/tlbflush.h> |
89 | #include <asm/uaccess.h> | 91 | #include <asm/uaccess.h> |
@@ -91,6 +93,7 @@ | |||
91 | /* Internal flags */ | 93 | /* Internal flags */ |
92 | #define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL << 0) /* Skip checks for continuous vmas */ | 94 | #define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL << 0) /* Skip checks for continuous vmas */ |
93 | #define MPOL_MF_INVERT (MPOL_MF_INTERNAL << 1) /* Invert check for nodemask */ | 95 | #define MPOL_MF_INVERT (MPOL_MF_INTERNAL << 1) /* Invert check for nodemask */ |
96 | #define MPOL_MF_STATS (MPOL_MF_INTERNAL << 2) /* Gather statistics */ | ||
94 | 97 | ||
95 | static kmem_cache_t *policy_cache; | 98 | static kmem_cache_t *policy_cache; |
96 | static kmem_cache_t *sn_cache; | 99 | static kmem_cache_t *sn_cache; |
@@ -228,6 +231,8 @@ static void migrate_page_add(struct vm_area_struct *vma, | |||
228 | } | 231 | } |
229 | } | 232 | } |
230 | 233 | ||
234 | static void gather_stats(struct page *, void *); | ||
235 | |||
231 | /* Scan through pages checking if pages follow certain conditions. */ | 236 | /* Scan through pages checking if pages follow certain conditions. */ |
232 | static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, | 237 | static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, |
233 | unsigned long addr, unsigned long end, | 238 | unsigned long addr, unsigned long end, |
@@ -252,7 +257,9 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, | |||
252 | if (node_isset(nid, *nodes) == !!(flags & MPOL_MF_INVERT)) | 257 | if (node_isset(nid, *nodes) == !!(flags & MPOL_MF_INVERT)) |
253 | continue; | 258 | continue; |
254 | 259 | ||
255 | if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) | 260 | if (flags & MPOL_MF_STATS) |
261 | gather_stats(page, private); | ||
262 | else if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) | ||
256 | migrate_page_add(vma, page, private, flags); | 263 | migrate_page_add(vma, page, private, flags); |
257 | else | 264 | else |
258 | break; | 265 | break; |
@@ -1460,3 +1467,132 @@ void numa_policy_rebind(const nodemask_t *old, const nodemask_t *new) | |||
1460 | { | 1467 | { |
1461 | rebind_policy(current->mempolicy, old, new); | 1468 | rebind_policy(current->mempolicy, old, new); |
1462 | } | 1469 | } |
1470 | |||
1471 | /* | ||
1472 | * Display pages allocated per node and memory policy via /proc. | ||
1473 | */ | ||
1474 | |||
1475 | static const char *policy_types[] = { "default", "prefer", "bind", | ||
1476 | "interleave" }; | ||
1477 | |||
1478 | /* | ||
1479 | * Convert a mempolicy into a string. | ||
1480 | * Returns the number of characters in buffer (if positive) | ||
1481 | * or an error (negative) | ||
1482 | */ | ||
1483 | static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) | ||
1484 | { | ||
1485 | char *p = buffer; | ||
1486 | int l; | ||
1487 | nodemask_t nodes; | ||
1488 | int mode = pol ? pol->policy : MPOL_DEFAULT; | ||
1489 | |||
1490 | switch (mode) { | ||
1491 | case MPOL_DEFAULT: | ||
1492 | nodes_clear(nodes); | ||
1493 | break; | ||
1494 | |||
1495 | case MPOL_PREFERRED: | ||
1496 | nodes_clear(nodes); | ||
1497 | node_set(pol->v.preferred_node, nodes); | ||
1498 | break; | ||
1499 | |||
1500 | case MPOL_BIND: | ||
1501 | get_zonemask(pol, &nodes); | ||
1502 | break; | ||
1503 | |||
1504 | case MPOL_INTERLEAVE: | ||
1505 | nodes = pol->v.nodes; | ||
1506 | break; | ||
1507 | |||
1508 | default: | ||
1509 | BUG(); | ||
1510 | return -EFAULT; | ||
1511 | } | ||
1512 | |||
1513 | l = strlen(policy_types[mode]); | ||
1514 | if (buffer + maxlen < p + l + 1) | ||
1515 | return -ENOSPC; | ||
1516 | |||
1517 | strcpy(p, policy_types[mode]); | ||
1518 | p += l; | ||
1519 | |||
1520 | if (!nodes_empty(nodes)) { | ||
1521 | if (buffer + maxlen < p + 2) | ||
1522 | return -ENOSPC; | ||
1523 | *p++ = '='; | ||
1524 | p += nodelist_scnprintf(p, buffer + maxlen - p, nodes); | ||
1525 | } | ||
1526 | return p - buffer; | ||
1527 | } | ||
1528 | |||
1529 | struct numa_maps { | ||
1530 | unsigned long pages; | ||
1531 | unsigned long anon; | ||
1532 | unsigned long mapped; | ||
1533 | unsigned long mapcount_max; | ||
1534 | unsigned long node[MAX_NUMNODES]; | ||
1535 | }; | ||
1536 | |||
1537 | static void gather_stats(struct page *page, void *private) | ||
1538 | { | ||
1539 | struct numa_maps *md = private; | ||
1540 | int count = page_mapcount(page); | ||
1541 | |||
1542 | if (count) | ||
1543 | md->mapped++; | ||
1544 | |||
1545 | if (count > md->mapcount_max) | ||
1546 | md->mapcount_max = count; | ||
1547 | |||
1548 | md->pages++; | ||
1549 | |||
1550 | if (PageAnon(page)) | ||
1551 | md->anon++; | ||
1552 | |||
1553 | md->node[page_to_nid(page)]++; | ||
1554 | cond_resched(); | ||
1555 | } | ||
1556 | |||
1557 | int show_numa_map(struct seq_file *m, void *v) | ||
1558 | { | ||
1559 | struct task_struct *task = m->private; | ||
1560 | struct vm_area_struct *vma = v; | ||
1561 | struct numa_maps *md; | ||
1562 | int n; | ||
1563 | char buffer[50]; | ||
1564 | |||
1565 | if (!vma->vm_mm) | ||
1566 | return 0; | ||
1567 | |||
1568 | md = kzalloc(sizeof(struct numa_maps), GFP_KERNEL); | ||
1569 | if (!md) | ||
1570 | return 0; | ||
1571 | |||
1572 | check_pgd_range(vma, vma->vm_start, vma->vm_end, | ||
1573 | &node_online_map, MPOL_MF_STATS, md); | ||
1574 | |||
1575 | if (md->pages) { | ||
1576 | mpol_to_str(buffer, sizeof(buffer), | ||
1577 | get_vma_policy(task, vma, vma->vm_start)); | ||
1578 | |||
1579 | seq_printf(m, "%08lx %s pages=%lu mapped=%lu maxref=%lu", | ||
1580 | vma->vm_start, buffer, md->pages, | ||
1581 | md->mapped, md->mapcount_max); | ||
1582 | |||
1583 | if (md->anon) | ||
1584 | seq_printf(m," anon=%lu",md->anon); | ||
1585 | |||
1586 | for_each_online_node(n) | ||
1587 | if (md->node[n]) | ||
1588 | seq_printf(m, " N%d=%lu", n, md->node[n]); | ||
1589 | |||
1590 | seq_putc(m, '\n'); | ||
1591 | } | ||
1592 | kfree(md); | ||
1593 | |||
1594 | if (m->count < m->size) | ||
1595 | m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; | ||
1596 | return 0; | ||
1597 | } | ||
1598 | |||