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
47 MEMCG_NR_MEMORY_EVENTS,47 MEMCG_NR_MEMORY_EVENTS,
48};48};
49 49
50enum mem_cgroup_protection {
51 MEMCG_PROT_NONE,
52 MEMCG_PROT_LOW,
53 MEMCG_PROT_MIN,
54};
55
56struct mem_cgroup_reclaim_cookie {50struct mem_cgroup_reclaim_cookie {
57 pg_data_t *pgdat;51 pg_data_t *pgdat;
58 unsigned int generation;52 unsigned int generation;
@@ -405,8 +399,36 @@ static inline unsigned long mem_cgroup_protection(struct mem_cgroup *root, · 346 unmodified lines
405 READ_ONCE(memcg->memory.elow));399 READ_ONCE(memcg->memory.elow));
406}400}
407 401
408enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root,402void mem_cgroup_calculate_protection(struct mem_cgroup *root,
409 struct mem_cgroup *memcg);403 struct mem_cgroup *memcg);
404
405static 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
415static 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
424static 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}
410 432
411int mem_cgroup_charge(struct page *page, struct mm_struct *mm, gfp_t gfp_mask);433int mem_cgroup_charge(struct page *page, struct mm_struct *mm, gfp_t gfp_mask);
412 434
@@ -935,10 +957,19 @@ static inline unsigned long mem_cgroup_protection(struct mem_cgroup *root, · 522 unmodified lines
935 return 0;957 return 0;
936}958}
937 959
938static inline enum mem_cgroup_protection mem_cgroup_protected(960static inline void mem_cgroup_calculate_protection(struct mem_cgroup *root,
939 struct mem_cgroup *root, struct mem_cgroup *memcg)961 struct mem_cgroup *memcg)
940{962{
941 return MEMCG_PROT_NONE;963}
964
965static inline bool mem_cgroup_below_low(struct mem_cgroup *memcg)
966{
967 return false;
968}
969
970static inline bool mem_cgroup_below_min(struct mem_cgroup *memcg)
971{
972 return false;
942}973}
943 974
944static inline int mem_cgroup_charge(struct page *page, struct mm_struct *mm,975static 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
6587 *6587 *
6588 * WARNING: This function is not stateless! It can only be used as part6588 * WARNING: This function is not stateless! It can only be used as part
6589 * of a top-down tree iteration, not for isolated queries.6589 * 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
6596 */6590 */
6597enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root,6591void mem_cgroup_calculate_protection(struct mem_cgroup *root,
6598 struct mem_cgroup *memcg)6592 struct mem_cgroup *memcg)
6599{6593{
6600 unsigned long usage, parent_usage;6594 unsigned long usage, parent_usage;
6601 struct mem_cgroup *parent;6595 struct mem_cgroup *parent;
6602 6596
6603 if (mem_cgroup_disabled())6597 if (mem_cgroup_disabled())
6604 return MEMCG_PROT_NONE;6598 return;
6605 6599
6606 if (!root)6600 if (!root)
6607 root = root_mem_cgroup;6601 root = root_mem_cgroup;
@@ -6614,21 +6608,21 @@ enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root, · 6 unmodified lines
6614 * that special casing.6608 * that special casing.
6615 */6609 */
6616 if (memcg == root)6610 if (memcg == root)
6617 return MEMCG_PROT_NONE;6611 return;
6618 6612
6619 usage = page_counter_read(&memcg->memory);6613 usage = page_counter_read(&memcg->memory);
6620 if (!usage)6614 if (!usage)
6621 return MEMCG_PROT_NONE;6615 return;
6622 6616
6623 parent = parent_mem_cgroup(memcg);6617 parent = parent_mem_cgroup(memcg);
6624 /* No parent means a non-hierarchical mode on v1 memcg */6618 /* No parent means a non-hierarchical mode on v1 memcg */
6625 if (!parent)6619 if (!parent)
6626 return MEMCG_PROT_NONE;6620 return;
6627 6621
6628 if (parent == root) {6622 if (parent == root) {
6629 memcg->memory.emin = READ_ONCE(memcg->memory.min);6623 memcg->memory.emin = READ_ONCE(memcg->memory.min);
6630 memcg->memory.elow = READ_ONCE(memcg->memory.low);6624 memcg->memory.elow = READ_ONCE(memcg->memory.low);
6631 goto out;6625 return;
6632 }6626 }
6633 6627
6634 parent_usage = page_counter_read(&parent->memory);6628 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
6642 READ_ONCE(memcg->memory.low),6636 READ_ONCE(memcg->memory.low),
6643 READ_ONCE(parent->memory.elow),6637 READ_ONCE(parent->memory.elow),
6644 atomic_long_read(&parent->memory.children_low_usage)));6638 atomic_long_read(&parent->memory.children_low_usage)));
6645
6646out:
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;
6653}6639}
6654 6640
6655/**6641/**
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
2620 unsigned long reclaimed;2620 unsigned long reclaimed;
2621 unsigned long scanned;2621 unsigned long scanned;
2622 2622
2623 switch (mem_cgroup_protected(target_memcg, memcg)) {2623 mem_cgroup_calculate_protection(target_memcg, memcg);
2624 case MEMCG_PROT_MIN:2624
2625 if (mem_cgroup_below_min(memcg)) {
2625 /*2626 /*
2626 * Hard protection.2627 * Hard protection.
2627 * If there is no reclaimable memory, OOM.2628 * If there is no reclaimable memory, OOM.
2628 */2629 */
2629 continue;2630 continue;
2630 case MEMCG_PROT_LOW:2631 } else if (mem_cgroup_below_low(memcg)) {
2631 /*2632 /*
2632 * Soft protection.2633 * Soft protection.
2633 * Respect the protection only as long as2634 * 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
2639 continue;2640 continue;
2640 }2641 }
2641 memcg_memory_event(memcg, MEMCG_LOW);2642 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;
2652 }2643 }
2653 2644
2654 reclaimed = sc->nr_reclaimed;2645 reclaimed = sc->nr_reclaimed;