diff options
| -rw-r--r-- | mm/memcontrol.c | 107 |
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 | ||
| 580 | static 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 | |||
| 589 | static void mem_cgroup_swap_statistics(struct mem_cgroup *mem, | 580 | static 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 | ||
| 1133 | static unsigned long mem_cgroup_node_nr_file_lru_pages(struct mem_cgroup *memcg, | 1123 | static 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 | ||
| 1134 | static 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 | ||
| 1144 | static unsigned long mem_cgroup_nr_file_lru_pages(struct mem_cgroup *memcg) | 1145 | static 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 | ||
| 1155 | static 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 | |||
| 1166 | static unsigned long mem_cgroup_nr_anon_lru_pages(struct mem_cgroup *memcg) | 1156 | static 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 | */ | ||
| 1562 | static 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 | */ | ||
| 1641 | bool 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 |
| 1631 | int mem_cgroup_select_victim_node(struct mem_cgroup *mem) | 1671 | int mem_cgroup_select_victim_node(struct mem_cgroup *mem) |
| 1632 | { | 1672 | { |
| 1633 | return 0; | 1673 | return 0; |
| 1634 | } | 1674 | } |
| 1675 | |||
| 1676 | bool 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; |
