aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorMichal Hocko <mhocko@suse.cz>2013-09-12 18:13:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-12 18:38:01 -0400
commite975de998b9612aa97e3165f8827c09e0d36ce77 (patch)
treefa014ce767613fb7398a7330ca9468466a441913 /mm
parent1be171d60bddcce2602c5d009029274d67736fd7 (diff)
memcg, vmscan: do not fall into reclaim-all pass too quickly
shrink_zone starts with soft reclaim pass first and then falls back to regular reclaim if nothing has been scanned. This behavior is natural but there is a catch. Memcg iterators, when used with the reclaim cookie, are designed to help to prevent from over reclaim by interleaving reclaimers (per node-zone-priority) so the tree walk might miss many (even all) nodes in the hierarchy e.g. when there are direct reclaimers racing with each other or with kswapd in the global case or multiple allocators reaching the limit for the target reclaim case. To make it even more complicated, targeted reclaim doesn't do the whole tree walk because it stops reclaiming once it reclaims sufficient pages. As a result groups over the limit might be missed, thus nothing is scanned, and reclaim would fall back to the reclaim all mode. This patch checks for the incomplete tree walk in shrink_zone. If no group has been visited and the hierarchy is soft reclaimable then we must have missed some groups, in which case the __shrink_zone is called again. This doesn't guarantee there will be some progress of course because the current reclaimer might be still racing with others but it would at least give a chance to start the walk without a big risk of reclaim latencies. Signed-off-by: Michal Hocko <mhocko@suse.cz> Cc: Balbir Singh <bsingharora@gmail.com> Cc: Glauber Costa <glommer@openvz.org> Cc: Greg Thelen <gthelen@google.com> Cc: Hugh Dickins <hughd@google.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Michel Lespinasse <walken@google.com> Cc: Tejun Heo <tj@kernel.org> Cc: Ying Han <yinghan@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/vmscan.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 04dca89c4f34..fa91c20fe4b7 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2142,10 +2142,11 @@ static inline bool should_continue_reclaim(struct zone *zone,
2142 } 2142 }
2143} 2143}
2144 2144
2145static void 2145static int
2146__shrink_zone(struct zone *zone, struct scan_control *sc, bool soft_reclaim) 2146__shrink_zone(struct zone *zone, struct scan_control *sc, bool soft_reclaim)
2147{ 2147{
2148 unsigned long nr_reclaimed, nr_scanned; 2148 unsigned long nr_reclaimed, nr_scanned;
2149 int groups_scanned = 0;
2149 2150
2150 do { 2151 do {
2151 struct mem_cgroup *root = sc->target_mem_cgroup; 2152 struct mem_cgroup *root = sc->target_mem_cgroup;
@@ -2163,6 +2164,7 @@ __shrink_zone(struct zone *zone, struct scan_control *sc, bool soft_reclaim)
2163 while ((memcg = mem_cgroup_iter_cond(root, memcg, &reclaim, filter))) { 2164 while ((memcg = mem_cgroup_iter_cond(root, memcg, &reclaim, filter))) {
2164 struct lruvec *lruvec; 2165 struct lruvec *lruvec;
2165 2166
2167 groups_scanned++;
2166 lruvec = mem_cgroup_zone_lruvec(zone, memcg); 2168 lruvec = mem_cgroup_zone_lruvec(zone, memcg);
2167 2169
2168 shrink_lruvec(lruvec, sc); 2170 shrink_lruvec(lruvec, sc);
@@ -2190,6 +2192,8 @@ __shrink_zone(struct zone *zone, struct scan_control *sc, bool soft_reclaim)
2190 2192
2191 } while (should_continue_reclaim(zone, sc->nr_reclaimed - nr_reclaimed, 2193 } while (should_continue_reclaim(zone, sc->nr_reclaimed - nr_reclaimed,
2192 sc->nr_scanned - nr_scanned, sc)); 2194 sc->nr_scanned - nr_scanned, sc));
2195
2196 return groups_scanned;
2193} 2197}
2194 2198
2195 2199
@@ -2197,8 +2201,19 @@ static void shrink_zone(struct zone *zone, struct scan_control *sc)
2197{ 2201{
2198 bool do_soft_reclaim = mem_cgroup_should_soft_reclaim(sc); 2202 bool do_soft_reclaim = mem_cgroup_should_soft_reclaim(sc);
2199 unsigned long nr_scanned = sc->nr_scanned; 2203 unsigned long nr_scanned = sc->nr_scanned;
2204 int scanned_groups;
2200 2205
2201 __shrink_zone(zone, sc, do_soft_reclaim); 2206 scanned_groups = __shrink_zone(zone, sc, do_soft_reclaim);
2207 /*
2208 * memcg iterator might race with other reclaimer or start from
2209 * a incomplete tree walk so the tree walk in __shrink_zone
2210 * might have missed groups that are above the soft limit. Try
2211 * another loop to catch up with others. Do it just once to
2212 * prevent from reclaim latencies when other reclaimers always
2213 * preempt this one.
2214 */
2215 if (do_soft_reclaim && !scanned_groups)
2216 __shrink_zone(zone, sc, do_soft_reclaim);
2202 2217
2203 /* 2218 /*
2204 * No group is over the soft limit or those that are do not have 2219 * No group is over the soft limit or those that are do not have