aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r--mm/memcontrol.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index a4bb857d902c..a18e228f140b 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -138,6 +138,7 @@ static const char * const mem_cgroup_lru_names[] = {
138 */ 138 */
139enum mem_cgroup_events_target { 139enum mem_cgroup_events_target {
140 MEM_CGROUP_TARGET_THRESH, 140 MEM_CGROUP_TARGET_THRESH,
141 MEM_CGROUP_TARGET_SOFTLIMIT,
141 MEM_CGROUP_TARGET_NUMAINFO, 142 MEM_CGROUP_TARGET_NUMAINFO,
142 MEM_CGROUP_NTARGETS, 143 MEM_CGROUP_NTARGETS,
143}; 144};
@@ -315,6 +316,22 @@ struct mem_cgroup {
315 atomic_t numainfo_events; 316 atomic_t numainfo_events;
316 atomic_t numainfo_updating; 317 atomic_t numainfo_updating;
317#endif 318#endif
319 /*
320 * Protects soft_contributed transitions.
321 * See mem_cgroup_update_soft_limit
322 */
323 spinlock_t soft_lock;
324
325 /*
326 * If true then this group has increased parents' children_in_excess
327 * when it got over the soft limit.
328 * When a group falls bellow the soft limit, parents' children_in_excess
329 * is decreased and soft_contributed changed to false.
330 */
331 bool soft_contributed;
332
333 /* Number of children that are in soft limit excess */
334 atomic_t children_in_excess;
318 335
319 struct mem_cgroup_per_node *nodeinfo[0]; 336 struct mem_cgroup_per_node *nodeinfo[0];
320 /* WARNING: nodeinfo must be the last member here */ 337 /* WARNING: nodeinfo must be the last member here */
@@ -802,6 +819,9 @@ static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg,
802 case MEM_CGROUP_TARGET_THRESH: 819 case MEM_CGROUP_TARGET_THRESH:
803 next = val + THRESHOLDS_EVENTS_TARGET; 820 next = val + THRESHOLDS_EVENTS_TARGET;
804 break; 821 break;
822 case MEM_CGROUP_TARGET_SOFTLIMIT:
823 next = val + SOFTLIMIT_EVENTS_TARGET;
824 break;
805 case MEM_CGROUP_TARGET_NUMAINFO: 825 case MEM_CGROUP_TARGET_NUMAINFO:
806 next = val + NUMAINFO_EVENTS_TARGET; 826 next = val + NUMAINFO_EVENTS_TARGET;
807 break; 827 break;
@@ -815,6 +835,42 @@ static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg,
815} 835}
816 836
817/* 837/*
838 * Called from rate-limitted memcg_check_events when enough
839 * MEM_CGROUP_TARGET_SOFTLIMIT events are accumulated and it makes sure
840 * that all the parents up the hierarchy will be noticed that this group
841 * is in excess or that it is not in excess anymore. mmecg->soft_contributed
842 * makes the transition a single action whenever the state flips from one to
843 * other.
844 */
845static void mem_cgroup_update_soft_limit(struct mem_cgroup *memcg)
846{
847 unsigned long long excess = res_counter_soft_limit_excess(&memcg->res);
848 struct mem_cgroup *parent = memcg;
849 int delta = 0;
850
851 spin_lock(&memcg->soft_lock);
852 if (excess) {
853 if (!memcg->soft_contributed) {
854 delta = 1;
855 memcg->soft_contributed = true;
856 }
857 } else {
858 if (memcg->soft_contributed) {
859 delta = -1;
860 memcg->soft_contributed = false;
861 }
862 }
863
864 /*
865 * Necessary to update all ancestors when hierarchy is used
866 * because their event counter is not touched.
867 */
868 while (delta && (parent = parent_mem_cgroup(parent)))
869 atomic_add(delta, &parent->children_in_excess);
870 spin_unlock(&memcg->soft_lock);
871}
872
873/*
818 * Check events in order. 874 * Check events in order.
819 * 875 *
820 */ 876 */
@@ -824,8 +880,11 @@ static void memcg_check_events(struct mem_cgroup *memcg, struct page *page)
824 /* threshold event is triggered in finer grain than soft limit */ 880 /* threshold event is triggered in finer grain than soft limit */
825 if (unlikely(mem_cgroup_event_ratelimit(memcg, 881 if (unlikely(mem_cgroup_event_ratelimit(memcg,
826 MEM_CGROUP_TARGET_THRESH))) { 882 MEM_CGROUP_TARGET_THRESH))) {
883 bool do_softlimit;
827 bool do_numainfo __maybe_unused; 884 bool do_numainfo __maybe_unused;
828 885
886 do_softlimit = mem_cgroup_event_ratelimit(memcg,
887 MEM_CGROUP_TARGET_SOFTLIMIT);
829#if MAX_NUMNODES > 1 888#if MAX_NUMNODES > 1
830 do_numainfo = mem_cgroup_event_ratelimit(memcg, 889 do_numainfo = mem_cgroup_event_ratelimit(memcg,
831 MEM_CGROUP_TARGET_NUMAINFO); 890 MEM_CGROUP_TARGET_NUMAINFO);
@@ -833,6 +892,8 @@ static void memcg_check_events(struct mem_cgroup *memcg, struct page *page)
833 preempt_enable(); 892 preempt_enable();
834 893
835 mem_cgroup_threshold(memcg); 894 mem_cgroup_threshold(memcg);
895 if (unlikely(do_softlimit))
896 mem_cgroup_update_soft_limit(memcg);
836#if MAX_NUMNODES > 1 897#if MAX_NUMNODES > 1
837 if (unlikely(do_numainfo)) 898 if (unlikely(do_numainfo))
838 atomic_inc(&memcg->numainfo_events); 899 atomic_inc(&memcg->numainfo_events);
@@ -1816,6 +1877,9 @@ int mem_cgroup_select_victim_node(struct mem_cgroup *memcg)
1816 * hierarchy if 1877 * hierarchy if
1817 * a) it is over its soft limit 1878 * a) it is over its soft limit
1818 * b) any parent up the hierarchy is over its soft limit 1879 * b) any parent up the hierarchy is over its soft limit
1880 *
1881 * If the given group doesn't have any children over the limit then it
1882 * doesn't make any sense to iterate its subtree.
1819 */ 1883 */
1820enum mem_cgroup_filter_t 1884enum mem_cgroup_filter_t
1821mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg, 1885mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
@@ -1837,6 +1901,8 @@ mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
1837 break; 1901 break;
1838 } 1902 }
1839 1903
1904 if (!atomic_read(&memcg->children_in_excess))
1905 return SKIP_TREE;
1840 return SKIP; 1906 return SKIP;
1841} 1907}
1842 1908
@@ -5892,6 +5958,7 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
5892 mutex_init(&memcg->thresholds_lock); 5958 mutex_init(&memcg->thresholds_lock);
5893 spin_lock_init(&memcg->move_lock); 5959 spin_lock_init(&memcg->move_lock);
5894 vmpressure_init(&memcg->vmpressure); 5960 vmpressure_init(&memcg->vmpressure);
5961 spin_lock_init(&memcg->soft_lock);
5895 5962
5896 return &memcg->css; 5963 return &memcg->css;
5897 5964
@@ -5969,6 +6036,10 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
5969 6036
5970 mem_cgroup_invalidate_reclaim_iterators(memcg); 6037 mem_cgroup_invalidate_reclaim_iterators(memcg);
5971 mem_cgroup_reparent_charges(memcg); 6038 mem_cgroup_reparent_charges(memcg);
6039 if (memcg->soft_contributed) {
6040 while ((memcg = parent_mem_cgroup(memcg)))
6041 atomic_dec(&memcg->children_in_excess);
6042 }
5972 mem_cgroup_destroy_all_caches(memcg); 6043 mem_cgroup_destroy_all_caches(memcg);
5973 vmpressure_cleanup(&memcg->vmpressure); 6044 vmpressure_cleanup(&memcg->vmpressure);
5974} 6045}