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 ;
static void drop_pagecache_sb ( struct super_block * sb )
{
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 ) {
if ( inode - > i_state & ( I_FREEING | I_WILL_FREE ) )
continue ;
2008-04-29 11:59:39 +04:00
if ( inode - > i_mapping - > nrpages = = 0 )
continue ;
2008-04-29 11:59:37 +04:00
__iget ( inode ) ;
spin_unlock ( & inode_lock ) ;
2007-07-16 10:38:14 +04:00
__invalidate_mapping_pages ( inode - > i_mapping , 0 , - 1 , true ) ;
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_pagecache ( void )
2006-01-08 12:00:39 +03:00
{
struct super_block * sb ;
spin_lock ( & sb_lock ) ;
restart :
list_for_each_entry ( sb , & super_blocks , s_list ) {
sb - > s_count + + ;
spin_unlock ( & sb_lock ) ;
down_read ( & sb - > s_umount ) ;
if ( sb - > s_root )
drop_pagecache_sb ( sb ) ;
up_read ( & sb - > s_umount ) ;
spin_lock ( & sb_lock ) ;
if ( __put_super_and_need_restart ( sb ) )
goto restart ;
}
spin_unlock ( & sb_lock ) ;
}
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 ,
struct file * file , void __user * buffer , size_t * length , loff_t * ppos )
{
proc_dointvec_minmax ( table , write , file , buffer , length , ppos ) ;
if ( write ) {
if ( sysctl_drop_caches & 1 )
drop_pagecache ( ) ;
if ( sysctl_drop_caches & 2 )
drop_slab ( ) ;
}
return 0 ;
}