Commit 694fbc0f authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

revert "memcg: enhance memcg iterator to support predicates"

Revert commit de57780d ("memcg: enhance memcg iterator to support
predicates")

I merged this prematurely - Michal and Johannes still disagree about the
overall design direction and the future remains unclear.

Cc: Michal Hocko <mhocko@suse.cz>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 30361e51
...@@ -53,23 +53,6 @@ struct mem_cgroup_reclaim_cookie { ...@@ -53,23 +53,6 @@ struct mem_cgroup_reclaim_cookie {
unsigned int generation; unsigned int generation;
}; };
enum mem_cgroup_filter_t {
VISIT, /* visit current node */
SKIP, /* skip the current node and continue traversal */
SKIP_TREE, /* skip the whole subtree and continue traversal */
};
/*
* mem_cgroup_filter_t predicate might instruct mem_cgroup_iter_cond how to
* iterate through the hierarchy tree. Each tree element is checked by the
* predicate before it is returned by the iterator. If a filter returns
* SKIP or SKIP_TREE then the iterator code continues traversal (with the
* next node down the hierarchy or the next node that doesn't belong under the
* memcg's subtree).
*/
typedef enum mem_cgroup_filter_t
(*mem_cgroup_iter_filter)(struct mem_cgroup *memcg, struct mem_cgroup *root);
#ifdef CONFIG_MEMCG #ifdef CONFIG_MEMCG
/* /*
* All "charge" functions with gfp_mask should use GFP_KERNEL or * All "charge" functions with gfp_mask should use GFP_KERNEL or
...@@ -137,18 +120,9 @@ mem_cgroup_prepare_migration(struct page *page, struct page *newpage, ...@@ -137,18 +120,9 @@ mem_cgroup_prepare_migration(struct page *page, struct page *newpage,
extern void mem_cgroup_end_migration(struct mem_cgroup *memcg, extern void mem_cgroup_end_migration(struct mem_cgroup *memcg,
struct page *oldpage, struct page *newpage, bool migration_ok); struct page *oldpage, struct page *newpage, bool migration_ok);
struct mem_cgroup *mem_cgroup_iter_cond(struct mem_cgroup *root, struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *,
struct mem_cgroup *prev, struct mem_cgroup *,
struct mem_cgroup_reclaim_cookie *reclaim, struct mem_cgroup_reclaim_cookie *);
mem_cgroup_iter_filter cond);
static inline struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
struct mem_cgroup *prev,
struct mem_cgroup_reclaim_cookie *reclaim)
{
return mem_cgroup_iter_cond(root, prev, reclaim, NULL);
}
void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *); void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *);
/* /*
...@@ -260,8 +234,7 @@ static inline void mem_cgroup_dec_page_stat(struct page *page, ...@@ -260,8 +234,7 @@ static inline void mem_cgroup_dec_page_stat(struct page *page,
mem_cgroup_update_page_stat(page, idx, -1); mem_cgroup_update_page_stat(page, idx, -1);
} }
enum mem_cgroup_filter_t bool mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
struct mem_cgroup *root); struct mem_cgroup *root);
void __mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx); void __mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx);
...@@ -376,15 +349,6 @@ static inline void mem_cgroup_end_migration(struct mem_cgroup *memcg, ...@@ -376,15 +349,6 @@ static inline void mem_cgroup_end_migration(struct mem_cgroup *memcg,
struct page *oldpage, struct page *newpage, bool migration_ok) struct page *oldpage, struct page *newpage, bool migration_ok)
{ {
} }
static inline struct mem_cgroup *
mem_cgroup_iter_cond(struct mem_cgroup *root,
struct mem_cgroup *prev,
struct mem_cgroup_reclaim_cookie *reclaim,
mem_cgroup_iter_filter cond)
{
/* first call must return non-NULL, second return NULL */
return (struct mem_cgroup *)(unsigned long)!prev;
}
static inline struct mem_cgroup * static inline struct mem_cgroup *
mem_cgroup_iter(struct mem_cgroup *root, mem_cgroup_iter(struct mem_cgroup *root,
...@@ -471,11 +435,10 @@ static inline void mem_cgroup_dec_page_stat(struct page *page, ...@@ -471,11 +435,10 @@ static inline void mem_cgroup_dec_page_stat(struct page *page,
} }
static inline static inline
enum mem_cgroup_filter_t bool mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
struct mem_cgroup *root) struct mem_cgroup *root)
{ {
return VISIT; return false;
} }
static inline void mem_cgroup_split_huge_fixup(struct page *head) static inline void mem_cgroup_split_huge_fixup(struct page *head)
......
...@@ -862,15 +862,6 @@ struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm) ...@@ -862,15 +862,6 @@ struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
return memcg; return memcg;
} }
static enum mem_cgroup_filter_t
mem_cgroup_filter(struct mem_cgroup *memcg, struct mem_cgroup *root,
mem_cgroup_iter_filter cond)
{
if (!cond)
return VISIT;
return cond(memcg, root);
}
/* /*
* Returns a next (in a pre-order walk) alive memcg (with elevated css * Returns a next (in a pre-order walk) alive memcg (with elevated css
* ref. count) or NULL if the whole root's subtree has been visited. * ref. count) or NULL if the whole root's subtree has been visited.
...@@ -878,7 +869,7 @@ mem_cgroup_filter(struct mem_cgroup *memcg, struct mem_cgroup *root, ...@@ -878,7 +869,7 @@ mem_cgroup_filter(struct mem_cgroup *memcg, struct mem_cgroup *root,
* helper function to be used by mem_cgroup_iter * helper function to be used by mem_cgroup_iter
*/ */
static struct mem_cgroup *__mem_cgroup_iter_next(struct mem_cgroup *root, static struct mem_cgroup *__mem_cgroup_iter_next(struct mem_cgroup *root,
struct mem_cgroup *last_visited, mem_cgroup_iter_filter cond) struct mem_cgroup *last_visited)
{ {
struct cgroup_subsys_state *prev_css, *next_css; struct cgroup_subsys_state *prev_css, *next_css;
...@@ -896,31 +887,11 @@ static struct mem_cgroup *__mem_cgroup_iter_next(struct mem_cgroup *root, ...@@ -896,31 +887,11 @@ static struct mem_cgroup *__mem_cgroup_iter_next(struct mem_cgroup *root,
if (next_css) { if (next_css) {
struct mem_cgroup *mem = mem_cgroup_from_css(next_css); struct mem_cgroup *mem = mem_cgroup_from_css(next_css);
switch (mem_cgroup_filter(mem, root, cond)) { if (css_tryget(&mem->css))
case SKIP: return mem;
else {
prev_css = next_css; prev_css = next_css;
goto skip_node; goto skip_node;
case SKIP_TREE:
if (mem == root)
return NULL;
/*
* css_rightmost_descendant is not an optimal way to
* skip through a subtree (especially for imbalanced
* trees leaning to right) but that's what we have right
* now. More effective solution would be traversing
* right-up for first non-NULL without calling
* css_next_descendant_pre afterwards.
*/
prev_css = css_rightmost_descendant(next_css);
goto skip_node;
case VISIT:
if (css_tryget(&mem->css))
return mem;
else {
prev_css = next_css;
goto skip_node;
}
break;
} }
} }
...@@ -984,7 +955,6 @@ static void mem_cgroup_iter_update(struct mem_cgroup_reclaim_iter *iter, ...@@ -984,7 +955,6 @@ static void mem_cgroup_iter_update(struct mem_cgroup_reclaim_iter *iter,
* @root: hierarchy root * @root: hierarchy root
* @prev: previously returned memcg, NULL on first invocation * @prev: previously returned memcg, NULL on first invocation
* @reclaim: cookie for shared reclaim walks, NULL for full walks * @reclaim: cookie for shared reclaim walks, NULL for full walks
* @cond: filter for visited nodes, NULL for no filter
* *
* Returns references to children of the hierarchy below @root, or * Returns references to children of the hierarchy below @root, or
* @root itself, or %NULL after a full round-trip. * @root itself, or %NULL after a full round-trip.
...@@ -997,18 +967,15 @@ static void mem_cgroup_iter_update(struct mem_cgroup_reclaim_iter *iter, ...@@ -997,18 +967,15 @@ static void mem_cgroup_iter_update(struct mem_cgroup_reclaim_iter *iter,
* divide up the memcgs in the hierarchy among all concurrent * divide up the memcgs in the hierarchy among all concurrent
* reclaimers operating on the same zone and priority. * reclaimers operating on the same zone and priority.
*/ */
struct mem_cgroup *mem_cgroup_iter_cond(struct mem_cgroup *root, struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
struct mem_cgroup *prev, struct mem_cgroup *prev,
struct mem_cgroup_reclaim_cookie *reclaim, struct mem_cgroup_reclaim_cookie *reclaim)
mem_cgroup_iter_filter cond)
{ {
struct mem_cgroup *memcg = NULL; struct mem_cgroup *memcg = NULL;
struct mem_cgroup *last_visited = NULL; struct mem_cgroup *last_visited = NULL;
if (mem_cgroup_disabled()) { if (mem_cgroup_disabled())
/* first call must return non-NULL, second return NULL */ return NULL;
return (struct mem_cgroup *)(unsigned long)!prev;
}
if (!root) if (!root)
root = root_mem_cgroup; root = root_mem_cgroup;
...@@ -1019,9 +986,7 @@ struct mem_cgroup *mem_cgroup_iter_cond(struct mem_cgroup *root, ...@@ -1019,9 +986,7 @@ struct mem_cgroup *mem_cgroup_iter_cond(struct mem_cgroup *root,
if (!root->use_hierarchy && root != root_mem_cgroup) { if (!root->use_hierarchy && root != root_mem_cgroup) {
if (prev) if (prev)
goto out_css_put; goto out_css_put;
if (mem_cgroup_filter(root, root, cond) == VISIT) return root;
return root;
return NULL;
} }
rcu_read_lock(); rcu_read_lock();
...@@ -1044,7 +1009,7 @@ struct mem_cgroup *mem_cgroup_iter_cond(struct mem_cgroup *root, ...@@ -1044,7 +1009,7 @@ struct mem_cgroup *mem_cgroup_iter_cond(struct mem_cgroup *root,
last_visited = mem_cgroup_iter_load(iter, root, &seq); last_visited = mem_cgroup_iter_load(iter, root, &seq);
} }
memcg = __mem_cgroup_iter_next(root, last_visited, cond); memcg = __mem_cgroup_iter_next(root, last_visited);
if (reclaim) { if (reclaim) {
mem_cgroup_iter_update(iter, last_visited, memcg, seq); mem_cgroup_iter_update(iter, last_visited, memcg, seq);
...@@ -1055,11 +1020,7 @@ struct mem_cgroup *mem_cgroup_iter_cond(struct mem_cgroup *root, ...@@ -1055,11 +1020,7 @@ struct mem_cgroup *mem_cgroup_iter_cond(struct mem_cgroup *root,
reclaim->generation = iter->generation; reclaim->generation = iter->generation;
} }
/* if (prev && !memcg)
* We have finished the whole tree walk or no group has been
* visited because filter told us to skip the root node.
*/
if (!memcg && (prev || (cond && !last_visited)))
goto out_unlock; goto out_unlock;
} }
out_unlock: out_unlock:
...@@ -1804,14 +1765,13 @@ int mem_cgroup_select_victim_node(struct mem_cgroup *memcg) ...@@ -1804,14 +1765,13 @@ int mem_cgroup_select_victim_node(struct mem_cgroup *memcg)
* a) it is over its soft limit * a) it is over its soft limit
* b) any parent up the hierarchy is over its soft limit * b) any parent up the hierarchy is over its soft limit
*/ */
enum mem_cgroup_filter_t bool mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
struct mem_cgroup *root) struct mem_cgroup *root)
{ {
struct mem_cgroup *parent = memcg; struct mem_cgroup *parent = memcg;
if (res_counter_soft_limit_excess(&memcg->res)) if (res_counter_soft_limit_excess(&memcg->res))
return VISIT; return true;
/* /*
* If any parent up to the root in the hierarchy is over its soft limit * If any parent up to the root in the hierarchy is over its soft limit
...@@ -1819,12 +1779,12 @@ mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg, ...@@ -1819,12 +1779,12 @@ mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
*/ */
while ((parent = parent_mem_cgroup(parent))) { while ((parent = parent_mem_cgroup(parent))) {
if (res_counter_soft_limit_excess(&parent->res)) if (res_counter_soft_limit_excess(&parent->res))
return VISIT; return true;
if (parent == root) if (parent == root)
break; break;
} }
return SKIP; return false;
} }
static DEFINE_SPINLOCK(memcg_oom_lock); static DEFINE_SPINLOCK(memcg_oom_lock);
......
...@@ -2185,16 +2185,21 @@ __shrink_zone(struct zone *zone, struct scan_control *sc, bool soft_reclaim) ...@@ -2185,16 +2185,21 @@ __shrink_zone(struct zone *zone, struct scan_control *sc, bool soft_reclaim)
.zone = zone, .zone = zone,
.priority = sc->priority, .priority = sc->priority,
}; };
struct mem_cgroup *memcg = NULL; struct mem_cgroup *memcg;
mem_cgroup_iter_filter filter = (soft_reclaim) ?
mem_cgroup_soft_reclaim_eligible : NULL;
nr_reclaimed = sc->nr_reclaimed; nr_reclaimed = sc->nr_reclaimed;
nr_scanned = sc->nr_scanned; nr_scanned = sc->nr_scanned;
while ((memcg = mem_cgroup_iter_cond(root, memcg, &reclaim, filter))) { memcg = mem_cgroup_iter(root, NULL, &reclaim);
do {
struct lruvec *lruvec; struct lruvec *lruvec;
if (soft_reclaim &&
!mem_cgroup_soft_reclaim_eligible(memcg, root)) {
memcg = mem_cgroup_iter(root, memcg, &reclaim);
continue;
}
lruvec = mem_cgroup_zone_lruvec(zone, memcg); lruvec = mem_cgroup_zone_lruvec(zone, memcg);
shrink_lruvec(lruvec, sc); shrink_lruvec(lruvec, sc);
...@@ -2214,7 +2219,8 @@ __shrink_zone(struct zone *zone, struct scan_control *sc, bool soft_reclaim) ...@@ -2214,7 +2219,8 @@ __shrink_zone(struct zone *zone, struct scan_control *sc, bool soft_reclaim)
mem_cgroup_iter_break(root, memcg); mem_cgroup_iter_break(root, memcg);
break; break;
} }
} memcg = mem_cgroup_iter(root, memcg, &reclaim);
} while (memcg);
vmpressure(sc->gfp_mask, sc->target_mem_cgroup, vmpressure(sc->gfp_mask, sc->target_mem_cgroup,
sc->nr_scanned - nr_scanned, sc->nr_scanned - nr_scanned,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment