diff --git a/include/linux/memcg_policy.h b/include/linux/memcg_policy.h index 201b0e973e3c47f7e6b980b5ff8f1a1eee0f293d..4aec2a1bb3ecf8a8e7f2c4835a524f54c09bb7de 100644 --- a/include/linux/memcg_policy.h +++ b/include/linux/memcg_policy.h @@ -15,7 +15,7 @@ struct scan_control; extern struct list_head score_head; extern bool score_head_inited; -extern spinlock_t score_list_lock; +extern rwlock_t score_list_lock; extern struct cgroup_subsys memory_cgrp_subsys; #ifdef CONFIG_HYPERHOLD_FILE_LRU void shrink_anon_memcg(struct pglist_data *pgdat, diff --git a/mm/memcg_control.c b/mm/memcg_control.c index 985fcaa669435e6154a561821f7fd3fcf8d8e720..dd62304a9c687e181ee61908217b95016b6be22c 100644 --- a/mm/memcg_control.c +++ b/mm/memcg_control.c @@ -17,7 +17,7 @@ struct list_head score_head; bool score_head_inited; -DEFINE_SPINLOCK(score_list_lock); +DEFINE_RWLOCK(score_list_lock); DEFINE_MUTEX(reclaim_para_lock); /** @@ -40,7 +40,7 @@ struct mem_cgroup *get_next_memcg(struct mem_cgroup *prev) if (unlikely(!score_head_inited)) return NULL; - spin_lock_irqsave(&score_list_lock, flags); + read_lock_irqsave(&score_list_lock, flags); if (unlikely(!prev)) pos = &score_head; @@ -60,7 +60,7 @@ struct mem_cgroup *get_next_memcg(struct mem_cgroup *prev) memcg = NULL; unlock: - spin_unlock_irqrestore(&score_list_lock, flags); + read_unlock_irqrestore(&score_list_lock, flags); if (prev) css_put(&prev->css); @@ -83,7 +83,7 @@ struct mem_cgroup *get_prev_memcg(struct mem_cgroup *next) if (unlikely(!score_head_inited)) return NULL; - spin_lock_irqsave(&score_list_lock, flags); + read_lock_irqsave(&score_list_lock, flags); if (unlikely(!next)) pos = &score_head; @@ -106,7 +106,7 @@ struct mem_cgroup *get_prev_memcg(struct mem_cgroup *next) memcg = NULL; unlock: - spin_unlock_irqrestore(&score_list_lock, flags); + read_unlock_irqrestore(&score_list_lock, flags); if (next) css_put(&next->css); @@ -125,7 +125,7 @@ void memcg_app_score_update(struct mem_cgroup *target) struct list_head *tmp; unsigned long flags; - spin_lock_irqsave(&score_list_lock, flags); + write_lock_irqsave(&score_list_lock, flags); list_for_each_prev_safe(pos, tmp, &score_head) { struct mem_cgroup *memcg = list_entry(pos, struct mem_cgroup, score_node); @@ -134,7 +134,7 @@ void memcg_app_score_update(struct mem_cgroup *target) break; } list_move_tail(&target->score_node, pos); - spin_unlock_irqrestore(&score_list_lock, flags); + write_unlock_irqrestore(&score_list_lock, flags); } static u64 mem_cgroup_app_score_read(struct cgroup_subsys_state *css, diff --git a/mm/memcg_reclaim.c b/mm/memcg_reclaim.c index f88826c13ae2e287713e5e7032ccd724cbd31416..74c3d4dfa08bb6d016b8d0481c10b0bc3fe2190a 100644 --- a/mm/memcg_reclaim.c +++ b/mm/memcg_reclaim.c @@ -215,6 +215,18 @@ void shrink_anon_memcg(struct pglist_data *pgdat, sc->nr_reclaimed_anon += nr_reclaimed; } +static inline bool memcg_is_child_of(struct mem_cgroup *mcg, struct mem_cgroup *tmcg) +{ + while (!mem_cgroup_is_root(mcg)) { + if (mcg == tmcg) + break; + + mcg = parent_mem_cgroup(mcg); + } + + return (mcg == tmcg); +} + static void shrink_anon(struct pglist_data *pgdat, struct scan_control *sc, unsigned long *nr) { @@ -229,7 +241,12 @@ static void shrink_anon(struct pglist_data *pgdat, node_lruvec(pgdat), LRU_INACTIVE_ANON, MAX_NR_ZONES); while ((memcg = get_next_memcg(memcg))) { - struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); + struct lruvec *lruvec = NULL; + + if (!memcg_is_child_of(memcg, target_memcg)) + continue; + + lruvec = mem_cgroup_lruvec(memcg, pgdat); reclaimed = sc->nr_reclaimed; scanned = sc->nr_scanned; @@ -438,8 +455,10 @@ bool shrink_node_hyperhold(struct pglist_data *pgdat, struct scan_control *sc) get_scan_count_hyperhold(pgdat, sc, nr, &node_lru_pages); - /* Shrink the Total-File-LRU */ - shrink_file(pgdat, sc, nr); + if (!cgroup_reclaim(sc)) { + /* Shrink the Total-File-LRU */ + shrink_file(pgdat, sc, nr); + } /* Shrink Anon by iterating score_list */ shrink_anon(pgdat, sc, nr); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 30e068e95e214f5b078f88c47d8f6ed4f2d59c18..b1d67bcfb617623c9047d07088eeb598bf10e77f 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5496,9 +5496,9 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) #ifdef CONFIG_HYPERHOLD_MEMCG unsigned long flags; - spin_lock_irqsave(&score_list_lock, flags); + write_lock_irqsave(&score_list_lock, flags); list_del_init(&memcg->score_node); - spin_unlock_irqrestore(&score_list_lock, flags); + write_unlock_irqrestore(&score_list_lock, flags); css_put(css); #endif diff --git a/mm/zswapd_control.c b/mm/zswapd_control.c index d91a08b5ae2fe0374c1fe59aa4d1c8f49b61c080..ab5ca24b300696633b8b337cc5d91b65e9203988 100644 --- a/mm/zswapd_control.c +++ b/mm/zswapd_control.c @@ -28,6 +28,8 @@ #define ZRAM_WM_RATIO 0 #define MAX_RATIO 100 +#define CHECK_BUFFER_VALID(var1, var2) (((var2) != 0) && ((var1) > (var2))) + struct zswapd_param { unsigned int min_score; unsigned int max_score; @@ -148,6 +150,11 @@ static ssize_t avail_buffers_params_write(struct kernfs_open_file *of, if (sscanf(buf, "%u %u %u %llu", &buffers, &min_buffers, &high_buffers, &threshold) != 4) return -EINVAL; + if (CHECK_BUFFER_VALID(min_buffers, buffers) || + CHECK_BUFFER_VALID(min_buffers, high_buffers) || + CHECK_BUFFER_VALID(buffers, high_buffers)) + return -EINVAL; + atomic_set(&avail_buffers, buffers); atomic_set(&min_avail_buffers, min_buffers); atomic_set(&high_avail_buffers, high_buffers); @@ -410,7 +417,8 @@ static ssize_t zswapd_single_memcg_param_write(struct kernfs_open_file *of, &refault_threshold) != 3) return -EINVAL; - if (ub_mem2zram_ratio > MAX_RATIO || ub_zram2ufs_ratio > MAX_RATIO) + if (ub_mem2zram_ratio > MAX_RATIO || ub_zram2ufs_ratio > MAX_RATIO || + refault_threshold > MAX_RATIO) return -EINVAL; atomic_set(&memcg->memcg_reclaimed.ub_mem2zram_ratio,