aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>2011-07-08 18:39:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-09 00:14:43 -0400
commit4d0c066d29f030d47d19678f8008933e67dd3b72 (patch)
tree96f46e845b7a937b2e41b735061f696d2cb03293
parent0b43c3aab0137595335b08b340a3f3e5af9818a6 (diff)
memcg: fix reclaimable lru check in memcg
Now, in mem_cgroup_hierarchical_reclaim(), mem_cgroup_local_usage() is used for checking whether the memcg contains reclaimable pages or not. If no pages in it, the routine skips it. But, mem_cgroup_local_usage() contains Unevictable pages and cannot handle "noswap" condition correctly. This doesn't work on a swapless system. This patch adds test_mem_cgroup_reclaimable() and replaces mem_cgroup_local_usage(). test_mem_cgroup_reclaimable() see LRU counter and returns correct answer to the caller. And this new function has "noswap" argument and can see only FILE LRU if necessary. [akpm@linux-foundation.org: coding-style fixes] [akpm@linux-foundation.org: fix kerneldoc layout] Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Michal Hocko <mhocko@suse.cz> Cc: Ying Han <yinghan@google.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/memcontrol.c107
1 files changed, 76 insertions, 31 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index ddffc74cdebe..a7a5cb1bf2c7 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -577,15 +577,6 @@ static long mem_cgroup_read_stat(struct mem_cgroup *mem,
577 return val; 577 return val;
578} 578}
579 579
580static long mem_cgroup_local_usage(struct mem_cgroup *mem)
581{
582 long ret;
583
584 ret = mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_RSS);
585 ret += mem_cgroup_read_stat(mem, MEM_CGROUP_STAT_CACHE);
586 return ret;
587}
588
589static void mem_cgroup_swap_statistics(struct mem_cgroup *mem, 580static void mem_cgroup_swap_statistics(struct mem_cgroup *mem,
590 bool charge) 581 bool charge)
591{ 582{
@@ -1129,7 +1120,6 @@ unsigned long mem_cgroup_zone_nr_lru_pages(struct mem_cgroup *memcg,
1129 return MEM_CGROUP_ZSTAT(mz, lru); 1120 return MEM_CGROUP_ZSTAT(mz, lru);
1130} 1121}
1131 1122
1132#ifdef CONFIG_NUMA
1133static unsigned long mem_cgroup_node_nr_file_lru_pages(struct mem_cgroup *memcg, 1123static unsigned long mem_cgroup_node_nr_file_lru_pages(struct mem_cgroup *memcg,
1134 int nid) 1124 int nid)
1135{ 1125{
@@ -1141,6 +1131,17 @@ static unsigned long mem_cgroup_node_nr_file_lru_pages(struct mem_cgroup *memcg,
1141 return ret; 1131 return ret;
1142} 1132}
1143 1133
1134static unsigned long mem_cgroup_node_nr_anon_lru_pages(struct mem_cgroup *memcg,
1135 int nid)
1136{
1137 unsigned long ret;
1138
1139 ret = mem_cgroup_get_zonestat_node(memcg, nid, LRU_INACTIVE_ANON) +
1140 mem_cgroup_get_zonestat_node(memcg, nid, LRU_ACTIVE_ANON);
1141 return ret;
1142}
1143
1144#if MAX_NUMNODES > 1
1144static unsigned long mem_cgroup_nr_file_lru_pages(struct mem_cgroup *memcg) 1145static unsigned long mem_cgroup_nr_file_lru_pages(struct mem_cgroup *memcg)
1145{ 1146{
1146 u64 total = 0; 1147 u64 total = 0;
@@ -1152,17 +1153,6 @@ static unsigned long mem_cgroup_nr_file_lru_pages(struct mem_cgroup *memcg)
1152 return total; 1153 return total;
1153} 1154}
1154 1155
1155static unsigned long mem_cgroup_node_nr_anon_lru_pages(struct mem_cgroup *memcg,
1156 int nid)
1157{
1158 unsigned long ret;
1159
1160 ret = mem_cgroup_get_zonestat_node(memcg, nid, LRU_INACTIVE_ANON) +
1161 mem_cgroup_get_zonestat_node(memcg, nid, LRU_ACTIVE_ANON);
1162
1163 return ret;
1164}
1165
1166static unsigned long mem_cgroup_nr_anon_lru_pages(struct mem_cgroup *memcg) 1156static unsigned long mem_cgroup_nr_anon_lru_pages(struct mem_cgroup *memcg)
1167{ 1157{
1168 u64 total = 0; 1158 u64 total = 0;
@@ -1559,6 +1549,28 @@ mem_cgroup_select_victim(struct mem_cgroup *root_mem)
1559 return ret; 1549 return ret;
1560} 1550}
1561 1551
1552/**
1553 * test_mem_cgroup_node_reclaimable
1554 * @mem: the target memcg
1555 * @nid: the node ID to be checked.
1556 * @noswap : specify true here if the user wants flle only information.
1557 *
1558 * This function returns whether the specified memcg contains any
1559 * reclaimable pages on a node. Returns true if there are any reclaimable
1560 * pages in the node.
1561 */
1562static bool test_mem_cgroup_node_reclaimable(struct mem_cgroup *mem,
1563 int nid, bool noswap)
1564{
1565 if (mem_cgroup_node_nr_file_lru_pages(mem, nid))
1566 return true;
1567 if (noswap || !total_swap_pages)
1568 return false;
1569 if (mem_cgroup_node_nr_anon_lru_pages(mem, nid))
1570 return true;
1571 return false;
1572
1573}
1562#if MAX_NUMNODES > 1 1574#if MAX_NUMNODES > 1
1563 1575
1564/* 1576/*
@@ -1580,15 +1592,8 @@ static void mem_cgroup_may_update_nodemask(struct mem_cgroup *mem)
1580 1592
1581 for_each_node_mask(nid, node_states[N_HIGH_MEMORY]) { 1593 for_each_node_mask(nid, node_states[N_HIGH_MEMORY]) {
1582 1594
1583 if (mem_cgroup_get_zonestat_node(mem, nid, LRU_INACTIVE_FILE) || 1595 if (!test_mem_cgroup_node_reclaimable(mem, nid, false))
1584 mem_cgroup_get_zonestat_node(mem, nid, LRU_ACTIVE_FILE)) 1596 node_clear(nid, mem->scan_nodes);
1585 continue;
1586
1587 if (total_swap_pages &&
1588 (mem_cgroup_get_zonestat_node(mem, nid, LRU_INACTIVE_ANON) ||
1589 mem_cgroup_get_zonestat_node(mem, nid, LRU_ACTIVE_ANON)))
1590 continue;
1591 node_clear(nid, mem->scan_nodes);
1592 } 1597 }
1593} 1598}
1594 1599
@@ -1627,11 +1632,51 @@ int mem_cgroup_select_victim_node(struct mem_cgroup *mem)
1627 return node; 1632 return node;
1628} 1633}
1629 1634
1635/*
1636 * Check all nodes whether it contains reclaimable pages or not.
1637 * For quick scan, we make use of scan_nodes. This will allow us to skip
1638 * unused nodes. But scan_nodes is lazily updated and may not cotain
1639 * enough new information. We need to do double check.
1640 */
1641bool mem_cgroup_reclaimable(struct mem_cgroup *mem, bool noswap)
1642{
1643 int nid;
1644
1645 /*
1646 * quick check...making use of scan_node.
1647 * We can skip unused nodes.
1648 */
1649 if (!nodes_empty(mem->scan_nodes)) {
1650 for (nid = first_node(mem->scan_nodes);
1651 nid < MAX_NUMNODES;
1652 nid = next_node(nid, mem->scan_nodes)) {
1653
1654 if (test_mem_cgroup_node_reclaimable(mem, nid, noswap))
1655 return true;
1656 }
1657 }
1658 /*
1659 * Check rest of nodes.
1660 */
1661 for_each_node_state(nid, N_HIGH_MEMORY) {
1662 if (node_isset(nid, mem->scan_nodes))
1663 continue;
1664 if (test_mem_cgroup_node_reclaimable(mem, nid, noswap))
1665 return true;
1666 }
1667 return false;
1668}
1669
1630#else 1670#else
1631int mem_cgroup_select_victim_node(struct mem_cgroup *mem) 1671int mem_cgroup_select_victim_node(struct mem_cgroup *mem)
1632{ 1672{
1633 return 0; 1673 return 0;
1634} 1674}
1675
1676bool mem_cgroup_reclaimable(struct mem_cgroup *mem, bool noswap)
1677{
1678 return test_mem_cgroup_node_reclaimable(mem, 0, noswap);
1679}
1635#endif 1680#endif
1636 1681
1637/* 1682/*
@@ -1702,7 +1747,7 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
1702 } 1747 }
1703 } 1748 }
1704 } 1749 }
1705 if (!mem_cgroup_local_usage(victim)) { 1750 if (!mem_cgroup_reclaimable(victim, noswap)) {
1706 /* this cgroup's local usage == 0 */ 1751 /* this cgroup's local usage == 0 */
1707 css_put(&victim->css); 1752 css_put(&victim->css);
1708 continue; 1753 continue;