[PATCH] drop page cache of a single file

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <[email protected]>

---

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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux