Create a new function of_peak_reset that resets the page_counter peak for a
given writer. This should allow it to be reused by other cgroups.

Signed-off-by: Thadeu Lima de Souza Cascardo <[email protected]>
---
 include/linux/cgroup-defs.h |  6 ++++++
 kernel/cgroup/cgroup.c      | 32 ++++++++++++++++++++++++++++++++
 mm/memcontrol.c             | 42 ++++++++----------------------------------
 3 files changed, 46 insertions(+), 34 deletions(-)

diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index f42563739d2e..a85044cb0553 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -22,6 +22,7 @@
 #include <linux/workqueue.h>
 #include <linux/bpf-cgroup-defs.h>
 #include <linux/psi_types.h>
+#include <linux/page_counter.h>
 
 #ifdef CONFIG_CGROUPS
 
@@ -868,11 +869,16 @@ struct cgroup_subsys {
 extern struct percpu_rw_semaphore cgroup_threadgroup_rwsem;
 extern bool cgroup_enable_per_threadgroup_rwsem;
 
+#define OFP_PEAK_UNSET (((-1UL)))
+
 struct cgroup_of_peak {
        unsigned long           value;
        struct list_head        list;
 };
 
+void of_peak_reset(struct cgroup_of_peak *ofp, struct page_counter *pc,
+                  struct list_head *watchers);
+
 /**
  * cgroup_threadgroup_change_begin - threadgroup exclusion for cgroups
  * @tsk: target task
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 45c0b1ed687a..9b98a5cccf0e 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -1981,6 +1981,38 @@ struct cgroup_of_peak *of_peak(struct kernfs_open_file 
*of)
        return &ctx->peak;
 }
 
+/**
+ * of_peak_reset - reset peak
+ * @ofp: open file context
+ * @pc: counter
+ * @watchers: list of other open file contexts
+ *
+ * This function updates all contexts in @watchers to the new usage of @pc.
+ * If @ofp is not in the list yet, that is, if its value is
+ * %OFP_PEAK_UNSET, it is added to @watchers list.
+ *
+ * A lock must be used to protect @watchers.
+ */
+void of_peak_reset(struct cgroup_of_peak *ofp, struct page_counter *pc,
+                  struct list_head *watchers)
+{
+       unsigned long usage;
+       struct cgroup_of_peak *peer_ctx;
+
+       usage = page_counter_read(pc);
+       WRITE_ONCE(pc->local_watermark, usage);
+
+       list_for_each_entry(peer_ctx, watchers, list)
+               if (usage > peer_ctx->value)
+                       WRITE_ONCE(peer_ctx->value, usage);
+
+       /* initial write, register watcher */
+       if (ofp->value == OFP_PEAK_UNSET)
+               list_add(&ofp->list, watchers);
+
+       WRITE_ONCE(ofp->value, usage);
+}
+
 static void apply_cgroup_root_flags(unsigned int root_flags)
 {
        if (current->nsproxy->cgroup_ns == &init_cgroup_ns) {
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index c03d4787d466..8754927070d3 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4517,8 +4517,6 @@ static u64 memory_current_read(struct cgroup_subsys_state 
*css,
        return (u64)page_counter_read(&memcg->memory) * PAGE_SIZE;
 }
 
-#define OFP_PEAK_UNSET (((-1UL)))
-
 static int peak_show(struct seq_file *sf, void *v, struct page_counter *pc)
 {
        struct cgroup_of_peak *ofp = of_peak(sf->private);
@@ -4563,45 +4561,18 @@ static void peak_release(struct kernfs_open_file *of)
        spin_unlock(&memcg->peaks_lock);
 }
 
-static ssize_t peak_write(struct kernfs_open_file *of, char *buf, size_t 
nbytes,
-                         loff_t off, struct page_counter *pc,
-                         struct list_head *watchers)
+static ssize_t memory_peak_write(struct kernfs_open_file *of, char *buf,
+                                size_t nbytes, loff_t off)
 {
-       unsigned long usage;
-       struct cgroup_of_peak *peer_ctx;
        struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
        struct cgroup_of_peak *ofp = of_peak(of);
 
        spin_lock(&memcg->peaks_lock);
-
-       usage = page_counter_read(pc);
-       WRITE_ONCE(pc->local_watermark, usage);
-
-       list_for_each_entry(peer_ctx, watchers, list)
-               if (usage > peer_ctx->value)
-                       WRITE_ONCE(peer_ctx->value, usage);
-
-       /* initial write, register watcher */
-       if (ofp->value == OFP_PEAK_UNSET)
-               list_add(&ofp->list, watchers);
-
-       WRITE_ONCE(ofp->value, usage);
+       of_peak_reset(ofp, &memcg->memory, &memcg->memory_peaks);
        spin_unlock(&memcg->peaks_lock);
-
        return nbytes;
 }
 
-static ssize_t memory_peak_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));
-
-       return peak_write(of, buf, nbytes, off, &memcg->memory,
-                         &memcg->memory_peaks);
-}
-
-#undef OFP_PEAK_UNSET
-
 static int memory_min_show(struct seq_file *m, void *v)
 {
        return seq_puts_memcg_tunable(m,
@@ -5611,9 +5582,12 @@ static ssize_t swap_peak_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_of_peak *ofp = of_peak(of);
 
-       return peak_write(of, buf, nbytes, off, &memcg->swap,
-                         &memcg->swap_peaks);
+       spin_lock(&memcg->peaks_lock);
+       of_peak_reset(ofp, &memcg->swap, &memcg->swap_peaks);
+       spin_unlock(&memcg->peaks_lock);
+       return nbytes;
 }
 
 static int swap_high_show(struct seq_file *m, void *v)

-- 
2.47.3

Reply via email to