diff options
-rw-r--r-- | mm/memcontrol.c | 65 |
1 files changed, 47 insertions, 18 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 6edef95fecf4..bec451da7def 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -123,6 +123,13 @@ struct mem_cgroup_stat_cpu { | |||
123 | unsigned long targets[MEM_CGROUP_NTARGETS]; | 123 | unsigned long targets[MEM_CGROUP_NTARGETS]; |
124 | }; | 124 | }; |
125 | 125 | ||
126 | struct mem_cgroup_reclaim_iter { | ||
127 | /* css_id of the last scanned hierarchy member */ | ||
128 | int position; | ||
129 | /* scan generation, increased every round-trip */ | ||
130 | unsigned int generation; | ||
131 | }; | ||
132 | |||
126 | /* | 133 | /* |
127 | * per-zone information in memory controller. | 134 | * per-zone information in memory controller. |
128 | */ | 135 | */ |
@@ -133,6 +140,8 @@ struct mem_cgroup_per_zone { | |||
133 | struct list_head lists[NR_LRU_LISTS]; | 140 | struct list_head lists[NR_LRU_LISTS]; |
134 | unsigned long count[NR_LRU_LISTS]; | 141 | unsigned long count[NR_LRU_LISTS]; |
135 | 142 | ||
143 | struct mem_cgroup_reclaim_iter reclaim_iter[DEF_PRIORITY + 1]; | ||
144 | |||
136 | struct zone_reclaim_stat reclaim_stat; | 145 | struct zone_reclaim_stat reclaim_stat; |
137 | struct rb_node tree_node; /* RB tree node */ | 146 | struct rb_node tree_node; /* RB tree node */ |
138 | unsigned long long usage_in_excess;/* Set to the value by which */ | 147 | unsigned long long usage_in_excess;/* Set to the value by which */ |
@@ -233,11 +242,6 @@ struct mem_cgroup { | |||
233 | * per zone LRU lists. | 242 | * per zone LRU lists. |
234 | */ | 243 | */ |
235 | struct mem_cgroup_lru_info info; | 244 | struct mem_cgroup_lru_info info; |
236 | /* | ||
237 | * While reclaiming in a hierarchy, we cache the last child we | ||
238 | * reclaimed from. | ||
239 | */ | ||
240 | int last_scanned_child; | ||
241 | int last_scanned_node; | 245 | int last_scanned_node; |
242 | #if MAX_NUMNODES > 1 | 246 | #if MAX_NUMNODES > 1 |
243 | nodemask_t scan_nodes; | 247 | nodemask_t scan_nodes; |
@@ -853,9 +857,16 @@ struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm) | |||
853 | return memcg; | 857 | return memcg; |
854 | } | 858 | } |
855 | 859 | ||
856 | static struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root, | 860 | struct mem_cgroup_reclaim_cookie { |
857 | struct mem_cgroup *prev, | 861 | struct zone *zone; |
858 | bool reclaim) | 862 | int priority; |
863 | unsigned int generation; | ||
864 | }; | ||
865 | |||
866 | static struct mem_cgroup * | ||
867 | mem_cgroup_iter(struct mem_cgroup *root, | ||
868 | struct mem_cgroup *prev, | ||
869 | struct mem_cgroup_reclaim_cookie *reclaim) | ||
859 | { | 870 | { |
860 | struct mem_cgroup *memcg = NULL; | 871 | struct mem_cgroup *memcg = NULL; |
861 | int id = 0; | 872 | int id = 0; |
@@ -876,10 +887,20 @@ static struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root, | |||
876 | } | 887 | } |
877 | 888 | ||
878 | while (!memcg) { | 889 | while (!memcg) { |
890 | struct mem_cgroup_reclaim_iter *uninitialized_var(iter); | ||
879 | struct cgroup_subsys_state *css; | 891 | struct cgroup_subsys_state *css; |
880 | 892 | ||
881 | if (reclaim) | 893 | if (reclaim) { |
882 | id = root->last_scanned_child; | 894 | int nid = zone_to_nid(reclaim->zone); |
895 | int zid = zone_idx(reclaim->zone); | ||
896 | struct mem_cgroup_per_zone *mz; | ||
897 | |||
898 | mz = mem_cgroup_zoneinfo(root, nid, zid); | ||
899 | iter = &mz->reclaim_iter[reclaim->priority]; | ||
900 | if (prev && reclaim->generation != iter->generation) | ||
901 | return NULL; | ||
902 | id = iter->position; | ||
903 | } | ||
883 | 904 | ||
884 | rcu_read_lock(); | 905 | rcu_read_lock(); |
885 | css = css_get_next(&mem_cgroup_subsys, id + 1, &root->css, &id); | 906 | css = css_get_next(&mem_cgroup_subsys, id + 1, &root->css, &id); |
@@ -891,8 +912,13 @@ static struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root, | |||
891 | id = 0; | 912 | id = 0; |
892 | rcu_read_unlock(); | 913 | rcu_read_unlock(); |
893 | 914 | ||
894 | if (reclaim) | 915 | if (reclaim) { |
895 | root->last_scanned_child = id; | 916 | iter->position = id; |
917 | if (!css) | ||
918 | iter->generation++; | ||
919 | else if (!prev && memcg) | ||
920 | reclaim->generation = iter->generation; | ||
921 | } | ||
896 | 922 | ||
897 | if (prev && !css) | 923 | if (prev && !css) |
898 | return NULL; | 924 | return NULL; |
@@ -915,14 +941,14 @@ static void mem_cgroup_iter_break(struct mem_cgroup *root, | |||
915 | * be used for reference counting. | 941 | * be used for reference counting. |
916 | */ | 942 | */ |
917 | #define for_each_mem_cgroup_tree(iter, root) \ | 943 | #define for_each_mem_cgroup_tree(iter, root) \ |
918 | for (iter = mem_cgroup_iter(root, NULL, false); \ | 944 | for (iter = mem_cgroup_iter(root, NULL, NULL); \ |
919 | iter != NULL; \ | 945 | iter != NULL; \ |
920 | iter = mem_cgroup_iter(root, iter, false)) | 946 | iter = mem_cgroup_iter(root, iter, NULL)) |
921 | 947 | ||
922 | #define for_each_mem_cgroup(iter) \ | 948 | #define for_each_mem_cgroup(iter) \ |
923 | for (iter = mem_cgroup_iter(NULL, NULL, false); \ | 949 | for (iter = mem_cgroup_iter(NULL, NULL, NULL); \ |
924 | iter != NULL; \ | 950 | iter != NULL; \ |
925 | iter = mem_cgroup_iter(NULL, iter, false)) | 951 | iter = mem_cgroup_iter(NULL, iter, NULL)) |
926 | 952 | ||
927 | static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg) | 953 | static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg) |
928 | { | 954 | { |
@@ -1692,6 +1718,10 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_memcg, | |||
1692 | bool check_soft = reclaim_options & MEM_CGROUP_RECLAIM_SOFT; | 1718 | bool check_soft = reclaim_options & MEM_CGROUP_RECLAIM_SOFT; |
1693 | unsigned long excess; | 1719 | unsigned long excess; |
1694 | unsigned long nr_scanned; | 1720 | unsigned long nr_scanned; |
1721 | struct mem_cgroup_reclaim_cookie reclaim = { | ||
1722 | .zone = zone, | ||
1723 | .priority = 0, | ||
1724 | }; | ||
1695 | 1725 | ||
1696 | excess = res_counter_soft_limit_excess(&root_memcg->res) >> PAGE_SHIFT; | 1726 | excess = res_counter_soft_limit_excess(&root_memcg->res) >> PAGE_SHIFT; |
1697 | 1727 | ||
@@ -1700,7 +1730,7 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_memcg, | |||
1700 | noswap = true; | 1730 | noswap = true; |
1701 | 1731 | ||
1702 | while (1) { | 1732 | while (1) { |
1703 | victim = mem_cgroup_iter(root_memcg, victim, true); | 1733 | victim = mem_cgroup_iter(root_memcg, victim, &reclaim); |
1704 | if (!victim) { | 1734 | if (!victim) { |
1705 | loop++; | 1735 | loop++; |
1706 | /* | 1736 | /* |
@@ -5028,7 +5058,6 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) | |||
5028 | res_counter_init(&memcg->res, NULL); | 5058 | res_counter_init(&memcg->res, NULL); |
5029 | res_counter_init(&memcg->memsw, NULL); | 5059 | res_counter_init(&memcg->memsw, NULL); |
5030 | } | 5060 | } |
5031 | memcg->last_scanned_child = 0; | ||
5032 | memcg->last_scanned_node = MAX_NUMNODES; | 5061 | memcg->last_scanned_node = MAX_NUMNODES; |
5033 | INIT_LIST_HEAD(&memcg->oom_notify); | 5062 | INIT_LIST_HEAD(&memcg->oom_notify); |
5034 | 5063 | ||