[PATCH] drop page cache of a single file

From: Zhang, Yanmin
Date: Wed Dec 27 2006 - 22:20:41 EST


Currently, by /proc/sys/vm/drop_caches, applications could drop pagecache,
slab(dentries and inodes), or both, but applications couldn't choose to
just drop the page cache of one file. An user of VOD (Video-On-Demand)
needs this capability to have more detailed control on page cache release.

Below patch against 2.6.19 implements it.

Signed-off-by: Zhang Yanmin <yanmin.zhang@xxxxxxxxx>

---

diff -Nraup linux-2.6.19/Documentation/filesystems/proc.txt linux-2.6.19_dropcache/Documentation/filesystems/proc.txt
--- linux-2.6.19/Documentation/filesystems/proc.txt 2006-12-08 15:32:44.000000000 +0800
+++ linux-2.6.19_dropcache/Documentation/filesystems/proc.txt 2006-12-28 10:20:39.000000000 +0800
@@ -1320,6 +1320,8 @@ To free dentries and inodes:
echo 2 > /proc/sys/vm/drop_caches
To free pagecache, dentries and inodes:
echo 3 > /proc/sys/vm/drop_caches
+To free the pagecache of one file:
+ echo "4 /path/to/filename" > /proc/sys/vm/drop_caches

As this is a non-destructive operation and dirty objects are not freeable, the
user should run `sync' first.
diff -Nraup linux-2.6.19/fs/drop_caches.c linux-2.6.19_dropcache/fs/drop_caches.c
--- linux-2.6.19/fs/drop_caches.c 2006-12-08 15:31:58.000000000 +0800
+++ linux-2.6.19_dropcache/fs/drop_caches.c 2006-12-28 11:04:22.000000000 +0800
@@ -8,9 +8,9 @@
#include <linux/writeback.h>
#include <linux/sysctl.h>
#include <linux/gfp.h>
+#include <linux/namei.h>

-/* A global variable is a bit ugly, but it keeps the code simple */
-int sysctl_drop_caches;
+char sysctl_drop_caches[PATH_MAX+2];

static void drop_pagecache_sb(struct super_block *sb)
{
@@ -54,15 +54,70 @@ void drop_slab(void)
} while (nr_objects > 10);
}

+void drop_file_pagecache(char *path)
+{
+ struct inode *inode;
+ struct nameidata nd;
+ int error;
+
+ if (!path || !*path)
+ return;
+
+ error = path_lookup(path, LOOKUP_FOLLOW, &nd);
+ if (error)
+ return;
+
+ inode = nd.dentry->d_inode;
+ if (!(inode->i_state & (I_FREEING|I_WILL_FREE)))
+ invalidate_inode_pages(inode->i_mapping);
+ path_release(&nd);
+
+ return;
+}
+
int drop_caches_sysctl_handler(ctl_table *table, int write,
struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
{
- proc_dointvec_minmax(table, write, file, buffer, length, ppos);
- if (write) {
- if (sysctl_drop_caches & 1)
+ int error;
+ char *path;
+ int operation;
+
+ error = proc_dostring(table, write, file, buffer, length, ppos);
+ if (write && !error) {
+ sscanf(sysctl_drop_caches, "%d", &operation);
+
+ switch (operation) {
+ case 1:
drop_pagecache();
- if (sysctl_drop_caches & 2)
+ break;
+ case 2:
drop_slab();
+ break;
+ case 3:
+ drop_pagecache();
+ drop_slab();
+ break;
+ case 4:
+ /*
+ * The format in sysctl_drop_caches is:
+ * 4 /path/to/filename
+ */
+ path = strchr(sysctl_drop_caches, '4');
+ if (!path)
+ break;
+
+ path ++;
+ while (*path) {
+ if (*path == ' ' || *path == '\t')
+ path ++;
+ else
+ break;
+ }
+
+ drop_file_pagecache(path);
+ break;
+ }
}
return 0;
}
+
diff -Nraup linux-2.6.19/include/linux/mm.h linux-2.6.19_dropcache/include/linux/mm.h
--- linux-2.6.19/include/linux/mm.h 2006-12-08 15:32:49.000000000 +0800
+++ linux-2.6.19_dropcache/include/linux/mm.h 2006-12-28 09:59:10.000000000 +0800
@@ -1121,6 +1121,7 @@ unsigned long shrink_slab(unsigned long
unsigned long lru_pages);
void drop_pagecache(void);
void drop_slab(void);
+void drop_file_pagecache(char *path);

#ifndef CONFIG_MMU
#define randomize_va_space 0
diff -Nraup linux-2.6.19/kernel/sysctl.c linux-2.6.19_dropcache/kernel/sysctl.c
--- linux-2.6.19/kernel/sysctl.c 2006-12-08 15:32:49.000000000 +0800
+++ linux-2.6.19_dropcache/kernel/sysctl.c 2006-12-28 09:50:18.000000000 +0800
@@ -73,7 +73,7 @@ extern int min_free_kbytes;
extern int printk_ratelimit_jiffies;
extern int printk_ratelimit_burst;
extern int pid_max_min, pid_max_max;
-extern int sysctl_drop_caches;
+extern char sysctl_drop_caches[PATH_MAX+2];
extern int percpu_pagelist_fraction;
extern int compat_log;

@@ -901,10 +901,10 @@ static ctl_table vm_table[] = {
.ctl_name = VM_DROP_PAGECACHE,
.procname = "drop_caches",
.data = &sysctl_drop_caches,
- .maxlen = sizeof(int),
+ .maxlen = sizeof(sysctl_drop_caches),
.mode = 0644,
.proc_handler = drop_caches_sysctl_handler,
- .strategy = &sysctl_intvec,
+ .strategy = &sysctl_string,
},
{
.ctl_name = VM_MIN_FREE_KBYTES,
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/