2005-04-17 02:20:36 +04:00
/* kafstimod.c: AFS timeout daemon
*
* Copyright ( C ) 2002 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 .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/sched.h>
# include <linux/completion.h>
# include "cell.h"
# include "volume.h"
# include "kafstimod.h"
# include <asm/errno.h>
# include "internal.h"
static DECLARE_COMPLETION ( kafstimod_alive ) ;
static DECLARE_COMPLETION ( kafstimod_dead ) ;
static DECLARE_WAIT_QUEUE_HEAD ( kafstimod_sleepq ) ;
static int kafstimod_die ;
static LIST_HEAD ( kafstimod_list ) ;
static DEFINE_SPINLOCK ( kafstimod_lock ) ;
static int kafstimod ( void * arg ) ;
/*****************************************************************************/
/*
* start the timeout daemon
*/
int afs_kafstimod_start ( void )
{
int ret ;
ret = kernel_thread ( kafstimod , NULL , 0 ) ;
if ( ret < 0 )
return ret ;
wait_for_completion ( & kafstimod_alive ) ;
return ret ;
} /* end afs_kafstimod_start() */
/*****************************************************************************/
/*
* stop the timeout daemon
*/
void afs_kafstimod_stop ( void )
{
/* get rid of my daemon */
kafstimod_die = 1 ;
wake_up ( & kafstimod_sleepq ) ;
wait_for_completion ( & kafstimod_dead ) ;
} /* end afs_kafstimod_stop() */
/*****************************************************************************/
/*
* timeout processing daemon
*/
static int kafstimod ( void * arg )
{
struct afs_timer * timer ;
DECLARE_WAITQUEUE ( myself , current ) ;
printk ( " kAFS: Started kafstimod %d \n " , current - > pid ) ;
daemonize ( " kafstimod " ) ;
complete ( & kafstimod_alive ) ;
/* loop around looking for things to attend to */
loop :
set_current_state ( TASK_INTERRUPTIBLE ) ;
add_wait_queue ( & kafstimod_sleepq , & myself ) ;
for ( ; ; ) {
unsigned long jif ;
signed long timeout ;
/* deal with the server being asked to die */
if ( kafstimod_die ) {
remove_wait_queue ( & kafstimod_sleepq , & myself ) ;
_leave ( " " ) ;
complete_and_exit ( & kafstimod_dead , 0 ) ;
}
2005-06-25 10:13:50 +04:00
try_to_freeze ( ) ;
2005-04-17 02:20:36 +04:00
/* discard pending signals */
afs_discard_my_signals ( ) ;
/* work out the time to elapse before the next event */
spin_lock ( & kafstimod_lock ) ;
if ( list_empty ( & kafstimod_list ) ) {
timeout = MAX_SCHEDULE_TIMEOUT ;
}
else {
timer = list_entry ( kafstimod_list . next ,
struct afs_timer , link ) ;
timeout = timer - > timo_jif ;
jif = jiffies ;
if ( time_before_eq ( ( unsigned long ) timeout , jif ) )
goto immediate ;
else {
timeout = ( long ) timeout - ( long ) jiffies ;
}
}
spin_unlock ( & kafstimod_lock ) ;
schedule_timeout ( timeout ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
}
/* the thing on the front of the queue needs processing
* - we come here with the lock held and timer pointing to the expired
* entry
*/
immediate :
remove_wait_queue ( & kafstimod_sleepq , & myself ) ;
set_current_state ( TASK_RUNNING ) ;
_debug ( " @@@ Begin Timeout of %p " , timer ) ;
/* dequeue the timer */
list_del_init ( & timer - > link ) ;
spin_unlock ( & kafstimod_lock ) ;
/* call the timeout function */
timer - > ops - > timed_out ( timer ) ;
_debug ( " @@@ End Timeout " ) ;
goto loop ;
} /* end kafstimod() */
/*****************************************************************************/
/*
* ( re - ) queue a timer
*/
void afs_kafstimod_add_timer ( struct afs_timer * timer , unsigned long timeout )
{
struct afs_timer * ptimer ;
struct list_head * _p ;
_enter ( " %p,%lu " , timer , timeout ) ;
spin_lock ( & kafstimod_lock ) ;
list_del ( & timer - > link ) ;
/* the timer was deferred or reset - put it back in the queue at the
* right place */
timer - > timo_jif = jiffies + timeout ;
list_for_each ( _p , & kafstimod_list ) {
ptimer = list_entry ( _p , struct afs_timer , link ) ;
if ( time_before ( timer - > timo_jif , ptimer - > timo_jif ) )
break ;
}
list_add_tail ( & timer - > link , _p ) ; /* insert before stopping point */
spin_unlock ( & kafstimod_lock ) ;
wake_up ( & kafstimod_sleepq ) ;
_leave ( " " ) ;
} /* end afs_kafstimod_add_timer() */
/*****************************************************************************/
/*
* dequeue a timer
* - returns 0 if the timer was deleted or - ENOENT if it wasn ' t queued
*/
int afs_kafstimod_del_timer ( struct afs_timer * timer )
{
int ret = 0 ;
_enter ( " %p " , timer ) ;
spin_lock ( & kafstimod_lock ) ;
if ( list_empty ( & timer - > link ) )
ret = - ENOENT ;
else
list_del_init ( & timer - > link ) ;
spin_unlock ( & kafstimod_lock ) ;
wake_up ( & kafstimod_sleepq ) ;
_leave ( " = %d " , ret ) ;
return ret ;
} /* end afs_kafstimod_del_timer() */