To clean the page cache one can use /proc/sys/vm/drop_caches. But this drops the whole page cache. In contrast to that sdrop_caches enables ability to drop the page cache selectively by path string. Suggested-by: Thomas Knauth <thomas.knauth@xxxxxx> Signed-off-by: Maksym Planeta <mcsim.planeta@xxxxxxxxx> --- Documentation/sysctl/vm.txt | 15 ++++++ fs/Makefile | 2 +- fs/sdrop_caches.c | 124 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 fs/sdrop_caches.c diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index bd4b34c..faad01d 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -28,6 +28,7 @@ Currently, these files are in /proc/sys/vm: - dirty_ratio - dirty_writeback_centisecs - drop_caches +- sdrop_caches - extfrag_threshold - hugepages_treat_as_movable - hugetlb_shm_group @@ -211,6 +212,20 @@ with your system. To disable them, echo 4 (bit 3) into drop_caches. ============================================================== +sdrop_caches + +Writing to this will cause the kernel to drop clean caches starting from +specified path. + +To free pagecache of a file: + echo /home/user/file > /proc/sys/vm/sdrop_caches +To free pagecache of a directory and all files in it. + echo /home/user/directly > /proc/sys/vm/sdrop_caches + +Restrictions are the same as for drop_caches. + +============================================================== + extfrag_threshold This parameter affects whether the kernel will compact memory or direct diff --git a/fs/Makefile b/fs/Makefile index 4030cbf..366c7b9 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -44,7 +44,7 @@ obj-$(CONFIG_FS_MBCACHE) += mbcache.o obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o obj-$(CONFIG_NFS_COMMON) += nfs_common/ obj-$(CONFIG_COREDUMP) += coredump.o -obj-$(CONFIG_SYSCTL) += drop_caches.o +obj-$(CONFIG_SYSCTL) += drop_caches.o sdrop_caches.o obj-$(CONFIG_FHANDLE) += fhandle.o diff --git a/fs/sdrop_caches.c b/fs/sdrop_caches.c new file mode 100644 index 0000000..c193655 --- /dev/null +++ b/fs/sdrop_caches.c @@ -0,0 +1,124 @@ +/* + * Implement the manual selective drop pagecache function + */ + +#include <linux/module.h> + + +#include <linux/kernel.h> +#include <linux/proc_fs.h> +#include <linux/string.h> +#include <linux/vmalloc.h> +#include <linux/uaccess.h> +#include <linux/mm.h> +#include <linux/fs.h> +#include <linux/writeback.h> +#include <linux/sysctl.h> +#include <linux/gfp.h> +#include <linux/limits.h> +#include <linux/namei.h> + +static void clean_mapping(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + + if (!inode) + return; + + if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || + (inode->i_mapping->nrpages == 0)) { + return; + } + + invalidate_mapping_pages(inode->i_mapping, 0, -1); +} + +static void clean_all_dentries_locked(struct dentry *dentry) +{ + struct dentry *child; + + list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { + clean_all_dentries_locked(child); + } + + clean_mapping(dentry); +} + +static void clean_all_dentries(struct dentry *dentry) +{ + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); + clean_all_dentries_locked(dentry); + spin_unlock(&dentry->d_lock); +} + +static int drop_pagecache(const char * __user filename) +{ + unsigned int lookup_flags = LOOKUP_FOLLOW; + struct path path; + int error; + +retry: + error = user_path_at(AT_FDCWD, filename, lookup_flags, &path); + if (!error) { + /* clean */ + clean_all_dentries(path.dentry); + } + if (retry_estale(error, lookup_flags)) { + lookup_flags |= LOOKUP_REVAL; + goto retry; + } + return error; +} + +static int sdrop_ctl_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + char __user *pathname = buffer + *lenp - 1; + + put_user('\0', pathname); + + if (!write) + return 0; + + return drop_pagecache(buffer); +} + +static struct ctl_path vm_path[] = { { .procname = "vm", }, { } }; +static struct ctl_table sdrop_ctl_table[] = { + { + .procname = "sdrop_caches", + .mode = 0644, + .proc_handler = sdrop_ctl_handler, + }, + { } +}; + +static struct ctl_table_header *sdrop_proc_entry; + +/* Init function called on module entry */ +int sdrop_init(void) +{ + int ret = 0; + + sdrop_proc_entry = register_sysctl_paths(vm_path, sdrop_ctl_table); + + if (sdrop_proc_entry == NULL) { + ret = -ENOMEM; + pr_err("sdrop_caches: Couldn't create proc entry\n"); + } + + return ret; +} + +/* Cleanup function called on module exit */ +void sdrop_cleanup(void) +{ + unregister_sysctl_table(sdrop_proc_entry); +} + +module_init(sdrop_init); +module_exit(sdrop_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Selective pagecache drop module"); +MODULE_AUTHOR("Maksym Planeta"); -- 2.0.0 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html