blob: 8aadd1379febd285e0807521c3c1a126899ef3f6 [file] [log] [blame] [edit]
From aa11d788b935a8b86976ffaa822e4ccdea9cf09f Mon Sep 17 00:00:00 2001
From: Bryan Yu <yuholong@google.com>
Date: Wed, 19 Oct 2022 13:31:24 +0900
Subject: [PATCH] CHROMIUM: Reland of add implementation of MGLRU in sysfs
This is a reland of CL:3839069 fixing the memcg bug and snprintf buffer
overflow.
Tested on ARM device with both memcg on and off.
This cherry-pick also contains the changes in CL:4004384.
BUG=b:254153610
TEST=Manual testing on DUT
Signed-off-by: Bryan Yu <yuholong@google.com>
Change-Id: I7dcd354fadda7b4a28c787f6b28dfbce3d1c2f87
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3965160
Reviewed-by: Suleiman Souhlal <suleiman@chromium.org>
Commit-Queue: Alexandre Marciano Gimenez <raging@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3998276
Reviewed-by: Alexandre Marciano Gimenez <raging@google.com>
Commit-Queue: Koki Ryu <kokiryu@chromium.org>
Tested-by: Koki Ryu <kokiryu@chromium.org>
Reviewed-by: Koki Ryu <kokiryu@chromium.org>
[rebase61(tzungbi):
Squashed:
FIXUP: CHROMIUM: Reland of add implementation of MGLRU in sysfs
]
Signed-off-by: Tzung-Bi Shih <tzungbi@chromium.org>
---
mm/vmscan.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 159 insertions(+)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 9129a0c93f55412f441e05af84db91097f7468d4..d0e86bf3c7c8ca57ccd70cdbe78c117c46431c01 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -5751,6 +5751,15 @@ static void lru_gen_change_state(bool enabled)
* sysfs interface
******************************************************************************/
+static int run_aging(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc,
+ bool can_swap, bool force_scan);
+
+static int run_eviction(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc,
+ int swappiness, unsigned long nr_to_reclaim);
+
+static int run_cmd(char cmd, int memcg_id, int nid, unsigned long seq,
+ struct scan_control *sc, int swappiness, unsigned long opt);
+
static ssize_t min_ttl_ms_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sysfs_emit(buf, "%u\n", jiffies_to_msecs(READ_ONCE(lru_gen_min_ttl)));
@@ -5818,9 +5827,159 @@ static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr,
static struct kobj_attribute lru_gen_enabled_attr = __ATTR_RW(enabled);
+static int print_node_mglru(struct lruvec *lruvec, char *buf, int orig_pos)
+{
+ unsigned long seq;
+ struct lru_gen_struct *lrugen = &lruvec->lrugen;
+
+ DEFINE_MAX_SEQ(lruvec);
+ DEFINE_MIN_SEQ(lruvec);
+
+ int print_pos = orig_pos;
+
+ seq = min(min_seq[0], min_seq[1]);
+
+ for (; seq <= max_seq; seq++) {
+ int gen, type, zone;
+ unsigned int msecs;
+
+ gen = lru_gen_from_seq(seq);
+ msecs = jiffies_to_msecs(jiffies - READ_ONCE(lrugen->timestamps[gen]));
+
+ print_pos += snprintf(buf + print_pos, PAGE_SIZE - print_pos,
+ " %10lu %10u", seq, msecs);
+
+ for (type = 0; type < ANON_AND_FILE; type++) {
+ long size = 0;
+
+ if (seq < min_seq[type]) {
+ print_pos += snprintf(buf + print_pos,
+ PAGE_SIZE - print_pos, " -0 ");
+ continue;
+ }
+
+ for (zone = 0; zone < MAX_NR_ZONES; zone++)
+ size += READ_ONCE(lrugen->nr_pages[gen][type][zone]);
+
+ print_pos += snprintf(buf + print_pos,
+ PAGE_SIZE - print_pos, " %10lu ", max(size, 0L));
+ }
+
+ print_pos += snprintf(buf + print_pos, PAGE_SIZE - print_pos, "\n");
+
+ }
+
+ return print_pos - orig_pos;
+}
+
+static ssize_t show_lru_gen_admin(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct lruvec *lruvec;
+ struct mem_cgroup *memcg;
+
+ char *path = kvmalloc(PATH_MAX, GFP_KERNEL);
+ int buf_len = 0;
+
+ if (!path)
+ return -EINVAL;
+ path[0] = 0;
+ buf[0] = 0;
+ memcg = mem_cgroup_iter(NULL, NULL, NULL);
+ do {
+ int nid;
+
+ for_each_node_state(nid, N_MEMORY) {
+ lruvec = mem_cgroup_lruvec(memcg, NODE_DATA(nid));
+ if (lruvec) {
+ if (nid == first_memory_node) {
+#ifdef CONFIG_MEMCG
+ if (memcg)
+ cgroup_path(memcg->css.cgroup, path, PATH_MAX);
+ else
+ path[0] = 0;
+#endif
+ buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len,
+ "memcg %5hu %s\n", mem_cgroup_id(memcg), path);
+ }
+
+ buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len,
+ " node %5d\n", nid);
+ buf_len += print_node_mglru(lruvec, buf, buf_len);
+ }
+ }
+ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)));
+
+ if (buf_len >= PAGE_SIZE)
+ buf_len = PAGE_SIZE - 1;
+ buf[buf_len] = 0;
+
+ kvfree(path);
+
+ return buf_len;
+}
+
+static ssize_t store_lru_gen_admin(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *src, size_t len)
+{
+ void *buf;
+ char *cur, *next;
+ int err = 0;
+ struct scan_control sc = {
+ .may_writepage = true,
+ .may_unmap = true,
+ .may_swap = true,
+ .reclaim_idx = MAX_NR_ZONES - 1,
+ .gfp_mask = GFP_KERNEL,
+ };
+
+ buf = kvmalloc(len + 1, GFP_USER);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf, src, len);
+
+ next = buf;
+ next[len] = '\0';
+
+ while ((cur = strsep(&next, ",;\n"))) {
+ int n;
+ int end;
+ char cmd;
+ unsigned int memcg_id;
+ unsigned int nid;
+ unsigned long seq;
+ unsigned int swappiness = -1;
+ unsigned long nr_to_reclaim = -1;
+
+ cur = skip_spaces(cur);
+ if (!*cur)
+ continue;
+
+ n = sscanf(cur, "%c %u %u %lu %n %u %n %lu %n", &cmd, &memcg_id, &nid,
+ &seq, &end, &swappiness, &end, &nr_to_reclaim, &end);
+ if (n < 4 || cur[end]) {
+ err = -EINVAL;
+ break;
+ }
+
+ err = run_cmd(cmd, memcg_id, nid, seq, &sc, swappiness, nr_to_reclaim);
+ if (err)
+ break;
+ }
+
+ kvfree(buf);
+
+ return err ? : len;
+}
+
+static struct kobj_attribute lru_gen_admin_attr = __ATTR(
+ admin, 0644, show_lru_gen_admin, store_lru_gen_admin
+);
+
static struct attribute *lru_gen_attrs[] = {
&lru_gen_min_ttl_attr.attr,
&lru_gen_enabled_attr.attr,
+ &lru_gen_admin_attr.attr,
NULL
};
--
2.38.3