History

mm, memcg: decouple e{low,min} state mutations from protection checks

mem_cgroup_protected currently is both used to set effective low and min and return a mem_cgroup_protection based on the result. As a user, this can be a little unexpected: it appears to be a simple predicate function, if not for the big warning in the comment above about the order in which it must be executed. This change makes it so that we separate the state mutations from the actual protection checks, which makes it more obvious where we need to be careful mutating internal state, and where we are simply checking and don't need to worry about that. [mhocko@suse.com - don't check protection on root memcgs]

Chris Down committed 6 years ago

Commit 45c7f7e1 parent 22f74963 files · +53 −45Browse files

Unified · Split

3 files
  1. include/linux/memcontrol.h +42 −11
  2. mm/memcontrol.c +7 −21
  3. mm/vmscan.c +4 −13
include/linux/memcontrol.h+42−11
@@ -47,12 +47,6 @@ enum memcg_memory_event { · 46 unmodified lines
4747 MEMCG_NR_MEMORY_EVENTS,
4848 };
4949
50−enum mem_cgroup_protection {
51− MEMCG_PROT_NONE,
52− MEMCG_PROT_LOW,
53− MEMCG_PROT_MIN,
54−};
55−
5650 struct mem_cgroup_reclaim_cookie {
5751 pg_data_t *pgdat;
5852 unsigned int generation;
@@ -405,8 +399,36 @@ static inline unsigned long mem_cgroup_protection(struct mem_cgroup *root, · 346 unmodified lines
405399 READ_ONCE(memcg->memory.elow));
406400 }
407401
408−enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root,
409− struct mem_cgroup *memcg);
402+void mem_cgroup_calculate_protection(struct mem_cgroup *root,
403+ struct mem_cgroup *memcg);
404+
405+static inline bool mem_cgroup_supports_protection(struct mem_cgroup *memcg)
406+{
407+ /*
408+ * The root memcg doesn't account charges, and doesn't support
409+ * protection.
410+ */
411+ return !mem_cgroup_disabled() && !mem_cgroup_is_root(memcg);
412+
413+}
414+
415+static inline bool mem_cgroup_below_low(struct mem_cgroup *memcg)
416+{
417+ if (!mem_cgroup_supports_protection(memcg))
418+ return false;
419+
420+ return READ_ONCE(memcg->memory.elow) >=
421+ page_counter_read(&memcg->memory);
422+}
423+
424+static inline bool mem_cgroup_below_min(struct mem_cgroup *memcg)
425+{
426+ if (!mem_cgroup_supports_protection(memcg))
427+ return false;
428+
429+ return READ_ONCE(memcg->memory.emin) >=
430+ page_counter_read(&memcg->memory);
431+}
410432
411433 int mem_cgroup_charge(struct page *page, struct mm_struct *mm, gfp_t gfp_mask);
412434
@@ -935,10 +957,19 @@ static inline unsigned long mem_cgroup_protection(struct mem_cgroup *root, · 522 unmodified lines
935957 return 0;
936958 }
937959
938−static inline enum mem_cgroup_protection mem_cgroup_protected(
939− struct mem_cgroup *root, struct mem_cgroup *memcg)
960+static inline void mem_cgroup_calculate_protection(struct mem_cgroup *root,
961+ struct mem_cgroup *memcg)
940962 {
941− return MEMCG_PROT_NONE;
963+}
964+
965+static inline bool mem_cgroup_below_low(struct mem_cgroup *memcg)
966+{
967+ return false;
968+}
969+
970+static inline bool mem_cgroup_below_min(struct mem_cgroup *memcg)
971+{
972+ return false;
942973 }
943974
944975 static inline int mem_cgroup_charge(struct page *page, struct mm_struct *mm,
mm/memcontrol.c+7−21
@@ -6587,21 +6587,15 @@ static unsigned long effective_protection(unsigned long usage, · 6586 unmodified lines
65876587 *
65886588 * WARNING: This function is not stateless! It can only be used as part
65896589 * of a top-down tree iteration, not for isolated queries.
6590− *
6591− * Returns one of the following:
6592− * MEMCG_PROT_NONE: cgroup memory is not protected
6593− * MEMCG_PROT_LOW: cgroup memory is protected as long there is
6594− * an unprotected supply of reclaimable memory from other cgroups.
6595− * MEMCG_PROT_MIN: cgroup memory is protected
65966590 */
6597−enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root,
6598− struct mem_cgroup *memcg)
6591+void mem_cgroup_calculate_protection(struct mem_cgroup *root,
6592+ struct mem_cgroup *memcg)
65996593 {
66006594 unsigned long usage, parent_usage;
66016595 struct mem_cgroup *parent;
66026596
66036597 if (mem_cgroup_disabled())
6604− return MEMCG_PROT_NONE;
6598+ return;
66056599
66066600 if (!root)
66076601 root = root_mem_cgroup;
@@ -6614,21 +6608,21 @@ enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root, · 6 unmodified lines
66146608 * that special casing.
66156609 */
66166610 if (memcg == root)
6617− return MEMCG_PROT_NONE;
6611+ return;
66186612
66196613 usage = page_counter_read(&memcg->memory);
66206614 if (!usage)
6621− return MEMCG_PROT_NONE;
6615+ return;
66226616
66236617 parent = parent_mem_cgroup(memcg);
66246618 /* No parent means a non-hierarchical mode on v1 memcg */
66256619 if (!parent)
6626− return MEMCG_PROT_NONE;
6620+ return;
66276621
66286622 if (parent == root) {
66296623 memcg->memory.emin = READ_ONCE(memcg->memory.min);
66306624 memcg->memory.elow = READ_ONCE(memcg->memory.low);
6631− goto out;
6625+ return;
66326626 }
66336627
66346628 parent_usage = page_counter_read(&parent->memory);
@@ -6642,14 +6636,6 @@ enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root, · 7 unmodified lines
66426636 READ_ONCE(memcg->memory.low),
66436637 READ_ONCE(parent->memory.elow),
66446638 atomic_long_read(&parent->memory.children_low_usage)));
6645−
6646−out:
6647− if (usage <= memcg->memory.emin)
6648− return MEMCG_PROT_MIN;
6649− else if (usage <= memcg->memory.elow)
6650− return MEMCG_PROT_LOW;
6651− else
6652− return MEMCG_PROT_NONE;
66536639 }
66546640
66556641 /**
mm/vmscan.c+4−13
@@ -2620,14 +2620,15 @@ static void shrink_node_memcgs(pg_data_t *pgdat, struct scan_control *sc) · 2619 unmodified lines
26202620 unsigned long reclaimed;
26212621 unsigned long scanned;
26222622
2623− switch (mem_cgroup_protected(target_memcg, memcg)) {
2624− case MEMCG_PROT_MIN:
2623+ mem_cgroup_calculate_protection(target_memcg, memcg);
2624+
2625+ if (mem_cgroup_below_min(memcg)) {
26252626 /*
26262627 * Hard protection.
26272628 * If there is no reclaimable memory, OOM.
26282629 */
26292630 continue;
2630− case MEMCG_PROT_LOW:
2631+ } else if (mem_cgroup_below_low(memcg)) {
26312632 /*
26322633 * Soft protection.
26332634 * Respect the protection only as long as
@@ -2639,16 +2640,6 @@ static void shrink_node_memcgs(pg_data_t *pgdat, struct scan_control *sc) · 5 unmodified lines
26392640 continue;
26402641 }
26412642 memcg_memory_event(memcg, MEMCG_LOW);
2642− break;
2643− case MEMCG_PROT_NONE:
2644− /*
2645− * All protection thresholds breached. We may
2646− * still choose to vary the scan pressure
2647− * applied based on by how much the cgroup in
2648− * question has exceeded its protection
2649− * thresholds (see get_scan_count).
2650− */
2651− break;
26522643 }
26532644
26542645 reclaimed = sc->nr_reclaimed;