2006-01-18 09:30:29 +00:00
/******************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* * Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
* * Copyright ( C ) 2004 - 2005 Red Hat , Inc . All rights reserved .
* *
* * 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 ) ;
}
void dlm_add_ast ( struct dlm_lkb * lkb , int type )
{
2006-07-12 16:44:04 -05:00
if ( lkb - > lkb_flags & DLM_IFL_USER ) {
dlm_user_add_ast ( lkb , type ) ;
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 ;
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 ) ;
2006-01-18 09:30:29 +00:00
int type = 0 , found , bmode ;
for ( ; ; ) {
2006-01-20 08:47:07 +00:00
found = 0 ;
2006-01-18 09:30:29 +00:00
spin_lock ( & ast_queue_lock ) ;
list_for_each_entry ( lkb , & ast_queue , lkb_astqueue ) {
r = lkb - > lkb_resource ;
ls = r - > res_ls ;
if ( dlm_locking_stopped ( ls ) )
continue ;
list_del ( & lkb - > lkb_astqueue ) ;
type = lkb - > lkb_ast_type ;
lkb - > lkb_ast_type = 0 ;
2006-01-20 08:47:07 +00:00
found = 1 ;
2006-01-18 09:30:29 +00:00
break ;
}
spin_unlock ( & ast_queue_lock ) ;
if ( ! found )
break ;
2008-02-06 00:35:45 -06:00
cast = lkb - > lkb_astfn ;
bast = lkb - > lkb_bastfn ;
2006-01-18 09:30:29 +00:00
bmode = lkb - > lkb_bastmode ;
if ( ( type & AST_COMP ) & & cast )
cast ( lkb - > lkb_astparam ) ;
/* FIXME: Is it safe to look at lkb_grmode here
without doing a lock_rsb ( ) ?
Look at other checks in v1 to avoid basts . */
if ( ( type & AST_BAST ) & & bast )
if ( ! dlm_modes_compat ( lkb - > lkb_grmode , bmode ) )
bast ( lkb - > lkb_astparam , bmode ) ;
/* this removes the reference added by dlm_add_ast
and may result in the lkb being freed */
dlm_put_lkb ( lkb ) ;
schedule ( ) ;
}
}
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
}