2006-01-18 09:30:29 +00:00
/******************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* * Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
2008-12-09 11:55:46 -06:00
* * Copyright ( C ) 2004 - 2008 Red Hat , Inc . All rights reserved .
2006-01-18 09:30:29 +00:00
* *
* * This copyrighted material is made available to anyone wishing to use ,
* * modify , copy , or redistribute it subject to the terms and conditions
* * of the GNU General Public License v .2 .
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "dlm_internal.h"
# include "lock.h"
2006-07-12 16:44:04 -05:00
# include "user.h"
2007-04-04 17:25:29 +02:00
# include "ast.h"
2006-01-18 09:30:29 +00:00
# define WAKE_ASTS 0
static struct list_head ast_queue ;
static spinlock_t ast_queue_lock ;
static struct task_struct * astd_task ;
static unsigned long astd_wakeflags ;
2006-01-20 08:47:07 +00:00
static struct mutex astd_running ;
2006-01-18 09:30:29 +00:00
void dlm_del_ast ( struct dlm_lkb * lkb )
{
spin_lock ( & ast_queue_lock ) ;
if ( lkb - > lkb_ast_type & ( AST_COMP | AST_BAST ) )
list_del ( & lkb - > lkb_astqueue ) ;
spin_unlock ( & ast_queue_lock ) ;
}
2008-12-09 11:55:46 -06:00
void dlm_add_ast ( struct dlm_lkb * lkb , int type , int bastmode )
2006-01-18 09:30:29 +00:00
{
2006-07-12 16:44:04 -05:00
if ( lkb - > lkb_flags & DLM_IFL_USER ) {
2008-12-09 11:55:46 -06:00
dlm_user_add_ast ( lkb , type , bastmode ) ;
2006-07-12 16:44:04 -05:00
return ;
}
2006-01-18 09:30:29 +00:00
spin_lock ( & ast_queue_lock ) ;
if ( ! ( lkb - > lkb_ast_type & ( AST_COMP | AST_BAST ) ) ) {
kref_get ( & lkb - > lkb_ref ) ;
list_add_tail ( & lkb - > lkb_astqueue , & ast_queue ) ;
}
lkb - > lkb_ast_type | = type ;
2008-12-09 11:55:46 -06:00
if ( bastmode )
lkb - > lkb_bastmode = bastmode ;
2006-01-18 09:30:29 +00:00
spin_unlock ( & ast_queue_lock ) ;
set_bit ( WAKE_ASTS , & astd_wakeflags ) ;
wake_up_process ( astd_task ) ;
}
static void process_asts ( void )
{
struct dlm_ls * ls = NULL ;
struct dlm_rsb * r = NULL ;
struct dlm_lkb * lkb ;
2008-02-06 00:35:45 -06:00
void ( * cast ) ( void * astparam ) ;
void ( * bast ) ( void * astparam , int mode ) ;
2008-12-23 10:22:56 -06:00
int type = 0 , bastmode ;
repeat :
spin_lock ( & ast_queue_lock ) ;
list_for_each_entry ( lkb , & ast_queue , lkb_astqueue ) {
r = lkb - > lkb_resource ;
ls = r - > res_ls ;
2006-01-18 09:30:29 +00:00
2008-12-23 10:22:56 -06:00
if ( dlm_locking_stopped ( ls ) )
continue ;
2006-01-18 09:30:29 +00:00
2008-12-23 10:22:56 -06:00
list_del ( & lkb - > lkb_astqueue ) ;
type = lkb - > lkb_ast_type ;
lkb - > lkb_ast_type = 0 ;
bastmode = lkb - > lkb_bastmode ;
spin_unlock ( & ast_queue_lock ) ;
2008-02-06 00:35:45 -06:00
cast = lkb - > lkb_astfn ;
bast = lkb - > lkb_bastfn ;
2006-01-18 09:30:29 +00:00
if ( ( type & AST_COMP ) & & cast )
cast ( lkb - > lkb_astparam ) ;
if ( ( type & AST_BAST ) & & bast )
2008-12-09 11:55:46 -06:00
bast ( lkb - > lkb_astparam , bastmode ) ;
2006-01-18 09:30:29 +00:00
/* this removes the reference added by dlm_add_ast
and may result in the lkb being freed */
dlm_put_lkb ( lkb ) ;
2008-12-10 09:31:02 -06:00
cond_resched ( ) ;
2008-12-23 10:22:56 -06:00
goto repeat ;
2006-01-18 09:30:29 +00:00
}
2008-12-23 10:22:56 -06:00
spin_unlock ( & ast_queue_lock ) ;
2006-01-18 09:30:29 +00:00
}
static inline int no_asts ( void )
{
int ret ;
spin_lock ( & ast_queue_lock ) ;
ret = list_empty ( & ast_queue ) ;
spin_unlock ( & ast_queue_lock ) ;
return ret ;
}
static int dlm_astd ( void * data )
{
while ( ! kthread_should_stop ( ) ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
if ( ! test_bit ( WAKE_ASTS , & astd_wakeflags ) )
schedule ( ) ;
set_current_state ( TASK_RUNNING ) ;
2006-01-20 08:47:07 +00:00
mutex_lock ( & astd_running ) ;
2006-01-18 09:30:29 +00:00
if ( test_and_clear_bit ( WAKE_ASTS , & astd_wakeflags ) )
process_asts ( ) ;
2006-01-20 08:47:07 +00:00
mutex_unlock ( & astd_running ) ;
2006-01-18 09:30:29 +00:00
}
return 0 ;
}
void dlm_astd_wake ( void )
{
if ( ! no_asts ( ) ) {
set_bit ( WAKE_ASTS , & astd_wakeflags ) ;
wake_up_process ( astd_task ) ;
}
}
int dlm_astd_start ( void )
{
struct task_struct * p ;
int error = 0 ;
INIT_LIST_HEAD ( & ast_queue ) ;
spin_lock_init ( & ast_queue_lock ) ;
2006-01-20 08:47:07 +00:00
mutex_init ( & astd_running ) ;
2006-01-18 09:30:29 +00:00
p = kthread_run ( dlm_astd , NULL , " dlm_astd " ) ;
if ( IS_ERR ( p ) )
error = PTR_ERR ( p ) ;
else
astd_task = p ;
return error ;
}
void dlm_astd_stop ( void )
{
kthread_stop ( astd_task ) ;
}
void dlm_astd_suspend ( void )
{
2006-01-20 08:47:07 +00:00
mutex_lock ( & astd_running ) ;
2006-01-18 09:30:29 +00:00
}
void dlm_astd_resume ( void )
{
2006-01-20 08:47:07 +00:00
mutex_unlock ( & astd_running ) ;
2006-01-18 09:30:29 +00:00
}