2006-01-18 09:30:29 +00:00
/******************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
2009-01-07 16:48:52 -06:00
* * Copyright ( C ) 2005 - 2009 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 <linux/pagemap.h>
# include <linux/seq_file.h>
# include <linux/module.h>
# include <linux/ctype.h>
# include <linux/debugfs.h>
# include "dlm_internal.h"
2007-05-16 15:56:13 -04:00
# include "lock.h"
2006-01-18 09:30:29 +00:00
2006-07-25 13:44:31 -05:00
# define DLM_DEBUG_BUF_LEN 4096
static char debug_buf [ DLM_DEBUG_BUF_LEN ] ;
static struct mutex debug_buf_lock ;
2006-01-18 09:30:29 +00:00
static struct dentry * dlm_root ;
static char * print_lockmode ( int mode )
{
switch ( mode ) {
case DLM_LOCK_IV :
return " -- " ;
case DLM_LOCK_NL :
return " NL " ;
case DLM_LOCK_CR :
return " CR " ;
case DLM_LOCK_CW :
return " CW " ;
case DLM_LOCK_PR :
return " PR " ;
case DLM_LOCK_PW :
return " PW " ;
case DLM_LOCK_EX :
return " EX " ;
default :
return " ?? " ;
}
}
2009-01-07 16:48:52 -06:00
static int print_format1_lock ( struct seq_file * s , struct dlm_lkb * lkb ,
struct dlm_rsb * res )
2006-01-18 09:30:29 +00:00
{
seq_printf ( s , " %08x %s " , lkb - > lkb_id , print_lockmode ( lkb - > lkb_grmode ) ) ;
2009-01-07 16:48:52 -06:00
if ( lkb - > lkb_status = = DLM_LKSTS_CONVERT | |
lkb - > lkb_status = = DLM_LKSTS_WAITING )
2006-01-18 09:30:29 +00:00
seq_printf ( s , " (%s) " , print_lockmode ( lkb - > lkb_rqmode ) ) ;
if ( lkb - > lkb_nodeid ) {
if ( lkb - > lkb_nodeid ! = res - > res_nodeid )
seq_printf ( s , " Remote: %3d %08x " , lkb - > lkb_nodeid ,
lkb - > lkb_remid ) ;
else
seq_printf ( s , " Master: %08x " , lkb - > lkb_remid ) ;
}
if ( lkb - > lkb_wait_type )
seq_printf ( s , " wait_type: %d " , lkb - > lkb_wait_type ) ;
2009-01-07 16:48:52 -06:00
return seq_printf ( s , " \n " ) ;
2006-01-18 09:30:29 +00:00
}
2008-12-16 14:53:23 -06:00
static int print_format1 ( struct dlm_rsb * res , struct seq_file * s )
2006-01-18 09:30:29 +00:00
{
struct dlm_lkb * lkb ;
2006-07-25 13:44:31 -05:00
int i , lvblen = res - > res_ls - > ls_lvblen , recover_list , root_list ;
2009-01-07 16:48:52 -06:00
int rv ;
2006-01-18 09:30:29 +00:00
2007-05-29 08:47:04 -05:00
lock_rsb ( res ) ;
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " \n Resource %p Name (len=%d) \" " ,
res , res - > res_length ) ;
if ( rv )
goto out ;
2006-01-18 09:30:29 +00:00
for ( i = 0 ; i < res - > res_length ; i + + ) {
if ( isprint ( res - > res_name [ i ] ) )
seq_printf ( s , " %c " , res - > res_name [ i ] ) ;
else
seq_printf ( s , " %c " , ' . ' ) ;
}
2009-01-07 16:48:52 -06:00
2006-01-18 09:30:29 +00:00
if ( res - > res_nodeid > 0 )
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " \" \n Local Copy, Master is node %d \n " ,
res - > res_nodeid ) ;
2006-01-18 09:30:29 +00:00
else if ( res - > res_nodeid = = 0 )
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " \" \n Master Copy \n " ) ;
2006-01-18 09:30:29 +00:00
else if ( res - > res_nodeid = = - 1 )
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " \" \n Looking up master (lkid %x) \n " ,
res - > res_first_lkid ) ;
2006-01-18 09:30:29 +00:00
else
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " \" \n Invalid master %d \n " ,
res - > res_nodeid ) ;
if ( rv )
goto out ;
2006-01-18 09:30:29 +00:00
/* Print the LVB: */
if ( res - > res_lvbptr ) {
seq_printf ( s , " LVB: " ) ;
for ( i = 0 ; i < lvblen ; i + + ) {
if ( i = = lvblen / 2 )
seq_printf ( s , " \n " ) ;
seq_printf ( s , " %02x " ,
( unsigned char ) res - > res_lvbptr [ i ] ) ;
}
if ( rsb_flag ( res , RSB_VALNOTVALID ) )
seq_printf ( s , " (INVALID) " ) ;
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " \n " ) ;
if ( rv )
goto out ;
2006-01-18 09:30:29 +00:00
}
2006-07-25 13:44:31 -05:00
root_list = ! list_empty ( & res - > res_root_list ) ;
recover_list = ! list_empty ( & res - > res_recover_list ) ;
if ( root_list | | recover_list ) {
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " Recovery: root %d recover %d flags %lx "
" count %d \n " , root_list , recover_list ,
res - > res_flags , res - > res_recover_locks_count ) ;
if ( rv )
goto out ;
2006-07-25 13:44:31 -05:00
}
2006-01-18 09:30:29 +00:00
/* Print the locks attached to this resource */
seq_printf ( s , " Granted Queue \n " ) ;
2009-01-07 16:48:52 -06:00
list_for_each_entry ( lkb , & res - > res_grantqueue , lkb_statequeue ) {
rv = print_format1_lock ( s , lkb , res ) ;
if ( rv )
goto out ;
}
2006-01-18 09:30:29 +00:00
seq_printf ( s , " Conversion Queue \n " ) ;
2009-01-07 16:48:52 -06:00
list_for_each_entry ( lkb , & res - > res_convertqueue , lkb_statequeue ) {
rv = print_format1_lock ( s , lkb , res ) ;
if ( rv )
goto out ;
}
2006-01-18 09:30:29 +00:00
seq_printf ( s , " Waiting Queue \n " ) ;
2009-01-07 16:48:52 -06:00
list_for_each_entry ( lkb , & res - > res_waitqueue , lkb_statequeue ) {
rv = print_format1_lock ( s , lkb , res ) ;
if ( rv )
goto out ;
}
2006-01-18 09:30:29 +00:00
2006-07-25 13:44:31 -05:00
if ( list_empty ( & res - > res_lookup ) )
goto out ;
seq_printf ( s , " Lookup Queue \n " ) ;
list_for_each_entry ( lkb , & res - > res_lookup , lkb_rsb_lookup ) {
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " %08x %s " , lkb - > lkb_id ,
print_lockmode ( lkb - > lkb_rqmode ) ) ;
2006-07-25 13:44:31 -05:00
if ( lkb - > lkb_wait_type )
seq_printf ( s , " wait_type: %d " , lkb - > lkb_wait_type ) ;
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " \n " ) ;
2006-07-25 13:44:31 -05:00
}
out :
2007-05-29 08:47:04 -05:00
unlock_rsb ( res ) ;
2009-01-07 16:48:52 -06:00
return rv ;
2007-05-29 08:47:04 -05:00
}
2009-01-07 16:48:52 -06:00
static int print_format2_lock ( struct seq_file * s , struct dlm_lkb * lkb ,
struct dlm_rsb * r )
2007-05-29 08:47:04 -05:00
{
2008-12-09 14:12:21 -06:00
u64 xid = 0 ;
u64 us ;
2009-01-07 16:48:52 -06:00
int rv ;
2007-05-29 08:47:04 -05:00
if ( lkb - > lkb_flags & DLM_IFL_USER ) {
2008-02-06 23:27:04 -06:00
if ( lkb - > lkb_ua )
xid = lkb - > lkb_ua - > xid ;
2007-05-29 08:47:04 -05:00
}
2008-12-09 14:12:21 -06:00
/* microseconds since lkb was added to current queue */
us = ktime_to_us ( ktime_sub ( ktime_get ( ) , lkb - > lkb_timestamp ) ) ;
2007-05-29 08:47:04 -05:00
2008-12-09 14:12:21 -06:00
/* id nodeid remid pid xid exflags flags sts grmode rqmode time_us
2007-07-06 09:47:08 -05:00
r_nodeid r_len r_name */
2007-05-29 08:47:04 -05:00
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " %x %d %x %u %llu %x %x %d %d %d %llu %u %d \" %s \" \n " ,
lkb - > lkb_id ,
lkb - > lkb_nodeid ,
lkb - > lkb_remid ,
lkb - > lkb_ownpid ,
( unsigned long long ) xid ,
lkb - > lkb_exflags ,
lkb - > lkb_flags ,
lkb - > lkb_status ,
lkb - > lkb_grmode ,
lkb - > lkb_rqmode ,
( unsigned long long ) us ,
r - > res_nodeid ,
r - > res_length ,
r - > res_name ) ;
return rv ;
2007-05-29 08:47:04 -05:00
}
2008-12-16 14:53:23 -06:00
static int print_format2 ( struct dlm_rsb * r , struct seq_file * s )
2007-05-29 08:47:04 -05:00
{
struct dlm_lkb * lkb ;
2009-01-07 16:48:52 -06:00
int rv = 0 ;
2007-05-29 08:47:04 -05:00
lock_rsb ( r ) ;
2009-01-07 16:48:52 -06:00
list_for_each_entry ( lkb , & r - > res_grantqueue , lkb_statequeue ) {
rv = print_format2_lock ( s , lkb , r ) ;
if ( rv )
goto out ;
}
2007-05-29 08:47:04 -05:00
2009-01-07 16:48:52 -06:00
list_for_each_entry ( lkb , & r - > res_convertqueue , lkb_statequeue ) {
rv = print_format2_lock ( s , lkb , r ) ;
if ( rv )
goto out ;
}
2008-12-16 14:53:23 -06:00
2009-01-07 16:48:52 -06:00
list_for_each_entry ( lkb , & r - > res_waitqueue , lkb_statequeue ) {
rv = print_format2_lock ( s , lkb , r ) ;
if ( rv )
goto out ;
}
out :
2008-12-16 14:53:23 -06:00
unlock_rsb ( r ) ;
2009-01-07 16:48:52 -06:00
return rv ;
2008-12-16 14:53:23 -06:00
}
2009-01-07 16:48:52 -06:00
static int print_format3_lock ( struct seq_file * s , struct dlm_lkb * lkb ,
int rsb_lookup )
2008-12-16 14:53:23 -06:00
{
u64 xid = 0 ;
2009-01-07 16:48:52 -06:00
int rv ;
2008-12-16 14:53:23 -06:00
if ( lkb - > lkb_flags & DLM_IFL_USER ) {
if ( lkb - > lkb_ua )
xid = lkb - > lkb_ua - > xid ;
}
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu \n " ,
lkb - > lkb_id ,
lkb - > lkb_nodeid ,
lkb - > lkb_remid ,
lkb - > lkb_ownpid ,
( unsigned long long ) xid ,
lkb - > lkb_exflags ,
lkb - > lkb_flags ,
lkb - > lkb_status ,
lkb - > lkb_grmode ,
lkb - > lkb_rqmode ,
lkb - > lkb_highbast ,
rsb_lookup ,
lkb - > lkb_wait_type ,
lkb - > lkb_lvbseq ,
( unsigned long long ) ktime_to_ns ( lkb - > lkb_timestamp ) ,
( unsigned long long ) ktime_to_ns ( lkb - > lkb_time_bast ) ) ;
return rv ;
2008-12-16 14:53:23 -06:00
}
static int print_format3 ( struct dlm_rsb * r , struct seq_file * s )
{
struct dlm_lkb * lkb ;
int i , lvblen = r - > res_ls - > ls_lvblen ;
int print_name = 1 ;
2009-01-07 16:48:52 -06:00
int rv ;
2008-12-16 14:53:23 -06:00
lock_rsb ( r ) ;
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " rsb %p %d %x %lx %d %d %u %d " ,
r ,
r - > res_nodeid ,
r - > res_first_lkid ,
r - > res_flags ,
! list_empty ( & r - > res_root_list ) ,
! list_empty ( & r - > res_recover_list ) ,
r - > res_recover_locks_count ,
r - > res_length ) ;
if ( rv )
goto out ;
2008-12-16 14:53:23 -06:00
for ( i = 0 ; i < r - > res_length ; i + + ) {
if ( ! isascii ( r - > res_name [ i ] ) | | ! isprint ( r - > res_name [ i ] ) )
print_name = 0 ;
}
seq_printf ( s , " %s " , print_name ? " str " : " hex " ) ;
for ( i = 0 ; i < r - > res_length ; i + + ) {
if ( print_name )
seq_printf ( s , " %c " , r - > res_name [ i ] ) ;
else
seq_printf ( s , " %02x " , ( unsigned char ) r - > res_name [ i ] ) ;
}
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " \n " ) ;
if ( rv )
goto out ;
2008-12-16 14:53:23 -06:00
if ( ! r - > res_lvbptr )
goto do_locks ;
seq_printf ( s , " lvb %u %d " , r - > res_lvbseq , lvblen ) ;
for ( i = 0 ; i < lvblen ; i + + )
seq_printf ( s , " %02x " , ( unsigned char ) r - > res_lvbptr [ i ] ) ;
2009-01-07 16:48:52 -06:00
rv = seq_printf ( s , " \n " ) ;
if ( rv )
goto out ;
2008-12-16 14:53:23 -06:00
do_locks :
2009-01-07 16:48:52 -06:00
list_for_each_entry ( lkb , & r - > res_grantqueue , lkb_statequeue ) {
rv = print_format3_lock ( s , lkb , 0 ) ;
if ( rv )
goto out ;
2006-01-18 09:30:29 +00:00
}
2009-01-07 16:48:52 -06:00
list_for_each_entry ( lkb , & r - > res_convertqueue , lkb_statequeue ) {
rv = print_format3_lock ( s , lkb , 0 ) ;
if ( rv )
goto out ;
2006-01-18 09:30:29 +00:00
}
2009-01-07 16:48:52 -06:00
list_for_each_entry ( lkb , & r - > res_waitqueue , lkb_statequeue ) {
rv = print_format3_lock ( s , lkb , 0 ) ;
if ( rv )
goto out ;
2006-01-18 09:30:29 +00:00
}
2009-01-07 16:48:52 -06:00
list_for_each_entry ( lkb , & r - > res_lookup , lkb_rsb_lookup ) {
rv = print_format3_lock ( s , lkb , 1 ) ;
if ( rv )
goto out ;
2006-01-18 09:30:29 +00:00
}
2009-01-07 16:48:52 -06:00
out :
unlock_rsb ( r ) ;
return rv ;
2006-01-18 09:30:29 +00:00
}
2009-01-07 16:48:52 -06:00
struct rsbtbl_iter {
struct dlm_rsb * rsb ;
unsigned bucket ;
int format ;
int header ;
} ;
2006-01-18 09:30:29 +00:00
2009-01-07 16:48:52 -06:00
/* seq_printf returns -1 if the buffer is full, and 0 otherwise.
If the buffer is full , seq_printf can be called again , but it
does nothing and just returns - 1. So , the these printing routines
periodically check the return value to avoid wasting too much time
trying to print to a full buffer . */
static int table_seq_show ( struct seq_file * seq , void * iter_ptr )
2006-01-18 09:30:29 +00:00
{
2009-01-07 16:48:52 -06:00
struct rsbtbl_iter * ri = iter_ptr ;
int rv = 0 ;
2006-01-18 09:30:29 +00:00
2008-12-16 14:53:23 -06:00
switch ( ri - > format ) {
case 1 :
2009-01-07 16:48:52 -06:00
rv = print_format1 ( ri - > rsb , seq ) ;
2008-12-16 14:53:23 -06:00
break ;
case 2 :
2007-05-29 08:47:04 -05:00
if ( ri - > header ) {
2009-01-07 16:48:52 -06:00
seq_printf ( seq , " id nodeid remid pid xid exflags "
" flags sts grmode rqmode time_ms "
" r_nodeid r_len r_name \n " ) ;
2007-05-29 08:47:04 -05:00
ri - > header = 0 ;
}
2009-01-07 16:48:52 -06:00
rv = print_format2 ( ri - > rsb , seq ) ;
2008-12-16 14:53:23 -06:00
break ;
case 3 :
if ( ri - > header ) {
2009-01-07 16:48:52 -06:00
seq_printf ( seq , " version rsb 1.1 lvb 1.1 lkb 1.1 \n " ) ;
2008-12-16 14:53:23 -06:00
ri - > header = 0 ;
}
2009-01-07 16:48:52 -06:00
rv = print_format3 ( ri - > rsb , seq ) ;
2008-12-16 14:53:23 -06:00
break ;
2007-05-29 08:47:04 -05:00
}
2006-01-18 09:30:29 +00:00
2009-01-07 16:48:52 -06:00
return rv ;
2006-01-18 09:30:29 +00:00
}
2009-09-22 16:43:43 -07:00
static const struct seq_operations format1_seq_ops ;
static const struct seq_operations format2_seq_ops ;
static const struct seq_operations format3_seq_ops ;
2006-01-18 09:30:29 +00:00
2009-01-07 16:48:52 -06:00
static void * table_seq_start ( struct seq_file * seq , loff_t * pos )
2006-01-18 09:30:29 +00:00
{
2009-01-07 16:48:52 -06:00
struct dlm_ls * ls = seq - > private ;
struct rsbtbl_iter * ri ;
struct dlm_rsb * r ;
loff_t n = * pos ;
unsigned bucket , entry ;
2006-01-18 09:30:29 +00:00
2009-01-07 16:48:52 -06:00
bucket = n > > 32 ;
entry = n & ( ( 1LL < < 32 ) - 1 ) ;
2007-05-29 08:47:04 -05:00
2009-01-07 16:48:52 -06:00
if ( bucket > = ls - > ls_rsbtbl_size )
return NULL ;
2007-05-29 08:47:04 -05:00
2009-11-30 16:34:43 -06:00
ri = kzalloc ( sizeof ( struct rsbtbl_iter ) , GFP_NOFS ) ;
2007-05-29 08:47:04 -05:00
if ( ! ri )
return NULL ;
2009-01-07 16:48:52 -06:00
if ( n = = 0 )
2007-05-29 08:47:04 -05:00
ri - > header = 1 ;
2009-01-07 16:48:52 -06:00
if ( seq - > op = = & format1_seq_ops )
ri - > format = 1 ;
if ( seq - > op = = & format2_seq_ops )
ri - > format = 2 ;
if ( seq - > op = = & format3_seq_ops )
ri - > format = 3 ;
2009-01-07 16:50:41 -06:00
spin_lock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2009-01-07 16:48:52 -06:00
if ( ! list_empty ( & ls - > ls_rsbtbl [ bucket ] . list ) ) {
list_for_each_entry ( r , & ls - > ls_rsbtbl [ bucket ] . list ,
res_hashchain ) {
if ( ! entry - - ) {
dlm_hold_rsb ( r ) ;
ri - > rsb = r ;
ri - > bucket = bucket ;
2009-01-07 16:50:41 -06:00
spin_unlock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2009-01-07 16:48:52 -06:00
return ri ;
}
}
2007-05-29 08:47:04 -05:00
}
2009-01-07 16:50:41 -06:00
spin_unlock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2007-05-29 08:47:04 -05:00
2009-01-07 16:48:52 -06:00
/*
* move to the first rsb in the next non - empty bucket
*/
2007-05-29 08:47:04 -05:00
2009-01-07 16:48:52 -06:00
/* zero the entry */
n & = ~ ( ( 1LL < < 32 ) - 1 ) ;
2007-05-29 08:47:04 -05:00
2009-01-07 16:48:52 -06:00
while ( 1 ) {
bucket + + ;
n + = 1LL < < 32 ;
2007-05-29 08:47:04 -05:00
2009-01-07 16:48:52 -06:00
if ( bucket > = ls - > ls_rsbtbl_size ) {
kfree ( ri ) ;
2007-05-29 08:47:04 -05:00
return NULL ;
}
2009-01-07 16:50:41 -06:00
spin_lock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2009-01-07 16:48:52 -06:00
if ( ! list_empty ( & ls - > ls_rsbtbl [ bucket ] . list ) ) {
r = list_first_entry ( & ls - > ls_rsbtbl [ bucket ] . list ,
struct dlm_rsb , res_hashchain ) ;
dlm_hold_rsb ( r ) ;
ri - > rsb = r ;
ri - > bucket = bucket ;
2009-01-07 16:50:41 -06:00
spin_unlock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2009-01-07 16:48:52 -06:00
* pos = n ;
return ri ;
}
2009-01-07 16:50:41 -06:00
spin_unlock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2009-01-07 16:48:52 -06:00
}
2007-05-29 08:47:04 -05:00
}
2009-01-07 16:48:52 -06:00
static void * table_seq_next ( struct seq_file * seq , void * iter_ptr , loff_t * pos )
2007-05-29 08:47:04 -05:00
{
2009-01-07 16:48:52 -06:00
struct dlm_ls * ls = seq - > private ;
struct rsbtbl_iter * ri = iter_ptr ;
struct list_head * next ;
struct dlm_rsb * r , * rp ;
loff_t n = * pos ;
unsigned bucket ;
bucket = n > > 32 ;
/*
* move to the next rsb in the same bucket
*/
2009-01-07 16:50:41 -06:00
spin_lock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2009-01-07 16:48:52 -06:00
rp = ri - > rsb ;
next = rp - > res_hashchain . next ;
if ( next ! = & ls - > ls_rsbtbl [ bucket ] . list ) {
r = list_entry ( next , struct dlm_rsb , res_hashchain ) ;
dlm_hold_rsb ( r ) ;
ri - > rsb = r ;
2009-01-07 16:50:41 -06:00
spin_unlock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2009-01-07 16:48:52 -06:00
dlm_put_rsb ( rp ) ;
+ + * pos ;
return ri ;
}
2009-01-07 16:50:41 -06:00
spin_unlock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2009-01-07 16:48:52 -06:00
dlm_put_rsb ( rp ) ;
2008-12-16 14:53:23 -06:00
2009-01-07 16:48:52 -06:00
/*
* move to the first rsb in the next non - empty bucket
*/
2008-12-16 14:53:23 -06:00
2009-01-07 16:48:52 -06:00
/* zero the entry */
n & = ~ ( ( 1LL < < 32 ) - 1 ) ;
2008-12-16 14:53:23 -06:00
2009-01-07 16:48:52 -06:00
while ( 1 ) {
bucket + + ;
n + = 1LL < < 32 ;
2008-12-16 14:53:23 -06:00
2009-01-07 16:48:52 -06:00
if ( bucket > = ls - > ls_rsbtbl_size ) {
kfree ( ri ) ;
return NULL ;
}
2008-12-16 14:53:23 -06:00
2009-01-07 16:50:41 -06:00
spin_lock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2009-01-07 16:48:52 -06:00
if ( ! list_empty ( & ls - > ls_rsbtbl [ bucket ] . list ) ) {
r = list_first_entry ( & ls - > ls_rsbtbl [ bucket ] . list ,
struct dlm_rsb , res_hashchain ) ;
dlm_hold_rsb ( r ) ;
ri - > rsb = r ;
ri - > bucket = bucket ;
2009-01-07 16:50:41 -06:00
spin_unlock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2009-01-07 16:48:52 -06:00
* pos = n ;
return ri ;
}
2009-01-07 16:50:41 -06:00
spin_unlock ( & ls - > ls_rsbtbl [ bucket ] . lock ) ;
2008-12-16 14:53:23 -06:00
}
}
2009-01-07 16:48:52 -06:00
static void table_seq_stop ( struct seq_file * seq , void * iter_ptr )
2008-12-16 14:53:23 -06:00
{
2009-01-07 16:48:52 -06:00
struct rsbtbl_iter * ri = iter_ptr ;
2008-12-16 14:53:23 -06:00
2009-01-07 16:48:52 -06:00
if ( ri ) {
dlm_put_rsb ( ri - > rsb ) ;
kfree ( ri ) ;
2008-12-16 14:53:23 -06:00
}
}
2009-09-22 16:43:43 -07:00
static const struct seq_operations format1_seq_ops = {
2009-01-07 16:48:52 -06:00
. start = table_seq_start ,
. next = table_seq_next ,
. stop = table_seq_stop ,
. show = table_seq_show ,
2008-12-16 14:53:23 -06:00
} ;
2009-09-22 16:43:43 -07:00
static const struct seq_operations format2_seq_ops = {
2009-01-07 16:48:52 -06:00
. start = table_seq_start ,
. next = table_seq_next ,
. stop = table_seq_stop ,
. show = table_seq_show ,
} ;
2009-09-22 16:43:43 -07:00
static const struct seq_operations format3_seq_ops = {
2009-01-07 16:48:52 -06:00
. start = table_seq_start ,
. next = table_seq_next ,
. stop = table_seq_stop ,
. show = table_seq_show ,
} ;
static const struct file_operations format1_fops ;
static const struct file_operations format2_fops ;
static const struct file_operations format3_fops ;
static int table_open ( struct inode * inode , struct file * file )
2008-12-16 14:53:23 -06:00
{
struct seq_file * seq ;
2009-01-07 16:48:52 -06:00
int ret = - 1 ;
if ( file - > f_op = = & format1_fops )
ret = seq_open ( file , & format1_seq_ops ) ;
else if ( file - > f_op = = & format2_fops )
ret = seq_open ( file , & format2_seq_ops ) ;
else if ( file - > f_op = = & format3_fops )
ret = seq_open ( file , & format3_seq_ops ) ;
2008-12-16 14:53:23 -06:00
if ( ret )
return ret ;
seq = file - > private_data ;
2009-01-07 16:48:52 -06:00
seq - > private = inode - > i_private ; /* the dlm_ls */
2008-12-16 14:53:23 -06:00
return 0 ;
}
2009-01-07 16:48:52 -06:00
static const struct file_operations format1_fops = {
. owner = THIS_MODULE ,
. open = table_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release
} ;
static const struct file_operations format2_fops = {
. owner = THIS_MODULE ,
. open = table_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release
} ;
static const struct file_operations format3_fops = {
2008-12-16 14:53:23 -06:00
. owner = THIS_MODULE ,
2009-01-07 16:48:52 -06:00
. open = table_open ,
2008-12-16 14:53:23 -06:00
. read = seq_read ,
. llseek = seq_lseek ,
. release = seq_release
} ;
2006-07-25 13:44:31 -05:00
/*
* dump lkb ' s on the ls_waiters list
*/
static int waiters_open ( struct inode * inode , struct file * file )
{
2006-09-27 01:50:31 -07:00
file - > private_data = inode - > i_private ;
2006-07-25 13:44:31 -05:00
return 0 ;
}
static ssize_t waiters_read ( struct file * file , char __user * userbuf ,
size_t count , loff_t * ppos )
{
struct dlm_ls * ls = file - > private_data ;
struct dlm_lkb * lkb ;
2006-08-08 11:31:30 -05:00
size_t len = DLM_DEBUG_BUF_LEN , pos = 0 , ret , rv ;
2006-07-25 13:44:31 -05:00
mutex_lock ( & debug_buf_lock ) ;
mutex_lock ( & ls - > ls_waiters_mutex ) ;
memset ( debug_buf , 0 , sizeof ( debug_buf ) ) ;
list_for_each_entry ( lkb , & ls - > ls_waiters , lkb_wait_reply ) {
2006-08-08 11:31:30 -05:00
ret = snprintf ( debug_buf + pos , len - pos , " %x %d %d %s \n " ,
lkb - > lkb_id , lkb - > lkb_wait_type ,
lkb - > lkb_nodeid , lkb - > lkb_resource - > res_name ) ;
if ( ret > = len - pos )
break ;
pos + = ret ;
2006-07-25 13:44:31 -05:00
}
mutex_unlock ( & ls - > ls_waiters_mutex ) ;
rv = simple_read_from_buffer ( userbuf , count , ppos , debug_buf , pos ) ;
mutex_unlock ( & debug_buf_lock ) ;
return rv ;
}
2007-02-12 00:55:34 -08:00
static const struct file_operations waiters_fops = {
2006-07-25 13:44:31 -05:00
. owner = THIS_MODULE ,
. open = waiters_open ,
. read = waiters_read
} ;
2008-12-16 14:53:23 -06:00
void dlm_delete_debug_file ( struct dlm_ls * ls )
{
if ( ls - > ls_debug_rsb_dentry )
debugfs_remove ( ls - > ls_debug_rsb_dentry ) ;
if ( ls - > ls_debug_waiters_dentry )
debugfs_remove ( ls - > ls_debug_waiters_dentry ) ;
if ( ls - > ls_debug_locks_dentry )
debugfs_remove ( ls - > ls_debug_locks_dentry ) ;
if ( ls - > ls_debug_all_dentry )
debugfs_remove ( ls - > ls_debug_all_dentry ) ;
}
2006-01-18 09:30:29 +00:00
int dlm_create_debug_file ( struct dlm_ls * ls )
{
2006-07-25 13:44:31 -05:00
char name [ DLM_LOCKSPACE_LEN + 8 ] ;
2008-12-16 14:53:23 -06:00
/* format 1 */
2006-07-25 13:44:31 -05:00
ls - > ls_debug_rsb_dentry = debugfs_create_file ( ls - > ls_name ,
S_IFREG | S_IRUGO ,
dlm_root ,
ls ,
2009-01-07 16:48:52 -06:00
& format1_fops ) ;
2006-07-26 08:29:06 -05:00
if ( ! ls - > ls_debug_rsb_dentry )
2008-12-16 14:53:23 -06:00
goto fail ;
2006-07-25 13:44:31 -05:00
2008-12-16 14:53:23 -06:00
/* format 2 */
2006-07-25 13:44:31 -05:00
2007-05-29 08:47:04 -05:00
memset ( name , 0 , sizeof ( name ) ) ;
2007-07-06 09:47:08 -05:00
snprintf ( name , DLM_LOCKSPACE_LEN + 8 , " %s_locks " , ls - > ls_name ) ;
ls - > ls_debug_locks_dentry = debugfs_create_file ( name ,
S_IFREG | S_IRUGO ,
dlm_root ,
ls ,
2009-01-07 16:48:52 -06:00
& format2_fops ) ;
2008-12-16 14:53:23 -06:00
if ( ! ls - > ls_debug_locks_dentry )
goto fail ;
/* format 3 */
memset ( name , 0 , sizeof ( name ) ) ;
snprintf ( name , DLM_LOCKSPACE_LEN + 8 , " %s_all " , ls - > ls_name ) ;
ls - > ls_debug_all_dentry = debugfs_create_file ( name ,
S_IFREG | S_IRUGO ,
dlm_root ,
ls ,
2009-01-07 16:48:52 -06:00
& format3_fops ) ;
2008-12-16 14:53:23 -06:00
if ( ! ls - > ls_debug_all_dentry )
goto fail ;
memset ( name , 0 , sizeof ( name ) ) ;
snprintf ( name , DLM_LOCKSPACE_LEN + 8 , " %s_waiters " , ls - > ls_name ) ;
ls - > ls_debug_waiters_dentry = debugfs_create_file ( name ,
S_IFREG | S_IRUGO ,
dlm_root ,
ls ,
& waiters_fops ) ;
if ( ! ls - > ls_debug_waiters_dentry )
goto fail ;
2007-05-29 08:47:04 -05:00
2006-07-25 13:44:31 -05:00
return 0 ;
2006-01-18 09:30:29 +00:00
2008-12-16 14:53:23 -06:00
fail :
dlm_delete_debug_file ( ls ) ;
return - ENOMEM ;
2006-01-18 09:30:29 +00:00
}
2008-02-02 01:53:46 +08:00
int __init dlm_register_debugfs ( void )
2006-01-18 09:30:29 +00:00
{
2006-07-25 13:44:31 -05:00
mutex_init ( & debug_buf_lock ) ;
2006-01-18 09:30:29 +00:00
dlm_root = debugfs_create_dir ( " dlm " , NULL ) ;
return dlm_root ? 0 : - ENOMEM ;
}
void dlm_unregister_debugfs ( void )
{
debugfs_remove ( dlm_root ) ;
}