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>
/* 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
spin_lock ( & inode_lock ) ;
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 ) ;
2008-04-29 11:59:37 +04:00
spin_unlock ( & inode_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 ;
spin_lock ( & inode_lock ) ;
2006-01-08 12:00:39 +03:00
}
spin_unlock ( & inode_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 ;
do {
nr_objects = shrink_slab ( 1000 , GFP_KERNEL , 1000 ) ;
} while ( nr_objects > 10 ) ;
}
int drop_caches_sysctl_handler ( 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 ) {
if ( sysctl_drop_caches & 1 )
2010-03-23 13:06:58 +03:00
iterate_supers ( drop_pagecache_sb , NULL ) ;
2006-01-08 12:00:39 +03:00
if ( sysctl_drop_caches & 2 )
drop_slab ( ) ;
}
return 0 ;
}