diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index c2ad120281e84542c1d644ec7cae85cb82c6ac6a..8d326442cda310d5b1b65226c3c7658995220a9e 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -575,6 +575,8 @@ static inline struct cftype *of_cft(struct kernfs_open_file *of) } struct cgroup_subsys_state *of_css(struct kernfs_open_file *of); +struct cgroup *cgroup_kn_lock_live(struct kernfs_node *kn, bool drain_offline); +void cgroup_kn_unlock(struct kernfs_node *kn); /* cft/css accessors for cftype->seq_*() operations */ static inline struct cftype *seq_cft(struct seq_file *seq) diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h index 9d4a477bbd37ca1b717149026a3c7a46f7b2ca52..dcd116f04174ab7468afdb3dd4d427d1d6c3a9b9 100644 --- a/kernel/cgroup/cgroup-internal.h +++ b/kernel/cgroup/cgroup-internal.h @@ -227,8 +227,6 @@ struct cgroup *kn_priv(struct kernfs_node *kn); struct cgroup_root *cgroup_root_from_kf(struct kernfs_root *kf_root); struct cgroup *task_cgroup_from_root(struct task_struct *task, struct cgroup_root *root); -struct cgroup *cgroup_kn_lock_live(struct kernfs_node *kn, bool drain_offline); -void cgroup_kn_unlock(struct kernfs_node *kn); int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen, struct cgroup_namespace *ns); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 55bbddf61cfc0fd1598a8b88665e41191239d9c6..e59d3816316271a3bcb1a95f2aed4dba51e44de5 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5277,12 +5277,14 @@ static ssize_t memory_wmark_scale_factor_write(struct kernfs_open_file *of, * wmark_min_adj: A -10, B -25, C 0, D 50, E -25, F 50 * wmark_min_eadj: A -10, B -10, C 0, D 50, E -10, F 50 */ -static void memcg_update_wmark_min_adj(struct mem_cgroup *memcg, int val) +static void memcg_update_wmark_min_adj_locked(struct mem_cgroup *memcg, + int val) { struct mem_cgroup *p; struct mem_cgroup *iter; - mutex_lock(&cgroup_mutex); + lockdep_assert_held(&cgroup_mutex); + memcg->wmark_min_adj = val; /* update hierarchical wmark_min_eadj, pre-order iteration */ for_each_mem_cgroup_tree(iter, memcg) { @@ -5294,7 +5296,6 @@ static void memcg_update_wmark_min_adj(struct mem_cgroup *memcg, int val) val = p->wmark_min_eadj; iter->wmark_min_eadj = val; } - mutex_unlock(&cgroup_mutex); } static int memory_wmark_min_adj_show(struct seq_file *m, void *v) @@ -5310,7 +5311,8 @@ static int memory_wmark_min_adj_show(struct seq_file *m, void *v) static ssize_t memory_wmark_min_adj_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { - struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of)); + struct cgroup *cgrp; + struct mem_cgroup *memcg; int ret, wmark_min_adj; buf = strstrip(buf); @@ -5321,8 +5323,14 @@ static ssize_t memory_wmark_min_adj_write(struct kernfs_open_file *of, if (wmark_min_adj < -25 || wmark_min_adj > 50) return -EINVAL; - memcg_update_wmark_min_adj(memcg, wmark_min_adj); + cgrp = cgroup_kn_lock_live(of->kn, false); + if (!cgrp) + return -ENODEV; + + memcg = mem_cgroup_from_css(of_css(of)); + memcg_update_wmark_min_adj_locked(memcg, wmark_min_adj); + cgroup_kn_unlock(of->kn); return nbytes; }