[PATCH 2/3] sysctl: add support for drop_caches for individual filesystem

From: Ye Bin
Date: Thu Oct 10 2024 - 07:12:19 EST


From: Ye Bin <yebin10@xxxxxxxxxx>

In order to better analyze the issue of file system uninstallation caused
by kernel module opening files, it is necessary to perform dentry recycling
on a single file system. But now, apart from global dentry recycling, it is
not supported to do dentry recycling on a single file system separately.
This feature has usage scenarios in problem localization scenarios.At the
same time, it also provides users with a slightly fine-grained
pagecache/entry recycling mechanism.
This patch supports the recycling of pagecache/entry for individual file
systems.

Signed-off-by: Ye Bin <yebin10@xxxxxxxxxx>
---
fs/drop_caches.c | 43 +++++++++++++++++++++++++++++++++++++++++++
include/linux/mm.h | 2 ++
kernel/sysctl.c | 9 +++++++++
3 files changed, 54 insertions(+)

diff --git a/fs/drop_caches.c b/fs/drop_caches.c
index d45ef541d848..99d412cf3e52 100644
--- a/fs/drop_caches.c
+++ b/fs/drop_caches.c
@@ -77,3 +77,46 @@ int drop_caches_sysctl_handler(const struct ctl_table *table, int write,
}
return 0;
}
+
+int drop_fs_caches_sysctl_handler(const struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos)
+{
+ unsigned int major, minor;
+ unsigned int ctl;
+ struct super_block *sb;
+ static int stfu;
+
+ if (!write)
+ return 0;
+
+ if (sscanf(buffer, "%u:%u:%u", &major, &minor, &ctl) != 3)
+ return -EINVAL;
+
+ if (ctl < *((int *)table->extra1) || ctl > *((int *)table->extra2))
+ return -EINVAL;
+
+ sb = user_get_super(MKDEV(major, minor), false);
+ if (!sb)
+ return -EINVAL;
+
+ if (ctl & 1) {
+ lru_add_drain_all();
+ drop_pagecache_sb(sb, NULL);
+ count_vm_event(DROP_PAGECACHE);
+ }
+
+ if (ctl & 2) {
+ shrink_dcache_sb(sb);
+ shrink_icache_sb(sb);
+ count_vm_event(DROP_SLAB);
+ }
+
+ drop_super(sb);
+
+ if (!stfu)
+ pr_info("%s (%d): drop_fs_caches: %u:%u:%d\n", current->comm,
+ task_pid_nr(current), major, minor, ctl);
+ stfu |= ctl & 4;
+
+ return 0;
+}
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 344541f8cba0..43079478296f 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3788,6 +3788,8 @@ extern bool process_shares_mm(struct task_struct *p, struct mm_struct *mm);
extern int sysctl_drop_caches;
int drop_caches_sysctl_handler(const struct ctl_table *, int, void *, size_t *,
loff_t *);
+int drop_fs_caches_sysctl_handler(const struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos);
#endif

void drop_slab(void);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 79e6cb1d5c48..d434cbe10e47 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2101,6 +2101,15 @@ static struct ctl_table vm_table[] = {
.extra1 = SYSCTL_ONE,
.extra2 = SYSCTL_FOUR,
},
+ {
+ .procname = "drop_fs_caches",
+ .data = NULL,
+ .maxlen = 256,
+ .mode = 0200,
+ .proc_handler = drop_fs_caches_sysctl_handler,
+ .extra1 = SYSCTL_ONE,
+ .extra2 = SYSCTL_FOUR,
+ },
{
.procname = "page_lock_unfairness",
.data = &sysctl_page_lock_unfairness,
--
2.31.1