Signed-off-by: Li Wang <liw...@ubuntukylin.com>
Signed-off-by: Yunchuan Wen <yunchuan...@ubuntukylin.com>
---
 fs/drop_caches.c |   45 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 37 insertions(+), 8 deletions(-)

diff --git a/fs/drop_caches.c b/fs/drop_caches.c
index 9fd702f..ab31393 100644
--- a/fs/drop_caches.c
+++ b/fs/drop_caches.c
@@ -8,10 +8,11 @@
 #include <linux/writeback.h>
 #include <linux/sysctl.h>
 #include <linux/gfp.h>
+#include <linux/fs_struct.h>
 #include "internal.h"
 
 /* A global variable is a bit ugly, but it keeps the code simple */
-int sysctl_drop_caches;
+char sysctl_drop_caches[PATH_MAX];
 
 static void drop_pagecache_sb(struct super_block *sb, void *unused)
 {
@@ -54,15 +55,43 @@ int drop_caches_sysctl_handler(ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
        int ret;
+       int command;
+       struct path path;
+       struct path root;
 
-       ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
-       if (ret)
-               return ret;
-       if (write) {
-               if (sysctl_drop_caches & 1)
+       ret = proc_dostring(table, write, buffer, length, ppos);
+       if (ret || !write)
+               goto out;
+       ret = -EINVAL;
+       command = sysctl_drop_caches[0] - '0';
+       if (command < 1 || command > 3)
+               goto out;
+       if (sysctl_drop_caches[1] == '\0') {
+               if (command & 1)
                        iterate_supers(drop_pagecache_sb, NULL);
-               if (sysctl_drop_caches & 2)
+               if (command & 2)
                        drop_slab();
+               ret = 0;
+               goto out;
        }
-       return 0;
+       if (sysctl_drop_caches[1] != ':' || sysctl_drop_caches[2] == '\0')
+               goto out;
+       if (sysctl_drop_caches[2] == '/')
+               get_fs_root(current->fs, &root);
+       else
+               get_fs_pwd(current->fs, &root);
+       ret = vfs_path_lookup(root.dentry, root.mnt,
+               &sysctl_drop_caches[2], 0, &path);
+       path_put(&root);
+       if (ret)
+               goto out;
+       if (command & 1)
+               shrink_pagecache_parent(path.dentry);
+       if (command & 2)
+               shrink_dcache_parent(path.dentry);
+       path_put(&path);
+out:
+       if (ret)
+               memset(sysctl_drop_caches, 0, PATH_MAX);
+       return ret;
 }
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to