aboutsummaryrefslogtreecommitdiffstats
path: root/mm/mempolicy.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/mempolicy.c')
-rw-r--r--mm/mempolicy.c138
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
95static kmem_cache_t *policy_cache; 98static kmem_cache_t *policy_cache;
96static kmem_cache_t *sn_cache; 99static 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
234static 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. */
232static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd, 237static 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
1475static 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 */
1483static 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
1529struct 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
1537static 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
1557int 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