2019-05-28 09:57:20 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2006-01-18 09:30:29 +00:00
/******************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* * Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
2010-02-24 11:08:18 -06:00
* * Copyright ( C ) 2004 - 2010 Red Hat , Inc . All rights reserved .
2006-01-18 09:30:29 +00:00
* *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-11-02 15:17:15 -04:00
# include <trace/events/dlm.h>
2006-01-18 09:30:29 +00:00
# include "dlm_internal.h"
2022-10-27 16:45:21 -04:00
# include "memory.h"
2006-01-18 09:30:29 +00:00
# include "lock.h"
2006-07-12 16:44:04 -05:00
# include "user.h"
2014-02-09 18:19:17 +05:30
# include "ast.h"
2006-01-18 09:30:29 +00:00
2022-10-27 16:45:21 -04:00
void dlm_release_callback ( struct kref * ref )
{
struct dlm_callback * cb = container_of ( ref , struct dlm_callback , ref ) ;
dlm_free_cb ( cb ) ;
}
void dlm_callback_set_last_ptr ( struct dlm_callback * * from ,
struct dlm_callback * to )
{
if ( * from )
kref_put ( & ( * from ) - > ref , dlm_release_callback ) ;
if ( to )
kref_get ( & to - > ref ) ;
* from = to ;
}
2006-01-18 09:30:29 +00:00
2022-10-27 16:45:21 -04:00
int dlm_enqueue_lkb_callback ( struct dlm_lkb * lkb , uint32_t flags , int mode ,
int status , uint32_t sbflags )
2011-02-21 14:58:21 -06:00
{
struct dlm_ls * ls = lkb - > lkb_resource - > res_ls ;
2022-10-27 16:45:21 -04:00
int rv = DLM_ENQUEUE_CALLBACK_SUCCESS ;
struct dlm_callback * cb ;
2011-02-21 14:58:21 -06:00
int prev_mode ;
2022-10-27 16:45:21 -04:00
if ( flags & DLM_CB_BAST ) {
/* if cb is a bast, it should be skipped if the blocking mode is
* compatible with the last granted mode
*/
if ( lkb - > lkb_last_cast ) {
if ( dlm_modes_compat ( mode , lkb - > lkb_last_cast - > mode ) ) {
log_debug ( ls , " skip %x bast mode %d for cast mode %d " ,
lkb - > lkb_id , mode ,
lkb - > lkb_last_cast - > mode ) ;
goto out ;
}
}
2011-02-21 14:58:21 -06:00
/*
* Suppress some redundant basts here , do more on removal .
* Don ' t even add a bast if the callback just before it
* is a bast for the same mode or a more restrictive mode .
* ( the addional > PR check is needed for PR / CW inversion )
*/
2022-10-27 16:45:21 -04:00
if ( lkb - > lkb_last_cb & & lkb - > lkb_last_cb - > flags & DLM_CB_BAST ) {
prev_mode = lkb - > lkb_last_cb - > mode ;
2011-02-21 14:58:21 -06:00
if ( ( prev_mode = = mode ) | |
( prev_mode > mode & & prev_mode > DLM_LOCK_PR ) ) {
2022-10-27 16:45:21 -04:00
log_debug ( ls , " skip %x add bast mode %d for bast mode %d " ,
lkb - > lkb_id , mode , prev_mode ) ;
2011-04-05 13:16:24 -05:00
goto out ;
2011-02-21 14:58:21 -06:00
}
}
}
2022-10-27 16:45:21 -04:00
cb = dlm_allocate_cb ( ) ;
if ( ! cb ) {
rv = DLM_ENQUEUE_CALLBACK_FAILURE ;
2011-04-05 13:16:24 -05:00
goto out ;
2011-02-21 14:58:21 -06:00
}
2022-10-27 16:45:21 -04:00
cb - > flags = flags ;
cb - > mode = mode ;
cb - > sb_status = status ;
cb - > sb_flags = ( sbflags & 0x000000FF ) ;
kref_init ( & cb - > ref ) ;
2023-03-06 15:48:08 -05:00
if ( ! test_and_set_bit ( DLM_IFL_CB_PENDING_BIT , & lkb - > lkb_iflags ) )
2022-10-27 16:45:21 -04:00
rv = DLM_ENQUEUE_CALLBACK_NEED_SCHED ;
2023-03-06 15:48:08 -05:00
2022-10-27 16:45:21 -04:00
list_add_tail ( & cb - > list , & lkb - > lkb_callbacks ) ;
2011-02-21 14:58:21 -06:00
2022-10-27 16:45:21 -04:00
if ( flags & DLM_CB_CAST )
dlm_callback_set_last_ptr ( & lkb - > lkb_last_cast , cb ) ;
2011-02-21 14:58:21 -06:00
2022-10-27 16:45:21 -04:00
dlm_callback_set_last_ptr ( & lkb - > lkb_last_cb , cb ) ;
2011-02-21 14:58:21 -06:00
2011-04-05 13:16:24 -05:00
out :
return rv ;
2011-02-21 14:58:21 -06:00
}
2022-10-27 16:45:21 -04:00
int dlm_dequeue_lkb_callback ( struct dlm_lkb * lkb , struct dlm_callback * * cb )
{
/* oldest undelivered cb is callbacks first entry */
* cb = list_first_entry_or_null ( & lkb - > lkb_callbacks ,
struct dlm_callback , list ) ;
if ( ! * cb )
return DLM_DEQUEUE_CALLBACK_EMPTY ;
/* remove it from callbacks so shift others down */
list_del ( & ( * cb ) - > list ) ;
if ( list_empty ( & lkb - > lkb_callbacks ) )
return DLM_DEQUEUE_CALLBACK_LAST ;
return DLM_DEQUEUE_CALLBACK_SUCCESS ;
}
2011-04-05 13:16:24 -05:00
void dlm_add_cb ( struct dlm_lkb * lkb , uint32_t flags , int mode , int status ,
uint32_t sbflags )
2011-02-21 14:58:21 -06:00
{
2011-04-05 13:16:24 -05:00
struct dlm_ls * ls = lkb - > lkb_resource - > res_ls ;
2011-02-21 14:58:21 -06:00
int rv ;
2023-03-06 15:48:15 -05:00
if ( test_bit ( DLM_DFL_USER_BIT , & lkb - > lkb_dflags ) ) {
2022-10-27 16:45:21 -04:00
dlm_user_add_ast ( lkb , flags , mode , status , sbflags ) ;
2006-07-12 16:44:04 -05:00
return ;
}
2022-10-27 16:45:19 -04:00
spin_lock ( & lkb - > lkb_cb_lock ) ;
2022-10-27 16:45:21 -04:00
rv = dlm_enqueue_lkb_callback ( lkb , flags , mode , status , sbflags ) ;
switch ( rv ) {
case DLM_ENQUEUE_CALLBACK_NEED_SCHED :
2006-01-18 09:30:29 +00:00
kref_get ( & lkb - > lkb_ref ) ;
2022-10-27 16:45:18 -04:00
spin_lock ( & ls - > ls_cb_lock ) ;
2011-04-05 13:16:24 -05:00
if ( test_bit ( LSFL_CB_DELAY , & ls - > ls_flags ) ) {
list_add ( & lkb - > lkb_cb_list , & ls - > ls_cb_delay ) ;
} else {
queue_work ( ls - > ls_callback_wq , & lkb - > lkb_cb_work ) ;
}
2022-10-27 16:45:18 -04:00
spin_unlock ( & ls - > ls_cb_lock ) ;
2022-10-27 16:45:21 -04:00
break ;
case DLM_ENQUEUE_CALLBACK_FAILURE :
2022-11-17 17:11:42 -05:00
WARN_ON_ONCE ( 1 ) ;
2022-10-27 16:45:21 -04:00
break ;
case DLM_ENQUEUE_CALLBACK_SUCCESS :
break ;
default :
2022-11-17 17:11:42 -05:00
WARN_ON_ONCE ( 1 ) ;
2022-10-27 16:45:21 -04:00
break ;
2011-04-05 13:16:24 -05:00
}
2022-10-27 16:45:19 -04:00
spin_unlock ( & lkb - > lkb_cb_lock ) ;
2006-01-18 09:30:29 +00:00
}
2011-04-05 13:16:24 -05:00
void dlm_callback_work ( struct work_struct * work )
2006-01-18 09:30:29 +00:00
{
2011-04-05 13:16:24 -05:00
struct dlm_lkb * lkb = container_of ( work , struct dlm_lkb , lkb_cb_work ) ;
struct dlm_ls * ls = lkb - > lkb_resource - > res_ls ;
2010-02-24 11:08:18 -06:00
void ( * castfn ) ( void * astparam ) ;
void ( * bastfn ) ( void * astparam , int mode ) ;
2022-10-27 16:45:21 -04:00
struct dlm_callback * cb ;
int rv ;
2006-01-18 09:30:29 +00:00
2022-10-27 16:45:19 -04:00
spin_lock ( & lkb - > lkb_cb_lock ) ;
2022-10-27 16:45:21 -04:00
rv = dlm_dequeue_lkb_callback ( lkb , & cb ) ;
2023-05-29 17:44:30 -04:00
if ( WARN_ON_ONCE ( rv = = DLM_DEQUEUE_CALLBACK_EMPTY ) ) {
clear_bit ( DLM_IFL_CB_PENDING_BIT , & lkb - > lkb_iflags ) ;
spin_unlock ( & lkb - > lkb_cb_lock ) ;
2022-11-17 17:11:41 -05:00
goto out ;
2023-05-29 17:44:30 -04:00
}
spin_unlock ( & lkb - > lkb_cb_lock ) ;
2010-02-24 11:08:18 -06:00
2022-10-27 16:45:21 -04:00
for ( ; ; ) {
castfn = lkb - > lkb_astfn ;
bastfn = lkb - > lkb_bastfn ;
if ( cb - > flags & DLM_CB_BAST ) {
trace_dlm_bast ( ls , lkb , cb - > mode ) ;
2022-10-27 16:45:20 -04:00
lkb - > lkb_last_bast_time = ktime_get ( ) ;
2022-10-27 16:45:21 -04:00
lkb - > lkb_last_bast_mode = cb - > mode ;
bastfn ( lkb - > lkb_astparam , cb - > mode ) ;
} else if ( cb - > flags & DLM_CB_CAST ) {
lkb - > lkb_lksb - > sb_status = cb - > sb_status ;
lkb - > lkb_lksb - > sb_flags = cb - > sb_flags ;
2022-06-22 14:45:11 -04:00
trace_dlm_ast ( ls , lkb ) ;
2022-10-27 16:45:20 -04:00
lkb - > lkb_last_cast_time = ktime_get ( ) ;
2022-06-22 14:45:10 -04:00
castfn ( lkb - > lkb_astparam ) ;
2010-02-24 11:08:18 -06:00
}
2022-10-27 16:45:21 -04:00
kref_put ( & cb - > ref , dlm_release_callback ) ;
spin_lock ( & lkb - > lkb_cb_lock ) ;
rv = dlm_dequeue_lkb_callback ( lkb , & cb ) ;
if ( rv = = DLM_DEQUEUE_CALLBACK_EMPTY ) {
2023-03-06 15:48:08 -05:00
clear_bit ( DLM_IFL_CB_PENDING_BIT , & lkb - > lkb_iflags ) ;
2022-10-27 16:45:21 -04:00
spin_unlock ( & lkb - > lkb_cb_lock ) ;
break ;
}
spin_unlock ( & lkb - > lkb_cb_lock ) ;
2006-01-18 09:30:29 +00:00
}
2022-11-17 17:11:41 -05:00
out :
2011-04-05 13:16:24 -05:00
/* undo kref_get from dlm_add_callback, may cause lkb to be freed */
dlm_put_lkb ( lkb ) ;
2006-01-18 09:30:29 +00:00
}
2011-04-05 13:16:24 -05:00
int dlm_callback_start ( struct dlm_ls * ls )
2006-01-18 09:30:29 +00:00
{
2011-04-05 13:16:24 -05:00
ls - > ls_callback_wq = alloc_workqueue ( " dlm_callback " ,
2016-10-19 11:34:54 -04:00
WQ_HIGHPRI | WQ_MEM_RECLAIM , 0 ) ;
2011-04-05 13:16:24 -05:00
if ( ! ls - > ls_callback_wq ) {
log_print ( " can't start dlm_callback workqueue " ) ;
return - ENOMEM ;
2006-01-18 09:30:29 +00:00
}
return 0 ;
}
2011-04-05 13:16:24 -05:00
void dlm_callback_stop ( struct dlm_ls * ls )
2006-01-18 09:30:29 +00:00
{
2011-04-05 13:16:24 -05:00
if ( ls - > ls_callback_wq )
destroy_workqueue ( ls - > ls_callback_wq ) ;
2006-01-18 09:30:29 +00:00
}
2011-04-05 13:16:24 -05:00
void dlm_callback_suspend ( struct dlm_ls * ls )
2006-01-18 09:30:29 +00:00
{
2022-08-15 15:43:26 -04:00
if ( ls - > ls_callback_wq ) {
2022-10-27 16:45:18 -04:00
spin_lock ( & ls - > ls_cb_lock ) ;
2022-08-15 15:43:26 -04:00
set_bit ( LSFL_CB_DELAY , & ls - > ls_flags ) ;
2022-10-27 16:45:18 -04:00
spin_unlock ( & ls - > ls_cb_lock ) ;
2006-01-18 09:30:29 +00:00
2011-04-05 13:16:24 -05:00
flush_workqueue ( ls - > ls_callback_wq ) ;
2022-08-15 15:43:26 -04:00
}
2006-01-18 09:30:29 +00:00
}
2018-11-08 14:04:50 -05:00
# define MAX_CB_QUEUE 25
2011-04-05 13:16:24 -05:00
void dlm_callback_resume ( struct dlm_ls * ls )
2006-01-18 09:30:29 +00:00
{
2011-04-05 13:16:24 -05:00
struct dlm_lkb * lkb , * safe ;
2021-11-02 15:17:14 -04:00
int count = 0 , sum = 0 ;
2021-11-30 14:47:14 -05:00
bool empty ;
2006-01-18 09:30:29 +00:00
2011-04-05 13:16:24 -05:00
if ( ! ls - > ls_callback_wq )
return ;
2018-11-08 14:04:50 -05:00
more :
2022-10-27 16:45:18 -04:00
spin_lock ( & ls - > ls_cb_lock ) ;
2011-04-05 13:16:24 -05:00
list_for_each_entry_safe ( lkb , safe , & ls - > ls_cb_delay , lkb_cb_list ) {
list_del_init ( & lkb - > lkb_cb_list ) ;
queue_work ( ls - > ls_callback_wq , & lkb - > lkb_cb_work ) ;
count + + ;
2018-11-08 14:04:50 -05:00
if ( count = = MAX_CB_QUEUE )
break ;
2011-04-05 13:16:24 -05:00
}
2021-11-30 14:47:14 -05:00
empty = list_empty ( & ls - > ls_cb_delay ) ;
2022-10-27 16:45:16 -04:00
if ( empty )
clear_bit ( LSFL_CB_DELAY , & ls - > ls_flags ) ;
2022-10-27 16:45:18 -04:00
spin_unlock ( & ls - > ls_cb_lock ) ;
2011-04-05 13:16:24 -05:00
2021-11-02 15:17:14 -04:00
sum + = count ;
2021-11-30 14:47:14 -05:00
if ( ! empty ) {
2018-11-08 14:04:50 -05:00
count = 0 ;
cond_resched ( ) ;
goto more ;
}
2021-11-02 15:17:14 -04:00
if ( sum )
log_rinfo ( ls , " %s %d " , __func__ , sum ) ;
2006-01-18 09:30:29 +00:00
}