Commit | Line | Data |
---|---|---|
9d0243bc AM |
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> | |
35cf7ba0 | 11 | #include "internal.h" |
9d0243bc AM |
12 | |
13 | /* A global variable is a bit ugly, but it keeps the code simple */ | |
14 | int sysctl_drop_caches; | |
15 | ||
16 | static void drop_pagecache_sb(struct super_block *sb) | |
17 | { | |
eccb95ce | 18 | struct inode *inode, *toput_inode = NULL; |
9d0243bc AM |
19 | |
20 | spin_lock(&inode_lock); | |
21 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | |
b6fac63c | 22 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) |
9d0243bc | 23 | continue; |
af065b8a JK |
24 | if (inode->i_mapping->nrpages == 0) |
25 | continue; | |
eccb95ce JK |
26 | __iget(inode); |
27 | spin_unlock(&inode_lock); | |
28697355 | 28 | invalidate_mapping_pages(inode->i_mapping, 0, -1); |
eccb95ce JK |
29 | iput(toput_inode); |
30 | toput_inode = inode; | |
31 | spin_lock(&inode_lock); | |
9d0243bc AM |
32 | } |
33 | spin_unlock(&inode_lock); | |
eccb95ce | 34 | iput(toput_inode); |
9d0243bc AM |
35 | } |
36 | ||
07d45da6 | 37 | static void drop_pagecache(void) |
9d0243bc | 38 | { |
6754af64 | 39 | struct super_block *sb, *n; |
9d0243bc AM |
40 | |
41 | spin_lock(&sb_lock); | |
6754af64 | 42 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { |
551de6f3 AV |
43 | if (list_empty(&sb->s_instances)) |
44 | continue; | |
9d0243bc AM |
45 | sb->s_count++; |
46 | spin_unlock(&sb_lock); | |
47 | down_read(&sb->s_umount); | |
48 | if (sb->s_root) | |
49 | drop_pagecache_sb(sb); | |
50 | up_read(&sb->s_umount); | |
51 | spin_lock(&sb_lock); | |
6754af64 | 52 | __put_super(sb); |
9d0243bc AM |
53 | } |
54 | spin_unlock(&sb_lock); | |
55 | } | |
56 | ||
07d45da6 | 57 | static void drop_slab(void) |
9d0243bc AM |
58 | { |
59 | int nr_objects; | |
60 | ||
61 | do { | |
62 | nr_objects = shrink_slab(1000, GFP_KERNEL, 1000); | |
63 | } while (nr_objects > 10); | |
64 | } | |
65 | ||
66 | int drop_caches_sysctl_handler(ctl_table *table, int write, | |
8d65af78 | 67 | void __user *buffer, size_t *length, loff_t *ppos) |
9d0243bc | 68 | { |
8d65af78 | 69 | proc_dointvec_minmax(table, write, buffer, length, ppos); |
9d0243bc AM |
70 | if (write) { |
71 | if (sysctl_drop_caches & 1) | |
72 | drop_pagecache(); | |
73 | if (sysctl_drop_caches & 2) | |
74 | drop_slab(); | |
75 | } | |
76 | return 0; | |
77 | } |