2006-01-08 12:00:39 +03:00
/*
* Implement the manual drop - all - pagecache function
*/
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/fs.h>
# include <linux/writeback.h>
# include <linux/sysctl.h>
# include <linux/gfp.h>
2011-03-22 14:23:40 +03:00
# include "internal.h"
2006-01-08 12:00:39 +03:00
/* A global variable is a bit ugly, but it keeps the code simple */
int sysctl_drop_caches ;
2010-03-23 13:06:58 +03:00
static void drop_pagecache_sb ( struct super_block * sb , void * unused )
2006-01-08 12:00:39 +03:00
{
2008-04-29 11:59:37 +04:00
struct inode * inode , * toput_inode = NULL ;
2006-01-08 12:00:39 +03:00
2011-03-22 14:23:40 +03:00
spin_lock ( & inode_sb_list_lock ) ;
2006-01-08 12:00:39 +03:00
list_for_each_entry ( inode , & sb - > s_inodes , i_sb_list ) {
2011-03-22 14:23:36 +03:00
spin_lock ( & inode - > i_lock ) ;
if ( ( inode - > i_state & ( I_FREEING | I_WILL_FREE | I_NEW ) ) | |
( inode - > i_mapping - > nrpages = = 0 ) ) {
spin_unlock ( & inode - > i_lock ) ;
2008-04-29 11:59:39 +04:00
continue ;
2011-03-22 14:23:36 +03:00
}
2008-04-29 11:59:37 +04:00
__iget ( inode ) ;
2011-03-22 14:23:36 +03:00
spin_unlock ( & inode - > i_lock ) ;
2011-03-22 14:23:40 +03:00
spin_unlock ( & inode_sb_list_lock ) ;
2009-06-17 02:32:59 +04:00
invalidate_mapping_pages ( inode - > i_mapping , 0 , - 1 ) ;
2008-04-29 11:59:37 +04:00
iput ( toput_inode ) ;
toput_inode = inode ;
2011-03-22 14:23:40 +03:00
spin_lock ( & inode_sb_list_lock ) ;
2006-01-08 12:00:39 +03:00
}
2011-03-22 14:23:40 +03:00
spin_unlock ( & inode_sb_list_lock ) ;
2008-04-29 11:59:37 +04:00
iput ( toput_inode ) ;
2006-01-08 12:00:39 +03:00
}
2008-04-29 11:58:57 +04:00
static void drop_slab ( void )
2006-01-08 12:00:39 +03:00
{
int nr_objects ;
2011-05-25 04:12:26 +04:00
struct shrink_control shrink = {
. gfp_mask = GFP_KERNEL ,
} ;
2006-01-08 12:00:39 +03:00
2013-08-28 04:18:03 +04:00
nodes_setall ( shrink . nodes_to_scan ) ;
2006-01-08 12:00:39 +03:00
do {
2011-05-25 04:12:27 +04:00
nr_objects = shrink_slab ( & shrink , 1000 , 1000 ) ;
2006-01-08 12:00:39 +03:00
} while ( nr_objects > 10 ) ;
}
2014-06-07 01:38:05 +04:00
int drop_caches_sysctl_handler ( struct ctl_table * table , int write ,
2009-09-24 02:57:19 +04:00
void __user * buffer , size_t * length , loff_t * ppos )
2006-01-08 12:00:39 +03:00
{
2011-03-24 02:43:09 +03:00
int ret ;
ret = proc_dointvec_minmax ( table , write , buffer , length , ppos ) ;
if ( ret )
return ret ;
2006-01-08 12:00:39 +03:00
if ( write ) {
2014-04-04 01:48:19 +04:00
static int stfu ;
if ( sysctl_drop_caches & 1 ) {
2010-03-23 13:06:58 +03:00
iterate_supers ( drop_pagecache_sb , NULL ) ;
2014-04-04 01:48:19 +04:00
count_vm_event ( DROP_PAGECACHE ) ;
}
if ( sysctl_drop_caches & 2 ) {
2006-01-08 12:00:39 +03:00
drop_slab ( ) ;
2014-04-04 01:48:19 +04:00
count_vm_event ( DROP_SLAB ) ;
}
if ( ! stfu ) {
pr_info ( " %s (%d): drop_caches: %d \n " ,
current - > comm , task_pid_nr ( current ) ,
sysctl_drop_caches ) ;
}
stfu | = sysctl_drop_caches & 4 ;
2006-01-08 12:00:39 +03:00
}
return 0 ;
}