2005-04-17 02:20:36 +04:00
/*
* linux / net / sunrpc / sched . c
*
* Scheduling for synchronous and asynchronous RPC requests .
*
* Copyright ( C ) 1996 Olaf Kirch , < okir @ monad . swb . de >
2007-02-10 02:38:13 +03:00
*
2005-04-17 02:20:36 +04:00
* TCP NFS related read + write fixes
* ( C ) 1999 Dave Airlie , University of Limerick , Ireland < airlied @ linux . ie >
*/
# include <linux/module.h>
# include <linux/sched.h>
# include <linux/interrupt.h>
# include <linux/slab.h>
# include <linux/mempool.h>
# include <linux/smp.h>
# include <linux/spinlock.h>
2006-03-21 09:33:17 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include <linux/sunrpc/clnt.h>
2009-09-10 13:25:04 +04:00
# include "sunrpc.h"
2005-04-17 02:20:36 +04:00
# ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_SCHED
# endif
/*
* RPC slabs and memory pools
*/
# define RPC_BUFFER_MAXSIZE (2048)
# define RPC_BUFFER_POOLSIZE (8)
# define RPC_TASK_POOLSIZE (8)
2006-12-07 07:33:20 +03:00
static struct kmem_cache * rpc_task_slabp __read_mostly ;
static struct kmem_cache * rpc_buffer_slabp __read_mostly ;
2005-08-26 23:05:31 +04:00
static mempool_t * rpc_task_mempool __read_mostly ;
static mempool_t * rpc_buffer_mempool __read_mostly ;
2005-04-17 02:20:36 +04:00
2006-11-22 17:55:48 +03:00
static void rpc_async_schedule ( struct work_struct * ) ;
2007-01-24 22:54:53 +03:00
static void rpc_release_task ( struct rpc_task * task ) ;
2007-07-19 00:18:52 +04:00
static void __rpc_queue_timer_fn ( unsigned long ptr ) ;
2005-04-17 02:20:36 +04:00
/*
* RPC tasks sit here while waiting for conditions to improve .
*/
2007-07-18 21:24:19 +04:00
static struct rpc_wait_queue delay_queue ;
2005-04-17 02:20:36 +04:00
/*
* rpciod - related stuff
*/
2006-03-20 21:44:08 +03:00
struct workqueue_struct * rpciod_workqueue ;
2005-04-17 02:20:36 +04:00
/*
* Disable the timer for a given RPC task . Should be called with
* queue - > lock and bh_disabled in order to avoid races within
* rpc_run_timer ( ) .
*/
2008-02-23 00:34:17 +03:00
static void
2008-02-23 01:27:59 +03:00
__rpc_disable_timer ( struct rpc_wait_queue * queue , struct rpc_task * task )
2005-04-17 02:20:36 +04:00
{
2007-07-19 00:18:52 +04:00
if ( task - > tk_timeout = = 0 )
return ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u disabling timer \n " , task - > tk_pid ) ;
2005-04-17 02:20:36 +04:00
task - > tk_timeout = 0 ;
2007-07-19 00:18:52 +04:00
list_del ( & task - > u . tk_wait . timer_list ) ;
2008-02-23 01:27:59 +03:00
if ( list_empty ( & queue - > timer_list . list ) )
del_timer ( & queue - > timer_list . timer ) ;
2007-07-19 00:18:52 +04:00
}
static void
rpc_set_queue_timer ( struct rpc_wait_queue * queue , unsigned long expires )
{
queue - > timer_list . expires = expires ;
mod_timer ( & queue - > timer_list . timer , expires ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Set up a timer for the current task .
*/
2008-02-23 00:34:17 +03:00
static void
2008-02-23 01:27:59 +03:00
__rpc_add_timer ( struct rpc_wait_queue * queue , struct rpc_task * task )
2005-04-17 02:20:36 +04:00
{
if ( ! task - > tk_timeout )
return ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u setting alarm for %lu ms \n " ,
2005-04-17 02:20:36 +04:00
task - > tk_pid , task - > tk_timeout * 1000 / HZ ) ;
2008-02-23 01:27:59 +03:00
task - > u . tk_wait . expires = jiffies + task - > tk_timeout ;
if ( list_empty ( & queue - > timer_list . list ) | | time_before ( task - > u . tk_wait . expires , queue - > timer_list . expires ) )
rpc_set_queue_timer ( queue , task - > u . tk_wait . expires ) ;
list_add ( & task - > u . tk_wait . timer_list , & queue - > timer_list . list ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Add new request to a priority queue .
*/
static void __rpc_add_wait_queue_priority ( struct rpc_wait_queue * queue , struct rpc_task * task )
{
struct list_head * q ;
struct rpc_task * t ;
INIT_LIST_HEAD ( & task - > u . tk_wait . links ) ;
q = & queue - > tasks [ task - > tk_priority ] ;
if ( unlikely ( task - > tk_priority > queue - > maxpriority ) )
q = & queue - > tasks [ queue - > maxpriority ] ;
list_for_each_entry ( t , q , u . tk_wait . list ) {
2007-07-14 23:40:00 +04:00
if ( t - > tk_owner = = task - > tk_owner ) {
2005-04-17 02:20:36 +04:00
list_add_tail ( & task - > u . tk_wait . list , & t - > u . tk_wait . links ) ;
return ;
}
}
list_add_tail ( & task - > u . tk_wait . list , q ) ;
}
/*
* Add new request to wait queue .
*
* Swapper tasks always get inserted at the head of the queue .
* This should avoid many nasty memory deadlocks and hopefully
* improve overall performance .
* Everyone else gets appended to the queue to ensure proper FIFO behavior .
*/
static void __rpc_add_wait_queue ( struct rpc_wait_queue * queue , struct rpc_task * task )
{
BUG_ON ( RPC_IS_QUEUED ( task ) ) ;
if ( RPC_IS_PRIORITY ( queue ) )
__rpc_add_wait_queue_priority ( queue , task ) ;
else if ( RPC_IS_SWAPPER ( task ) )
list_add ( & task - > u . tk_wait . list , & queue - > tasks [ 0 ] ) ;
else
list_add_tail ( & task - > u . tk_wait . list , & queue - > tasks [ 0 ] ) ;
2008-02-22 23:46:41 +03:00
task - > tk_waitqueue = queue ;
2006-03-20 21:44:15 +03:00
queue - > qlen + + ;
2005-04-17 02:20:36 +04:00
rpc_set_queued ( task ) ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u added to queue %p \" %s \" \n " ,
task - > tk_pid , queue , rpc_qname ( queue ) ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Remove request from a priority queue .
*/
static void __rpc_remove_wait_queue_priority ( struct rpc_task * task )
{
struct rpc_task * t ;
if ( ! list_empty ( & task - > u . tk_wait . links ) ) {
t = list_entry ( task - > u . tk_wait . links . next , struct rpc_task , u . tk_wait . list ) ;
list_move ( & t - > u . tk_wait . list , & task - > u . tk_wait . list ) ;
list_splice_init ( & task - > u . tk_wait . links , & t - > u . tk_wait . links ) ;
}
}
/*
* Remove request from queue .
* Note : must be called with spin lock held .
*/
2008-02-22 23:46:41 +03:00
static void __rpc_remove_wait_queue ( struct rpc_wait_queue * queue , struct rpc_task * task )
2005-04-17 02:20:36 +04:00
{
2008-02-23 01:27:59 +03:00
__rpc_disable_timer ( queue , task ) ;
2005-04-17 02:20:36 +04:00
if ( RPC_IS_PRIORITY ( queue ) )
__rpc_remove_wait_queue_priority ( task ) ;
2007-07-19 00:18:52 +04:00
list_del ( & task - > u . tk_wait . list ) ;
2006-03-20 21:44:15 +03:00
queue - > qlen - - ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u removed from queue %p \" %s \" \n " ,
task - > tk_pid , queue , rpc_qname ( queue ) ) ;
2005-04-17 02:20:36 +04:00
}
static inline void rpc_set_waitqueue_priority ( struct rpc_wait_queue * queue , int priority )
{
queue - > priority = priority ;
queue - > count = 1 < < ( priority * 2 ) ;
}
2007-07-14 23:40:00 +04:00
static inline void rpc_set_waitqueue_owner ( struct rpc_wait_queue * queue , pid_t pid )
2005-04-17 02:20:36 +04:00
{
2007-07-14 23:40:00 +04:00
queue - > owner = pid ;
2005-04-17 02:20:36 +04:00
queue - > nr = RPC_BATCH_COUNT ;
}
static inline void rpc_reset_waitqueue_priority ( struct rpc_wait_queue * queue )
{
rpc_set_waitqueue_priority ( queue , queue - > maxpriority ) ;
2007-07-14 23:40:00 +04:00
rpc_set_waitqueue_owner ( queue , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:40:00 +04:00
static void __rpc_init_priority_wait_queue ( struct rpc_wait_queue * queue , const char * qname , unsigned char nr_queues )
2005-04-17 02:20:36 +04:00
{
int i ;
spin_lock_init ( & queue - > lock ) ;
for ( i = 0 ; i < ARRAY_SIZE ( queue - > tasks ) ; i + + )
INIT_LIST_HEAD ( & queue - > tasks [ i ] ) ;
2007-07-14 23:40:00 +04:00
queue - > maxpriority = nr_queues - 1 ;
2005-04-17 02:20:36 +04:00
rpc_reset_waitqueue_priority ( queue ) ;
2007-07-19 00:18:52 +04:00
queue - > qlen = 0 ;
setup_timer ( & queue - > timer_list . timer , __rpc_queue_timer_fn , ( unsigned long ) queue ) ;
INIT_LIST_HEAD ( & queue - > timer_list . list ) ;
2005-04-17 02:20:36 +04:00
# ifdef RPC_DEBUG
queue - > name = qname ;
# endif
}
void rpc_init_priority_wait_queue ( struct rpc_wait_queue * queue , const char * qname )
{
2007-07-14 23:40:00 +04:00
__rpc_init_priority_wait_queue ( queue , qname , RPC_NR_PRIORITY ) ;
2005-04-17 02:20:36 +04:00
}
2009-12-15 08:27:56 +03:00
EXPORT_SYMBOL_GPL ( rpc_init_priority_wait_queue ) ;
2005-04-17 02:20:36 +04:00
void rpc_init_wait_queue ( struct rpc_wait_queue * queue , const char * qname )
{
2007-07-14 23:40:00 +04:00
__rpc_init_priority_wait_queue ( queue , qname , 1 ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_init_wait_queue ) ;
2005-04-17 02:20:36 +04:00
2008-02-23 01:06:55 +03:00
void rpc_destroy_wait_queue ( struct rpc_wait_queue * queue )
{
2007-07-19 00:18:52 +04:00
del_timer_sync ( & queue - > timer_list . timer ) ;
2008-02-23 01:06:55 +03:00
}
EXPORT_SYMBOL_GPL ( rpc_destroy_wait_queue ) ;
2007-12-07 00:24:39 +03:00
static int rpc_wait_bit_killable ( void * word )
2006-01-03 11:55:06 +03:00
{
2007-12-07 00:24:39 +03:00
if ( fatal_signal_pending ( current ) )
2006-01-03 11:55:06 +03:00
return - ERESTARTSYS ;
schedule ( ) ;
return 0 ;
}
2007-06-16 22:17:01 +04:00
# ifdef RPC_DEBUG
static void rpc_task_set_debuginfo ( struct rpc_task * task )
{
static atomic_t rpc_pid ;
task - > tk_pid = atomic_inc_return ( & rpc_pid ) ;
}
# else
static inline void rpc_task_set_debuginfo ( struct rpc_task * task )
{
}
# endif
2006-11-12 06:18:03 +03:00
static void rpc_set_active ( struct rpc_task * task )
{
2007-06-16 22:17:01 +04:00
rpc_task_set_debuginfo ( task ) ;
2010-07-31 22:29:08 +04:00
set_bit ( RPC_TASK_ACTIVE , & task - > tk_runstate ) ;
2006-11-12 06:18:03 +03:00
}
2006-01-03 11:55:06 +03:00
/*
* Mark an RPC call as having completed by clearing the ' active ' bit
2011-02-21 22:05:41 +03:00
* and then waking up all tasks that were sleeping .
2006-01-03 11:55:06 +03:00
*/
2011-02-21 22:05:41 +03:00
static int rpc_complete_task ( struct rpc_task * task )
2006-01-03 11:55:06 +03:00
{
2011-02-21 22:05:41 +03:00
void * m = & task - > tk_runstate ;
wait_queue_head_t * wq = bit_waitqueue ( m , RPC_TASK_ACTIVE ) ;
struct wait_bit_key k = __WAIT_BIT_KEY_INITIALIZER ( m , RPC_TASK_ACTIVE ) ;
unsigned long flags ;
int ret ;
spin_lock_irqsave ( & wq - > lock , flags ) ;
2006-11-12 06:18:03 +03:00
clear_bit ( RPC_TASK_ACTIVE , & task - > tk_runstate ) ;
2011-02-21 22:05:41 +03:00
ret = atomic_dec_and_test ( & task - > tk_count ) ;
if ( waitqueue_active ( wq ) )
__wake_up_locked_key ( wq , TASK_NORMAL , & k ) ;
spin_unlock_irqrestore ( & wq - > lock , flags ) ;
return ret ;
2006-01-03 11:55:06 +03:00
}
/*
* Allow callers to wait for completion of an RPC call
2011-02-21 22:05:41 +03:00
*
* Note the use of out_of_line_wait_on_bit ( ) rather than wait_on_bit ( )
* to enforce taking of the wq - > lock and hence avoid races with
* rpc_complete_task ( ) .
2006-01-03 11:55:06 +03:00
*/
int __rpc_wait_for_completion_task ( struct rpc_task * task , int ( * action ) ( void * ) )
{
if ( action = = NULL )
2007-12-07 00:24:39 +03:00
action = rpc_wait_bit_killable ;
2011-02-21 22:05:41 +03:00
return out_of_line_wait_on_bit ( & task - > tk_runstate , RPC_TASK_ACTIVE ,
2007-12-07 00:24:39 +03:00
action , TASK_KILLABLE ) ;
2006-01-03 11:55:06 +03:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( __rpc_wait_for_completion_task ) ;
2006-01-03 11:55:06 +03:00
2005-04-17 02:20:36 +04:00
/*
* Make an RPC task runnable .
*
2007-02-10 02:38:13 +03:00
* Note : If the task is ASYNC , this must be called with
2005-04-17 02:20:36 +04:00
* the spinlock held to protect the wait queue operation .
*/
static void rpc_make_runnable ( struct rpc_task * task )
{
rpc_clear_queued ( task ) ;
2006-11-05 20:42:48 +03:00
if ( rpc_test_and_set_running ( task ) )
return ;
2005-04-17 02:20:36 +04:00
if ( RPC_IS_ASYNC ( task ) ) {
2006-11-22 17:55:48 +03:00
INIT_WORK ( & task - > u . tk_work , rpc_async_schedule ) ;
2011-02-11 18:42:35 +03:00
queue_work ( rpciod_workqueue , & task - > u . tk_work ) ;
2005-04-17 02:20:36 +04:00
} else
2005-06-22 21:16:21 +04:00
wake_up_bit ( & task - > tk_runstate , RPC_TASK_QUEUED ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Prepare for sleeping on a wait queue .
* By always appending tasks to the list we ensure FIFO behavior .
* NB : An RPC task will only receive interrupt - driven events as long
* as it ' s on a wait queue .
*/
static void __rpc_sleep_on ( struct rpc_wait_queue * q , struct rpc_task * task ,
2008-02-23 00:34:17 +03:00
rpc_action action )
2005-04-17 02:20:36 +04:00
{
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u sleep_on(queue \" %s \" time %lu) \n " ,
task - > tk_pid , rpc_qname ( q ) , jiffies ) ;
2005-04-17 02:20:36 +04:00
__rpc_add_wait_queue ( q , task ) ;
BUG_ON ( task - > tk_callback ! = NULL ) ;
task - > tk_callback = action ;
2008-02-23 01:27:59 +03:00
__rpc_add_timer ( q , task ) ;
2005-04-17 02:20:36 +04:00
}
void rpc_sleep_on ( struct rpc_wait_queue * q , struct rpc_task * task ,
2008-02-23 00:34:17 +03:00
rpc_action action )
2005-04-17 02:20:36 +04:00
{
2010-07-31 22:29:08 +04:00
/* We shouldn't ever put an inactive task to sleep */
BUG_ON ( ! RPC_IS_ACTIVATED ( task ) ) ;
2006-11-12 06:18:03 +03:00
2005-04-17 02:20:36 +04:00
/*
* Protect the queue operations .
*/
spin_lock_bh ( & q - > lock ) ;
2008-02-23 00:34:17 +03:00
__rpc_sleep_on ( q , task , action ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_bh ( & q - > lock ) ;
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_sleep_on ) ;
2005-04-17 02:20:36 +04:00
/**
* __rpc_do_wake_up_task - wake up a single rpc_task
2008-02-22 23:46:41 +03:00
* @ queue : wait queue
2005-04-17 02:20:36 +04:00
* @ task : task to be woken up
*
* Caller must hold queue - > lock , and have cleared the task queued flag .
*/
2008-02-22 23:46:41 +03:00
static void __rpc_do_wake_up_task ( struct rpc_wait_queue * queue , struct rpc_task * task )
2005-04-17 02:20:36 +04:00
{
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u __rpc_wake_up_task (now %lu) \n " ,
task - > tk_pid , jiffies ) ;
2005-04-17 02:20:36 +04:00
/* Has the task been executed yet? If not, we cannot wake it up! */
if ( ! RPC_IS_ACTIVATED ( task ) ) {
printk ( KERN_ERR " RPC: Inactive task (%p) being woken up! \n " , task ) ;
return ;
}
2008-02-22 23:46:41 +03:00
__rpc_remove_wait_queue ( queue , task ) ;
2005-04-17 02:20:36 +04:00
rpc_make_runnable ( task ) ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: __rpc_wake_up_task done \n " ) ;
2005-04-17 02:20:36 +04:00
}
/*
2008-02-22 23:46:41 +03:00
* Wake up a queued task while the queue lock is being held
2005-04-17 02:20:36 +04:00
*/
2008-02-22 23:46:41 +03:00
static void rpc_wake_up_task_queue_locked ( struct rpc_wait_queue * queue , struct rpc_task * task )
2005-04-17 02:20:36 +04:00
{
2008-02-26 08:40:50 +03:00
if ( RPC_IS_QUEUED ( task ) & & task - > tk_waitqueue = = queue )
__rpc_do_wake_up_task ( queue , task ) ;
2005-04-17 02:20:36 +04:00
}
2009-12-15 08:27:53 +03:00
/*
* Tests whether rpc queue is empty
*/
int rpc_queue_empty ( struct rpc_wait_queue * queue )
{
int res ;
spin_lock_bh ( & queue - > lock ) ;
res = queue - > qlen ;
spin_unlock_bh ( & queue - > lock ) ;
2010-09-23 00:43:57 +04:00
return res = = 0 ;
2009-12-15 08:27:53 +03:00
}
EXPORT_SYMBOL_GPL ( rpc_queue_empty ) ;
2005-04-17 02:20:36 +04:00
/*
2008-02-22 23:46:41 +03:00
* Wake up a task on a specific queue
2005-04-17 02:20:36 +04:00
*/
2008-02-22 23:46:41 +03:00
void rpc_wake_up_queued_task ( struct rpc_wait_queue * queue , struct rpc_task * task )
2005-04-17 02:20:36 +04:00
{
2008-02-26 08:53:49 +03:00
spin_lock_bh ( & queue - > lock ) ;
2008-02-22 23:46:41 +03:00
rpc_wake_up_task_queue_locked ( queue , task ) ;
2008-02-26 08:53:49 +03:00
spin_unlock_bh ( & queue - > lock ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-22 23:46:41 +03:00
EXPORT_SYMBOL_GPL ( rpc_wake_up_queued_task ) ;
2005-04-17 02:20:36 +04:00
/*
* Wake up the next task on a priority queue .
*/
static struct rpc_task * __rpc_wake_up_next_priority ( struct rpc_wait_queue * queue )
{
struct list_head * q ;
struct rpc_task * task ;
/*
2007-07-14 23:40:00 +04:00
* Service a batch of tasks from a single owner .
2005-04-17 02:20:36 +04:00
*/
q = & queue - > tasks [ queue - > priority ] ;
if ( ! list_empty ( q ) ) {
task = list_entry ( q - > next , struct rpc_task , u . tk_wait . list ) ;
2007-07-14 23:40:00 +04:00
if ( queue - > owner = = task - > tk_owner ) {
2005-04-17 02:20:36 +04:00
if ( - - queue - > nr )
goto out ;
list_move_tail ( & task - > u . tk_wait . list , q ) ;
}
/*
* Check if we need to switch queues .
*/
if ( - - queue - > count )
2007-07-14 23:40:00 +04:00
goto new_owner ;
2005-04-17 02:20:36 +04:00
}
/*
* Service the next queue .
*/
do {
if ( q = = & queue - > tasks [ 0 ] )
q = & queue - > tasks [ queue - > maxpriority ] ;
else
q = q - 1 ;
if ( ! list_empty ( q ) ) {
task = list_entry ( q - > next , struct rpc_task , u . tk_wait . list ) ;
goto new_queue ;
}
} while ( q ! = & queue - > tasks [ queue - > priority ] ) ;
rpc_reset_waitqueue_priority ( queue ) ;
return NULL ;
new_queue :
rpc_set_waitqueue_priority ( queue , ( unsigned int ) ( q - & queue - > tasks [ 0 ] ) ) ;
2007-07-14 23:40:00 +04:00
new_owner :
rpc_set_waitqueue_owner ( queue , task - > tk_owner ) ;
2005-04-17 02:20:36 +04:00
out :
2008-02-22 23:46:41 +03:00
rpc_wake_up_task_queue_locked ( queue , task ) ;
2005-04-17 02:20:36 +04:00
return task ;
}
/*
* Wake up the next task on the wait queue .
*/
struct rpc_task * rpc_wake_up_next ( struct rpc_wait_queue * queue )
{
struct rpc_task * task = NULL ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: wake_up_next(%p \" %s \" ) \n " ,
queue , rpc_qname ( queue ) ) ;
2008-02-26 08:53:49 +03:00
spin_lock_bh ( & queue - > lock ) ;
2005-04-17 02:20:36 +04:00
if ( RPC_IS_PRIORITY ( queue ) )
task = __rpc_wake_up_next_priority ( queue ) ;
else {
task_for_first ( task , & queue - > tasks [ 0 ] )
2008-02-22 23:46:41 +03:00
rpc_wake_up_task_queue_locked ( queue , task ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-26 08:53:49 +03:00
spin_unlock_bh ( & queue - > lock ) ;
2005-04-17 02:20:36 +04:00
return task ;
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_wake_up_next ) ;
2005-04-17 02:20:36 +04:00
/**
* rpc_wake_up - wake up all rpc_tasks
* @ queue : rpc_wait_queue on which the tasks are sleeping
*
* Grabs queue - > lock
*/
void rpc_wake_up ( struct rpc_wait_queue * queue )
{
2006-03-14 08:20:48 +03:00
struct rpc_task * task , * next ;
2005-04-17 02:20:36 +04:00
struct list_head * head ;
2006-03-14 08:20:48 +03:00
2008-02-26 08:53:49 +03:00
spin_lock_bh ( & queue - > lock ) ;
2005-04-17 02:20:36 +04:00
head = & queue - > tasks [ queue - > maxpriority ] ;
for ( ; ; ) {
2006-03-14 08:20:48 +03:00
list_for_each_entry_safe ( task , next , head , u . tk_wait . list )
2008-02-22 23:46:41 +03:00
rpc_wake_up_task_queue_locked ( queue , task ) ;
2005-04-17 02:20:36 +04:00
if ( head = = & queue - > tasks [ 0 ] )
break ;
head - - ;
}
2008-02-26 08:53:49 +03:00
spin_unlock_bh ( & queue - > lock ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_wake_up ) ;
2005-04-17 02:20:36 +04:00
/**
* rpc_wake_up_status - wake up all rpc_tasks and set their status value .
* @ queue : rpc_wait_queue on which the tasks are sleeping
* @ status : status value to set
*
* Grabs queue - > lock
*/
void rpc_wake_up_status ( struct rpc_wait_queue * queue , int status )
{
2006-03-14 08:20:48 +03:00
struct rpc_task * task , * next ;
2005-04-17 02:20:36 +04:00
struct list_head * head ;
2008-02-26 08:53:49 +03:00
spin_lock_bh ( & queue - > lock ) ;
2005-04-17 02:20:36 +04:00
head = & queue - > tasks [ queue - > maxpriority ] ;
for ( ; ; ) {
2006-03-14 08:20:48 +03:00
list_for_each_entry_safe ( task , next , head , u . tk_wait . list ) {
2005-04-17 02:20:36 +04:00
task - > tk_status = status ;
2008-02-22 23:46:41 +03:00
rpc_wake_up_task_queue_locked ( queue , task ) ;
2005-04-17 02:20:36 +04:00
}
if ( head = = & queue - > tasks [ 0 ] )
break ;
head - - ;
}
2008-02-26 08:53:49 +03:00
spin_unlock_bh ( & queue - > lock ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_wake_up_status ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 00:18:52 +04:00
static void __rpc_queue_timer_fn ( unsigned long ptr )
{
struct rpc_wait_queue * queue = ( struct rpc_wait_queue * ) ptr ;
struct rpc_task * task , * n ;
unsigned long expires , now , timeo ;
spin_lock ( & queue - > lock ) ;
expires = now = jiffies ;
list_for_each_entry_safe ( task , n , & queue - > timer_list . list , u . tk_wait . timer_list ) {
timeo = task - > u . tk_wait . expires ;
if ( time_after_eq ( now , timeo ) ) {
dprintk ( " RPC: %5u timeout \n " , task - > tk_pid ) ;
task - > tk_status = - ETIMEDOUT ;
rpc_wake_up_task_queue_locked ( queue , task ) ;
continue ;
}
if ( expires = = now | | time_after ( expires , timeo ) )
expires = timeo ;
}
if ( ! list_empty ( & queue - > timer_list . list ) )
rpc_set_queue_timer ( queue , expires ) ;
spin_unlock ( & queue - > lock ) ;
}
2006-09-01 02:24:08 +04:00
static void __rpc_atrun ( struct rpc_task * task )
{
2008-02-23 00:34:17 +03:00
task - > tk_status = 0 ;
2006-09-01 02:24:08 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Run a task at a later time
*/
2006-09-01 02:24:08 +04:00
void rpc_delay ( struct rpc_task * task , unsigned long delay )
2005-04-17 02:20:36 +04:00
{
task - > tk_timeout = delay ;
2008-02-23 00:34:17 +03:00
rpc_sleep_on ( & delay_queue , task , __rpc_atrun ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_delay ) ;
2005-04-17 02:20:36 +04:00
2006-01-03 11:55:05 +03:00
/*
* Helper to call task - > tk_ops - > rpc_call_prepare
*/
2009-04-01 17:22:40 +04:00
void rpc_prepare_task ( struct rpc_task * task )
2006-01-03 11:55:05 +03:00
{
task - > tk_ops - > rpc_call_prepare ( task , task - > tk_calldata ) ;
}
2005-06-22 21:16:19 +04:00
/*
2006-01-03 11:55:04 +03:00
* Helper that calls task - > tk_ops - > rpc_call_done if it exists
2005-06-22 21:16:19 +04:00
*/
2006-01-03 11:55:03 +03:00
void rpc_exit_task ( struct rpc_task * task )
2005-06-22 21:16:19 +04:00
{
2006-01-03 11:55:03 +03:00
task - > tk_action = NULL ;
2006-01-03 11:55:04 +03:00
if ( task - > tk_ops - > rpc_call_done ! = NULL ) {
task - > tk_ops - > rpc_call_done ( task , task - > tk_calldata ) ;
2005-06-22 21:16:19 +04:00
if ( task - > tk_action ! = NULL ) {
2006-01-03 11:55:03 +03:00
WARN_ON ( RPC_ASSASSINATED ( task ) ) ;
/* Always release the RPC slot and buffer memory */
xprt_release ( task ) ;
2005-06-22 21:16:19 +04:00
}
}
}
2010-07-31 22:29:08 +04:00
void rpc_exit ( struct rpc_task * task , int status )
{
task - > tk_status = status ;
task - > tk_action = rpc_exit_task ;
if ( RPC_IS_QUEUED ( task ) )
rpc_wake_up_queued_task ( task - > tk_waitqueue , task ) ;
}
EXPORT_SYMBOL_GPL ( rpc_exit ) ;
2005-06-22 21:16:19 +04:00
2006-10-19 00:01:05 +04:00
void rpc_release_calldata ( const struct rpc_call_ops * ops , void * calldata )
{
2008-06-11 21:37:09 +04:00
if ( ops - > rpc_release ! = NULL )
2006-10-19 00:01:05 +04:00
ops - > rpc_release ( calldata ) ;
}
2005-04-17 02:20:36 +04:00
/*
* This is the RPC ` scheduler ' ( or rather , the finite state machine ) .
*/
2007-02-04 00:38:41 +03:00
static void __rpc_execute ( struct rpc_task * task )
2005-04-17 02:20:36 +04:00
{
2009-03-11 03:33:16 +03:00
struct rpc_wait_queue * queue ;
int task_is_async = RPC_IS_ASYNC ( task ) ;
int status = 0 ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u __rpc_execute flags=0x%x \n " ,
task - > tk_pid , task - > tk_flags ) ;
2005-04-17 02:20:36 +04:00
BUG_ON ( RPC_IS_QUEUED ( task ) ) ;
2005-06-22 21:16:19 +04:00
for ( ; ; ) {
2011-07-07 03:58:23 +04:00
void ( * do_action ) ( struct rpc_task * ) ;
2005-04-17 02:20:36 +04:00
/*
2011-07-07 03:58:23 +04:00
* Execute any pending callback first .
2005-04-17 02:20:36 +04:00
*/
2011-07-07 03:58:23 +04:00
do_action = task - > tk_callback ;
task - > tk_callback = NULL ;
if ( do_action = = NULL ) {
2011-03-16 02:56:30 +03:00
/*
* Perform the next FSM step .
2011-07-07 03:58:23 +04:00
* tk_action may be NULL if the task has been killed .
* In particular , note that rpc_killall_tasks may
* do this at any time , so beware when dereferencing .
2011-03-16 02:56:30 +03:00
*/
2011-07-07 03:58:23 +04:00
do_action = task - > tk_action ;
if ( do_action = = NULL )
2005-04-17 02:20:36 +04:00
break ;
}
2011-07-07 03:58:23 +04:00
do_action ( task ) ;
2005-04-17 02:20:36 +04:00
/*
* Lockless check for whether task is sleeping or not .
*/
if ( ! RPC_IS_QUEUED ( task ) )
continue ;
2009-03-11 03:33:16 +03:00
/*
* The queue - > lock protects against races with
* rpc_make_runnable ( ) .
*
* Note that once we clear RPC_TASK_RUNNING on an asynchronous
* rpc_task , rpc_make_runnable ( ) can assign it to a
* different workqueue . We therefore cannot assume that the
* rpc_task pointer may still be dereferenced .
*/
queue = task - > tk_waitqueue ;
spin_lock_bh ( & queue - > lock ) ;
if ( ! RPC_IS_QUEUED ( task ) ) {
spin_unlock_bh ( & queue - > lock ) ;
2005-04-17 02:20:36 +04:00
continue ;
}
2009-03-11 03:33:16 +03:00
rpc_clear_running ( task ) ;
spin_unlock_bh ( & queue - > lock ) ;
if ( task_is_async )
return ;
2005-04-17 02:20:36 +04:00
/* sync task: sleep here */
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u sync task going to sleep \n " , task - > tk_pid ) ;
2005-06-22 21:16:21 +04:00
status = out_of_line_wait_on_bit ( & task - > tk_runstate ,
2007-12-07 00:24:39 +03:00
RPC_TASK_QUEUED , rpc_wait_bit_killable ,
TASK_KILLABLE ) ;
2005-06-22 21:16:21 +04:00
if ( status = = - ERESTARTSYS ) {
2005-04-17 02:20:36 +04:00
/*
* When a sync task receives a signal , it exits with
* - ERESTARTSYS . In order to catch any callbacks that
* clean up after sleeping on some queue , we don ' t
* break the loop here , but go around once more .
*/
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u got signal \n " , task - > tk_pid ) ;
2005-06-22 21:16:21 +04:00
task - > tk_flags | = RPC_TASK_KILLED ;
rpc_exit ( task , - ERESTARTSYS ) ;
2005-04-17 02:20:36 +04:00
}
rpc_set_running ( task ) ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u sync task resuming \n " , task - > tk_pid ) ;
2005-04-17 02:20:36 +04:00
}
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u return %d, status %d \n " , task - > tk_pid , status ,
task - > tk_status ) ;
2005-04-17 02:20:36 +04:00
/* Release all resources associated with the task */
rpc_release_task ( task ) ;
}
/*
* User - visible entry point to the scheduler .
*
* This may be called recursively if e . g . an async NFS task updates
* the attributes and finds that dirty pages must be flushed .
* NOTE : Upon exit of this function the task is guaranteed to be
* released . In particular note that tk_release ( ) will have
* been called , so your task memory may have been freed .
*/
2007-02-04 00:38:41 +03:00
void rpc_execute ( struct rpc_task * task )
2005-04-17 02:20:36 +04:00
{
2006-01-03 11:55:06 +03:00
rpc_set_active ( task ) ;
2010-07-31 22:29:08 +04:00
rpc_make_runnable ( task ) ;
if ( ! RPC_IS_ASYNC ( task ) )
__rpc_execute ( task ) ;
2005-04-17 02:20:36 +04:00
}
2006-11-22 17:55:48 +03:00
static void rpc_async_schedule ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2006-11-22 17:55:48 +03:00
__rpc_execute ( container_of ( work , struct rpc_task , u . tk_work ) ) ;
2005-04-17 02:20:36 +04:00
}
2006-01-03 11:55:49 +03:00
/**
* rpc_malloc - allocate an RPC buffer
* @ task : RPC task that will use this buffer
* @ size : requested byte size
2005-04-17 02:20:36 +04:00
*
2007-03-30 00:47:58 +04:00
* To prevent rpciod from hanging , this allocator never sleeps ,
* returning NULL if the request cannot be serviced immediately .
* The caller can arrange to sleep in a way that is safe for rpciod .
*
* Most requests are ' small ' ( under 2 KiB ) and can be serviced from a
* mempool , ensuring that NFS reads and writes can always proceed ,
* and that there is good locality of reference for these buffers .
*
2005-04-17 02:20:36 +04:00
* In order to avoid memory starvation triggering more writebacks of
2007-03-30 00:47:58 +04:00
* NFS requests , we avoid using GFP_KERNEL .
2005-04-17 02:20:36 +04:00
*/
2007-03-30 00:47:58 +04:00
void * rpc_malloc ( struct rpc_task * task , size_t size )
2005-04-17 02:20:36 +04:00
{
2007-05-09 02:23:28 +04:00
struct rpc_buffer * buf ;
2007-03-30 00:47:58 +04:00
gfp_t gfp = RPC_IS_SWAPPER ( task ) ? GFP_ATOMIC : GFP_NOWAIT ;
2005-04-17 02:20:36 +04:00
2007-05-09 02:23:28 +04:00
size + = sizeof ( struct rpc_buffer ) ;
2007-03-30 00:47:58 +04:00
if ( size < = RPC_BUFFER_MAXSIZE )
buf = mempool_alloc ( rpc_buffer_mempool , gfp ) ;
2005-04-17 02:20:36 +04:00
else
2007-03-30 00:47:58 +04:00
buf = kmalloc ( size , gfp ) ;
2007-05-09 10:30:11 +04:00
if ( ! buf )
return NULL ;
2007-05-09 02:23:28 +04:00
buf - > len = size ;
2007-05-08 13:37:26 +04:00
dprintk ( " RPC: %5u allocated buffer of size %zu at %p \n " ,
2007-03-30 00:47:58 +04:00
task - > tk_pid , size , buf ) ;
2007-05-09 02:23:28 +04:00
return & buf - > data ;
2005-04-17 02:20:36 +04:00
}
2007-09-10 21:45:36 +04:00
EXPORT_SYMBOL_GPL ( rpc_malloc ) ;
2005-04-17 02:20:36 +04:00
2006-01-03 11:55:49 +03:00
/**
* rpc_free - free buffer allocated via rpc_malloc
2007-03-30 00:47:58 +04:00
* @ buffer : buffer to free
2006-01-03 11:55:49 +03:00
*
*/
2007-03-30 00:47:58 +04:00
void rpc_free ( void * buffer )
2005-04-17 02:20:36 +04:00
{
2007-05-09 02:23:28 +04:00
size_t size ;
struct rpc_buffer * buf ;
2006-01-03 11:55:49 +03:00
2007-03-30 00:47:58 +04:00
if ( ! buffer )
return ;
2007-05-09 02:23:28 +04:00
buf = container_of ( buffer , struct rpc_buffer , data ) ;
size = buf - > len ;
2007-03-30 00:47:58 +04:00
2007-05-08 13:37:26 +04:00
dprintk ( " RPC: freeing buffer of size %zu at %p \n " ,
2007-03-30 00:47:58 +04:00
size , buf ) ;
2007-05-09 02:23:28 +04:00
2007-03-30 00:47:58 +04:00
if ( size < = RPC_BUFFER_MAXSIZE )
mempool_free ( buf , rpc_buffer_mempool ) ;
else
kfree ( buf ) ;
2005-04-17 02:20:36 +04:00
}
2007-09-10 21:45:36 +04:00
EXPORT_SYMBOL_GPL ( rpc_free ) ;
2005-04-17 02:20:36 +04:00
/*
* Creation and deletion of RPC task structures
*/
2007-10-26 02:42:55 +04:00
static void rpc_init_task ( struct rpc_task * task , const struct rpc_task_setup * task_setup_data )
2005-04-17 02:20:36 +04:00
{
memset ( task , 0 , sizeof ( * task ) ) ;
2006-01-03 11:55:06 +03:00
atomic_set ( & task - > tk_count , 1 ) ;
2007-07-14 23:39:59 +04:00
task - > tk_flags = task_setup_data - > flags ;
task - > tk_ops = task_setup_data - > callback_ops ;
task - > tk_calldata = task_setup_data - > callback_data ;
2007-06-15 00:40:14 +04:00
INIT_LIST_HEAD ( & task - > tk_task ) ;
2005-04-17 02:20:36 +04:00
/* Initialize retry counters */
task - > tk_garb_retry = 2 ;
task - > tk_cred_retry = 2 ;
2011-05-31 23:15:34 +04:00
task - > tk_rebind_retry = 2 ;
2005-04-17 02:20:36 +04:00
2007-07-14 23:40:00 +04:00
task - > tk_priority = task_setup_data - > priority - RPC_PRIORITY_LOW ;
task - > tk_owner = current - > tgid ;
2005-04-17 02:20:36 +04:00
/* Initialize workqueue for async tasks */
2008-02-20 04:04:21 +03:00
task - > tk_workqueue = task_setup_data - > workqueue ;
2005-04-17 02:20:36 +04:00
2007-07-14 23:39:59 +04:00
if ( task - > tk_ops - > rpc_call_prepare ! = NULL )
task - > tk_action = rpc_prepare_task ;
2006-01-03 11:55:04 +03:00
2006-03-20 21:44:17 +03:00
/* starting timestamp */
2010-05-07 21:34:47 +04:00
task - > tk_start = ktime_get ( ) ;
2006-03-20 21:44:17 +03:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: new task initialized, procpid %u \n " ,
2007-10-19 10:40:40 +04:00
task_pid_nr ( current ) ) ;
2005-04-17 02:20:36 +04:00
}
static struct rpc_task *
rpc_alloc_task ( void )
{
return ( struct rpc_task * ) mempool_alloc ( rpc_task_mempool , GFP_NOFS ) ;
}
/*
2007-06-10 03:49:36 +04:00
* Create a new task for the specified client .
2005-04-17 02:20:36 +04:00
*/
2007-07-14 23:39:59 +04:00
struct rpc_task * rpc_new_task ( const struct rpc_task_setup * setup_data )
2005-04-17 02:20:36 +04:00
{
2007-10-26 02:42:53 +04:00
struct rpc_task * task = setup_data - > task ;
unsigned short flags = 0 ;
if ( task = = NULL ) {
task = rpc_alloc_task ( ) ;
2010-04-17 00:41:10 +04:00
if ( task = = NULL ) {
rpc_release_calldata ( setup_data - > callback_ops ,
setup_data - > callback_data ) ;
return ERR_PTR ( - ENOMEM ) ;
}
2007-10-26 02:42:53 +04:00
flags = RPC_TASK_DYNAMIC ;
}
2005-04-17 02:20:36 +04:00
2007-07-14 23:39:59 +04:00
rpc_init_task ( task , setup_data ) ;
2007-10-26 02:42:53 +04:00
task - > tk_flags | = flags ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: allocated task %p \n " , task ) ;
2005-04-17 02:20:36 +04:00
return task ;
}
2008-02-20 04:04:21 +03:00
static void rpc_free_task ( struct rpc_task * task )
2005-04-17 02:20:36 +04:00
{
2006-01-03 11:55:04 +03:00
const struct rpc_call_ops * tk_ops = task - > tk_ops ;
void * calldata = task - > tk_calldata ;
2005-04-17 02:20:36 +04:00
2008-02-26 08:53:49 +03:00
if ( task - > tk_flags & RPC_TASK_DYNAMIC ) {
dprintk ( " RPC: %5u freeing task \n " , task - > tk_pid ) ;
mempool_free ( task , rpc_task_mempool ) ;
}
2008-02-20 04:04:21 +03:00
rpc_release_calldata ( tk_ops , calldata ) ;
}
static void rpc_async_release ( struct work_struct * work )
{
rpc_free_task ( container_of ( work , struct rpc_task , u . tk_work ) ) ;
}
2011-02-21 22:05:41 +03:00
static void rpc_release_resources_task ( struct rpc_task * task )
2008-02-20 04:04:21 +03:00
{
2006-11-12 06:18:03 +03:00
if ( task - > tk_rqstp )
xprt_release ( task ) ;
2011-03-27 19:48:57 +04:00
if ( task - > tk_msg . rpc_cred ) {
2010-07-31 22:29:08 +04:00
put_rpccred ( task - > tk_msg . rpc_cred ) ;
2011-03-27 19:48:57 +04:00
task - > tk_msg . rpc_cred = NULL ;
}
2010-07-31 22:29:08 +04:00
rpc_task_release_client ( task ) ;
2011-02-21 22:05:41 +03:00
}
static void rpc_final_put_task ( struct rpc_task * task ,
struct workqueue_struct * q )
{
if ( q ! = NULL ) {
2008-02-20 04:04:21 +03:00
INIT_WORK ( & task - > u . tk_work , rpc_async_release ) ;
2011-02-21 22:05:41 +03:00
queue_work ( q , & task - > u . tk_work ) ;
2008-02-20 04:04:21 +03:00
} else
rpc_free_task ( task ) ;
2006-11-12 06:18:03 +03:00
}
2011-02-21 22:05:41 +03:00
static void rpc_do_put_task ( struct rpc_task * task , struct workqueue_struct * q )
{
if ( atomic_dec_and_test ( & task - > tk_count ) ) {
rpc_release_resources_task ( task ) ;
rpc_final_put_task ( task , q ) ;
}
}
void rpc_put_task ( struct rpc_task * task )
{
rpc_do_put_task ( task , NULL ) ;
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpc_put_task ) ;
2006-11-12 06:18:03 +03:00
2011-02-21 22:05:41 +03:00
void rpc_put_task_async ( struct rpc_task * task )
{
rpc_do_put_task ( task , task - > tk_workqueue ) ;
}
EXPORT_SYMBOL_GPL ( rpc_put_task_async ) ;
2007-01-24 22:54:53 +03:00
static void rpc_release_task ( struct rpc_task * task )
2006-11-12 06:18:03 +03:00
{
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u release task \n " , task - > tk_pid ) ;
2005-04-17 02:20:36 +04:00
BUG_ON ( RPC_IS_QUEUED ( task ) ) ;
2011-02-21 22:05:41 +03:00
rpc_release_resources_task ( task ) ;
2006-11-12 06:18:03 +03:00
2011-02-21 22:05:41 +03:00
/*
* Note : at this point we have been removed from rpc_clnt - > cl_tasks ,
* so it should be safe to use task - > tk_count as a test for whether
* or not any other processes still hold references to our rpc_task .
*/
if ( atomic_read ( & task - > tk_count ) ! = 1 + ! RPC_IS_ASYNC ( task ) ) {
/* Wake up anyone who may be waiting for task completion */
if ( ! rpc_complete_task ( task ) )
return ;
} else {
if ( ! atomic_dec_and_test ( & task - > tk_count ) )
return ;
}
rpc_final_put_task ( task , task - > tk_workqueue ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-20 00:32:20 +04:00
int rpciod_up ( void )
{
return try_module_get ( THIS_MODULE ) ? 0 : - EINVAL ;
}
void rpciod_down ( void )
{
module_put ( THIS_MODULE ) ;
}
2005-04-17 02:20:36 +04:00
/*
2007-07-20 00:32:20 +04:00
* Start up the rpciod workqueue .
2005-04-17 02:20:36 +04:00
*/
2007-07-20 00:32:20 +04:00
static int rpciod_start ( void )
2005-04-17 02:20:36 +04:00
{
struct workqueue_struct * wq ;
2007-06-15 01:08:36 +04:00
2005-04-17 02:20:36 +04:00
/*
* Create the rpciod thread and wait for it to start .
*/
2007-06-15 01:08:36 +04:00
dprintk ( " RPC: creating workqueue rpciod \n " ) ;
2011-01-25 16:35:54 +03:00
wq = alloc_workqueue ( " rpciod " , WQ_MEM_RECLAIM , 0 ) ;
2005-04-17 02:20:36 +04:00
rpciod_workqueue = wq ;
2007-07-20 00:32:20 +04:00
return rpciod_workqueue ! = NULL ;
2005-04-17 02:20:36 +04:00
}
2007-07-20 00:32:20 +04:00
static void rpciod_stop ( void )
2005-04-17 02:20:36 +04:00
{
2007-07-20 00:32:20 +04:00
struct workqueue_struct * wq = NULL ;
2007-06-15 01:08:36 +04:00
2007-07-20 00:32:20 +04:00
if ( rpciod_workqueue = = NULL )
return ;
2007-06-15 01:08:36 +04:00
dprintk ( " RPC: destroying workqueue rpciod \n " ) ;
2005-04-17 02:20:36 +04:00
2007-07-20 00:32:20 +04:00
wq = rpciod_workqueue ;
rpciod_workqueue = NULL ;
destroy_workqueue ( wq ) ;
2005-04-17 02:20:36 +04:00
}
void
rpc_destroy_mempool ( void )
{
2007-07-20 00:32:20 +04:00
rpciod_stop ( ) ;
2005-04-17 02:20:36 +04:00
if ( rpc_buffer_mempool )
mempool_destroy ( rpc_buffer_mempool ) ;
if ( rpc_task_mempool )
mempool_destroy ( rpc_task_mempool ) ;
2006-09-27 12:49:40 +04:00
if ( rpc_task_slabp )
kmem_cache_destroy ( rpc_task_slabp ) ;
if ( rpc_buffer_slabp )
kmem_cache_destroy ( rpc_buffer_slabp ) ;
2008-02-23 01:06:55 +03:00
rpc_destroy_wait_queue ( & delay_queue ) ;
2005-04-17 02:20:36 +04:00
}
int
rpc_init_mempool ( void )
{
2008-02-23 01:06:55 +03:00
/*
* The following is not strictly a mempool initialisation ,
* but there is no harm in doing it here
*/
rpc_init_wait_queue ( & delay_queue , " delayq " ) ;
if ( ! rpciod_start ( ) )
goto err_nomem ;
2005-04-17 02:20:36 +04:00
rpc_task_slabp = kmem_cache_create ( " rpc_tasks " ,
sizeof ( struct rpc_task ) ,
0 , SLAB_HWCACHE_ALIGN ,
2007-07-20 05:11:58 +04:00
NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! rpc_task_slabp )
goto err_nomem ;
rpc_buffer_slabp = kmem_cache_create ( " rpc_buffers " ,
RPC_BUFFER_MAXSIZE ,
0 , SLAB_HWCACHE_ALIGN ,
2007-07-20 05:11:58 +04:00
NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! rpc_buffer_slabp )
goto err_nomem ;
2006-03-26 13:37:50 +04:00
rpc_task_mempool = mempool_create_slab_pool ( RPC_TASK_POOLSIZE ,
rpc_task_slabp ) ;
2005-04-17 02:20:36 +04:00
if ( ! rpc_task_mempool )
goto err_nomem ;
2006-03-26 13:37:50 +04:00
rpc_buffer_mempool = mempool_create_slab_pool ( RPC_BUFFER_POOLSIZE ,
rpc_buffer_slabp ) ;
2005-04-17 02:20:36 +04:00
if ( ! rpc_buffer_mempool )
goto err_nomem ;
return 0 ;
err_nomem :
rpc_destroy_mempool ( ) ;
return - ENOMEM ;
}