xref: /openbmc/linux/fs/drop_caches.c (revision 384740dc)
1 /*
2  * Implement the manual drop-all-pagecache function
3  */
4 
5 #include <linux/kernel.h>
6 #include <linux/mm.h>
7 #include <linux/fs.h>
8 #include <linux/writeback.h>
9 #include <linux/sysctl.h>
10 #include <linux/gfp.h>
11 
12 /* A global variable is a bit ugly, but it keeps the code simple */
13 int sysctl_drop_caches;
14 
15 static void drop_pagecache_sb(struct super_block *sb)
16 {
17 	struct inode *inode, *toput_inode = NULL;
18 
19 	spin_lock(&inode_lock);
20 	list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
21 		if (inode->i_state & (I_FREEING|I_WILL_FREE))
22 			continue;
23 		if (inode->i_mapping->nrpages == 0)
24 			continue;
25 		__iget(inode);
26 		spin_unlock(&inode_lock);
27 		__invalidate_mapping_pages(inode->i_mapping, 0, -1, true);
28 		iput(toput_inode);
29 		toput_inode = inode;
30 		spin_lock(&inode_lock);
31 	}
32 	spin_unlock(&inode_lock);
33 	iput(toput_inode);
34 }
35 
36 static void drop_pagecache(void)
37 {
38 	struct super_block *sb;
39 
40 	spin_lock(&sb_lock);
41 restart:
42 	list_for_each_entry(sb, &super_blocks, s_list) {
43 		sb->s_count++;
44 		spin_unlock(&sb_lock);
45 		down_read(&sb->s_umount);
46 		if (sb->s_root)
47 			drop_pagecache_sb(sb);
48 		up_read(&sb->s_umount);
49 		spin_lock(&sb_lock);
50 		if (__put_super_and_need_restart(sb))
51 			goto restart;
52 	}
53 	spin_unlock(&sb_lock);
54 }
55 
56 static void drop_slab(void)
57 {
58 	int nr_objects;
59 
60 	do {
61 		nr_objects = shrink_slab(1000, GFP_KERNEL, 1000);
62 	} while (nr_objects > 10);
63 }
64 
65 int drop_caches_sysctl_handler(ctl_table *table, int write,
66 	struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
67 {
68 	proc_dointvec_minmax(table, write, file, buffer, length, ppos);
69 	if (write) {
70 		if (sysctl_drop_caches & 1)
71 			drop_pagecache();
72 		if (sysctl_drop_caches & 2)
73 			drop_slab();
74 	}
75 	return 0;
76 }
77