2009-04-03 16:42:36 +01:00
/* General filesystem local caching manager
*
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# define FSCACHE_DEBUG_LEVEL CACHE
# include <linux/module.h>
# include <linux/init.h>
# include <linux/sched.h>
# include <linux/completion.h>
# include <linux/slab.h>
2010-07-20 22:09:01 +02:00
# include <linux/seq_file.h>
2009-04-03 16:42:36 +01:00
# include "internal.h"
MODULE_DESCRIPTION ( " FS Cache Manager " ) ;
MODULE_AUTHOR ( " Red Hat, Inc. " ) ;
MODULE_LICENSE ( " GPL " ) ;
unsigned fscache_defer_lookup = 1 ;
module_param_named ( defer_lookup , fscache_defer_lookup , uint ,
S_IWUSR | S_IRUGO ) ;
MODULE_PARM_DESC ( fscache_defer_lookup ,
" Defer cookie lookup to background thread " ) ;
unsigned fscache_defer_create = 1 ;
module_param_named ( defer_create , fscache_defer_create , uint ,
S_IWUSR | S_IRUGO ) ;
MODULE_PARM_DESC ( fscache_defer_create ,
" Defer cookie creation to background thread " ) ;
unsigned fscache_debug ;
module_param_named ( debug , fscache_debug , uint ,
S_IWUSR | S_IRUGO ) ;
MODULE_PARM_DESC ( fscache_debug ,
" FS-Cache debugging mask " ) ;
struct kobject * fscache_root ;
2010-07-20 22:09:01 +02:00
struct workqueue_struct * fscache_object_wq ;
2010-07-20 22:09:01 +02:00
struct workqueue_struct * fscache_op_wq ;
2010-07-20 22:09:01 +02:00
DEFINE_PER_CPU ( wait_queue_head_t , fscache_object_cong_wait ) ;
/* these values serve as lower bounds, will be adjusted in fscache_init() */
static unsigned fscache_object_max_active = 4 ;
2010-07-20 22:09:01 +02:00
static unsigned fscache_op_max_active = 2 ;
2010-07-20 22:09:01 +02:00
# ifdef CONFIG_SYSCTL
static struct ctl_table_header * fscache_sysctl_header ;
static int fscache_max_active_sysctl ( struct ctl_table * table , int write ,
void __user * buffer ,
size_t * lenp , loff_t * ppos )
{
struct workqueue_struct * * wqp = table - > extra1 ;
unsigned int * datap = table - > data ;
int ret ;
ret = proc_dointvec ( table , write , buffer , lenp , ppos ) ;
if ( ret = = 0 )
workqueue_set_max_active ( * wqp , * datap ) ;
return ret ;
}
ctl_table fscache_sysctls [ ] = {
{
. procname = " object_max_active " ,
. data = & fscache_object_max_active ,
. maxlen = sizeof ( unsigned ) ,
. mode = 0644 ,
. proc_handler = fscache_max_active_sysctl ,
. extra1 = & fscache_object_wq ,
} ,
2010-07-20 22:09:01 +02:00
{
. procname = " operation_max_active " ,
. data = & fscache_op_max_active ,
. maxlen = sizeof ( unsigned ) ,
. mode = 0644 ,
. proc_handler = fscache_max_active_sysctl ,
. extra1 = & fscache_op_wq ,
} ,
2010-07-20 22:09:01 +02:00
{ }
} ;
ctl_table fscache_sysctls_root [ ] = {
{
. procname = " fscache " ,
. mode = 0555 ,
. child = fscache_sysctls ,
} ,
{ }
} ;
# endif
2009-04-03 16:42:36 +01:00
/*
* initialise the fs caching module
*/
static int __init fscache_init ( void )
{
2010-07-20 22:09:01 +02:00
unsigned int nr_cpus = num_possible_cpus ( ) ;
unsigned int cpu ;
2009-04-03 16:42:36 +01:00
int ret ;
2010-07-20 22:09:01 +02:00
fscache_object_max_active =
clamp_val ( nr_cpus ,
fscache_object_max_active , WQ_UNBOUND_MAX_ACTIVE ) ;
ret = - ENOMEM ;
fscache_object_wq = alloc_workqueue ( " fscache_object " , WQ_UNBOUND ,
fscache_object_max_active ) ;
if ( ! fscache_object_wq )
goto error_object_wq ;
2010-07-20 22:09:01 +02:00
fscache_op_max_active =
clamp_val ( fscache_object_max_active / 2 ,
fscache_op_max_active , WQ_UNBOUND_MAX_ACTIVE ) ;
ret = - ENOMEM ;
fscache_op_wq = alloc_workqueue ( " fscache_operation " , WQ_UNBOUND ,
fscache_op_max_active ) ;
if ( ! fscache_op_wq )
goto error_op_wq ;
2010-07-20 22:09:01 +02:00
for_each_possible_cpu ( cpu )
init_waitqueue_head ( & per_cpu ( fscache_object_cong_wait , cpu ) ) ;
2009-04-03 16:42:37 +01:00
ret = fscache_proc_init ( ) ;
if ( ret < 0 )
goto error_proc ;
2010-07-20 22:09:01 +02:00
# ifdef CONFIG_SYSCTL
ret = - ENOMEM ;
fscache_sysctl_header = register_sysctl_table ( fscache_sysctls_root ) ;
if ( ! fscache_sysctl_header )
goto error_sysctl ;
# endif
2009-04-03 16:42:38 +01:00
fscache_cookie_jar = kmem_cache_create ( " fscache_cookie_jar " ,
sizeof ( struct fscache_cookie ) ,
0 ,
0 ,
fscache_cookie_init_once ) ;
if ( ! fscache_cookie_jar ) {
printk ( KERN_NOTICE
" FS-Cache: Failed to allocate a cookie jar \n " ) ;
ret = - ENOMEM ;
goto error_cookie_jar ;
}
2009-04-03 16:42:37 +01:00
fscache_root = kobject_create_and_add ( " fscache " , kernel_kobj ) ;
if ( ! fscache_root )
goto error_kobj ;
2009-04-03 16:42:36 +01:00
printk ( KERN_NOTICE " FS-Cache: Loaded \n " ) ;
return 0 ;
2009-04-03 16:42:37 +01:00
error_kobj :
2009-04-03 16:42:38 +01:00
kmem_cache_destroy ( fscache_cookie_jar ) ;
error_cookie_jar :
2010-07-20 22:09:01 +02:00
# ifdef CONFIG_SYSCTL
unregister_sysctl_table ( fscache_sysctl_header ) ;
error_sysctl :
# endif
2009-04-03 16:42:37 +01:00
fscache_proc_cleanup ( ) ;
2009-04-03 16:42:37 +01:00
error_proc :
2010-07-20 22:09:01 +02:00
destroy_workqueue ( fscache_op_wq ) ;
error_op_wq :
2010-07-20 22:09:01 +02:00
destroy_workqueue ( fscache_object_wq ) ;
error_object_wq :
2009-04-03 16:42:36 +01:00
return ret ;
}
fs_initcall ( fscache_init ) ;
/*
* clean up on module removal
*/
static void __exit fscache_exit ( void )
{
_enter ( " " ) ;
2009-04-03 16:42:37 +01:00
kobject_put ( fscache_root ) ;
2009-04-03 16:42:38 +01:00
kmem_cache_destroy ( fscache_cookie_jar ) ;
2010-07-24 11:10:09 +02:00
# ifdef CONFIG_SYSCTL
2010-07-20 22:09:01 +02:00
unregister_sysctl_table ( fscache_sysctl_header ) ;
2010-07-24 11:10:09 +02:00
# endif
2009-04-03 16:42:37 +01:00
fscache_proc_cleanup ( ) ;
2010-07-20 22:09:01 +02:00
destroy_workqueue ( fscache_op_wq ) ;
2010-07-20 22:09:01 +02:00
destroy_workqueue ( fscache_object_wq ) ;
2009-04-03 16:42:36 +01:00
printk ( KERN_NOTICE " FS-Cache: Unloaded \n " ) ;
}
module_exit ( fscache_exit ) ;
2009-04-03 16:42:38 +01:00
/*
* wait_on_bit ( ) sleep function for uninterruptible waiting
*/
int fscache_wait_bit ( void * flags )
{
schedule ( ) ;
return 0 ;
}
EXPORT_SYMBOL ( fscache_wait_bit ) ;
/*
* wait_on_bit ( ) sleep function for interruptible waiting
*/
int fscache_wait_bit_interruptible ( void * flags )
{
schedule ( ) ;
return signal_pending ( current ) ;
}
EXPORT_SYMBOL ( fscache_wait_bit_interruptible ) ;