2006-01-16 19:50:04 +03:00
/*
* Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
2006-05-18 23:09:15 +04:00
* Copyright ( C ) 2004 - 2006 Red Hat , Inc . All rights reserved .
2006-01-16 19:50:04 +03:00
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2006-09-01 19:05:15 +04:00
* of the GNU General Public License version 2.
2006-01-16 19:50:04 +03:00
*/
# include <linux/sched.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/completion.h>
# include <linux/buffer_head.h>
# include <linux/module.h>
# include <linux/kobject.h>
2006-02-28 01:23:27 +03:00
# include <linux/gfs2_ondisk.h>
2006-09-19 09:56:29 +04:00
# include <linux/lm_interface.h>
2006-01-16 19:50:04 +03:00
# include <asm/uaccess.h>
# include "gfs2.h"
2006-02-28 01:23:27 +03:00
# include "incore.h"
2006-01-16 19:50:04 +03:00
# include "lm.h"
# include "sys.h"
# include "super.h"
# include "glock.h"
# include "quota.h"
2006-02-28 01:23:27 +03:00
# include "util.h"
2006-01-16 19:50:04 +03:00
char * gfs2_sys_margs ;
spinlock_t gfs2_sys_margs_lock ;
static ssize_t id_show ( struct gfs2_sbd * sdp , char * buf )
{
2006-09-07 01:57:06 +04:00
return snprintf ( buf , PAGE_SIZE , " %s \n " , sdp - > sd_vfs - > s_id ) ;
2006-01-16 19:50:04 +03:00
}
static ssize_t fsname_show ( struct gfs2_sbd * sdp , char * buf )
{
2006-09-07 01:57:06 +04:00
return snprintf ( buf , PAGE_SIZE , " %s \n " , sdp - > sd_fsname ) ;
2006-01-16 19:50:04 +03:00
}
static ssize_t freeze_show ( struct gfs2_sbd * sdp , char * buf )
{
unsigned int count ;
2006-02-21 15:51:39 +03:00
mutex_lock ( & sdp - > sd_freeze_lock ) ;
2006-01-16 19:50:04 +03:00
count = sdp - > sd_freeze_count ;
2006-02-21 15:51:39 +03:00
mutex_unlock ( & sdp - > sd_freeze_lock ) ;
2006-01-16 19:50:04 +03:00
2006-09-07 01:57:06 +04:00
return snprintf ( buf , PAGE_SIZE , " %u \n " , count ) ;
2006-01-16 19:50:04 +03:00
}
static ssize_t freeze_store ( struct gfs2_sbd * sdp , const char * buf , size_t len )
{
ssize_t ret = len ;
int error = 0 ;
int n = simple_strtol ( buf , NULL , 0 ) ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
switch ( n ) {
case 0 :
gfs2_unfreeze_fs ( sdp ) ;
break ;
case 1 :
error = gfs2_freeze_fs ( sdp ) ;
break ;
default :
ret = - EINVAL ;
}
if ( error )
fs_warn ( sdp , " freeze %d error %d " , n , error ) ;
return ret ;
}
static ssize_t withdraw_show ( struct gfs2_sbd * sdp , char * buf )
{
unsigned int b = test_bit ( SDF_SHUTDOWN , & sdp - > sd_flags ) ;
2006-09-07 01:57:06 +04:00
return snprintf ( buf , PAGE_SIZE , " %u \n " , b ) ;
2006-01-16 19:50:04 +03:00
}
static ssize_t withdraw_store ( struct gfs2_sbd * sdp , const char * buf , size_t len )
{
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
if ( simple_strtol ( buf , NULL , 0 ) ! = 1 )
return - EINVAL ;
gfs2_lm_withdraw ( sdp ,
" GFS2: fsid=%s: withdrawing from cluster at user's request \n " ,
sdp - > sd_fsname ) ;
return len ;
}
static ssize_t statfs_sync_store ( struct gfs2_sbd * sdp , const char * buf ,
size_t len )
{
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
if ( simple_strtol ( buf , NULL , 0 ) ! = 1 )
return - EINVAL ;
gfs2_statfs_sync ( sdp ) ;
return len ;
}
static ssize_t shrink_store ( struct gfs2_sbd * sdp , const char * buf , size_t len )
{
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
if ( simple_strtol ( buf , NULL , 0 ) ! = 1 )
return - EINVAL ;
gfs2_gl_hash_clear ( sdp , NO_WAIT ) ;
return len ;
}
static ssize_t quota_sync_store ( struct gfs2_sbd * sdp , const char * buf ,
size_t len )
{
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
if ( simple_strtol ( buf , NULL , 0 ) ! = 1 )
return - EINVAL ;
gfs2_quota_sync ( sdp ) ;
return len ;
}
static ssize_t quota_refresh_user_store ( struct gfs2_sbd * sdp , const char * buf ,
size_t len )
{
2006-09-04 20:49:07 +04:00
u32 id ;
2006-01-16 19:50:04 +03:00
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
id = simple_strtoul ( buf , NULL , 0 ) ;
gfs2_quota_refresh ( sdp , 1 , id ) ;
return len ;
}
static ssize_t quota_refresh_group_store ( struct gfs2_sbd * sdp , const char * buf ,
size_t len )
{
2006-09-04 20:49:07 +04:00
u32 id ;
2006-01-16 19:50:04 +03:00
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
id = simple_strtoul ( buf , NULL , 0 ) ;
gfs2_quota_refresh ( sdp , 0 , id ) ;
return len ;
}
struct gfs2_attr {
struct attribute attr ;
ssize_t ( * show ) ( struct gfs2_sbd * , char * ) ;
ssize_t ( * store ) ( struct gfs2_sbd * , const char * , size_t ) ;
} ;
# define GFS2_ATTR(name, mode, show, store) \
static struct gfs2_attr gfs2_attr_ # # name = __ATTR ( name , mode , show , store )
GFS2_ATTR ( id , 0444 , id_show , NULL ) ;
GFS2_ATTR ( fsname , 0444 , fsname_show , NULL ) ;
GFS2_ATTR ( freeze , 0644 , freeze_show , freeze_store ) ;
GFS2_ATTR ( shrink , 0200 , NULL , shrink_store ) ;
GFS2_ATTR ( withdraw , 0644 , withdraw_show , withdraw_store ) ;
GFS2_ATTR ( statfs_sync , 0200 , NULL , statfs_sync_store ) ;
GFS2_ATTR ( quota_sync , 0200 , NULL , quota_sync_store ) ;
GFS2_ATTR ( quota_refresh_user , 0200 , NULL , quota_refresh_user_store ) ;
GFS2_ATTR ( quota_refresh_group , 0200 , NULL , quota_refresh_group_store ) ;
static struct attribute * gfs2_attrs [ ] = {
& gfs2_attr_id . attr ,
& gfs2_attr_fsname . attr ,
& gfs2_attr_freeze . attr ,
& gfs2_attr_shrink . attr ,
& gfs2_attr_withdraw . attr ,
& gfs2_attr_statfs_sync . attr ,
& gfs2_attr_quota_sync . attr ,
& gfs2_attr_quota_refresh_user . attr ,
& gfs2_attr_quota_refresh_group . attr ,
NULL ,
} ;
static ssize_t gfs2_attr_show ( struct kobject * kobj , struct attribute * attr ,
char * buf )
{
struct gfs2_sbd * sdp = container_of ( kobj , struct gfs2_sbd , sd_kobj ) ;
struct gfs2_attr * a = container_of ( attr , struct gfs2_attr , attr ) ;
return a - > show ? a - > show ( sdp , buf ) : 0 ;
}
static ssize_t gfs2_attr_store ( struct kobject * kobj , struct attribute * attr ,
const char * buf , size_t len )
{
struct gfs2_sbd * sdp = container_of ( kobj , struct gfs2_sbd , sd_kobj ) ;
struct gfs2_attr * a = container_of ( attr , struct gfs2_attr , attr ) ;
return a - > store ? a - > store ( sdp , buf , len ) : len ;
}
static struct sysfs_ops gfs2_attr_ops = {
. show = gfs2_attr_show ,
. store = gfs2_attr_store ,
} ;
static struct kobj_type gfs2_ktype = {
. default_attrs = gfs2_attrs ,
. sysfs_ops = & gfs2_attr_ops ,
} ;
static struct kset gfs2_kset = {
. subsys = & fs_subsys ,
2006-09-05 23:41:57 +04:00
. kobj = { . name = " gfs2 " } ,
2006-01-16 19:50:04 +03:00
. ktype = & gfs2_ktype ,
} ;
/*
* display struct lm_lockstruct fields
*/
struct lockstruct_attr {
struct attribute attr ;
ssize_t ( * show ) ( struct gfs2_sbd * , char * ) ;
} ;
# define LOCKSTRUCT_ATTR(name, fmt) \
static ssize_t name # # _show ( struct gfs2_sbd * sdp , char * buf ) \
{ \
2006-09-07 01:57:06 +04:00
return snprintf ( buf , PAGE_SIZE , fmt , sdp - > sd_lockstruct . ls_ # # name ) ; \
2006-01-16 19:50:04 +03:00
} \
static struct lockstruct_attr lockstruct_attr_ # # name = __ATTR_RO ( name )
LOCKSTRUCT_ATTR ( jid , " %u \n " ) ;
LOCKSTRUCT_ATTR ( first , " %u \n " ) ;
LOCKSTRUCT_ATTR ( lvb_size , " %u \n " ) ;
LOCKSTRUCT_ATTR ( flags , " %d \n " ) ;
static struct attribute * lockstruct_attrs [ ] = {
& lockstruct_attr_jid . attr ,
& lockstruct_attr_first . attr ,
& lockstruct_attr_lvb_size . attr ,
& lockstruct_attr_flags . attr ,
2006-09-05 18:53:09 +04:00
NULL ,
2006-01-16 19:50:04 +03:00
} ;
/*
* display struct gfs2_args fields
*/
struct args_attr {
struct attribute attr ;
ssize_t ( * show ) ( struct gfs2_sbd * , char * ) ;
} ;
# define ARGS_ATTR(name, fmt) \
static ssize_t name # # _show ( struct gfs2_sbd * sdp , char * buf ) \
{ \
2006-09-07 01:57:06 +04:00
return snprintf ( buf , PAGE_SIZE , fmt , sdp - > sd_args . ar_ # # name ) ; \
2006-01-16 19:50:04 +03:00
} \
static struct args_attr args_attr_ # # name = __ATTR_RO ( name )
ARGS_ATTR ( lockproto , " %s \n " ) ;
ARGS_ATTR ( locktable , " %s \n " ) ;
ARGS_ATTR ( hostdata , " %s \n " ) ;
ARGS_ATTR ( spectator , " %d \n " ) ;
ARGS_ATTR ( ignore_local_fs , " %d \n " ) ;
ARGS_ATTR ( localcaching , " %d \n " ) ;
ARGS_ATTR ( localflocks , " %d \n " ) ;
ARGS_ATTR ( debug , " %d \n " ) ;
ARGS_ATTR ( upgrade , " %d \n " ) ;
ARGS_ATTR ( num_glockd , " %u \n " ) ;
ARGS_ATTR ( posix_acl , " %d \n " ) ;
ARGS_ATTR ( quota , " %u \n " ) ;
ARGS_ATTR ( suiddir , " %d \n " ) ;
ARGS_ATTR ( data , " %d \n " ) ;
/* one oddball doesn't fit the macro mold */
static ssize_t noatime_show ( struct gfs2_sbd * sdp , char * buf )
{
2006-09-07 01:57:06 +04:00
return snprintf ( buf , PAGE_SIZE , " %d \n " ,
! ! test_bit ( SDF_NOATIME , & sdp - > sd_flags ) ) ;
2006-01-16 19:50:04 +03:00
}
static struct args_attr args_attr_noatime = __ATTR_RO ( noatime ) ;
static struct attribute * args_attrs [ ] = {
& args_attr_lockproto . attr ,
& args_attr_locktable . attr ,
& args_attr_hostdata . attr ,
& args_attr_spectator . attr ,
& args_attr_ignore_local_fs . attr ,
& args_attr_localcaching . attr ,
& args_attr_localflocks . attr ,
& args_attr_debug . attr ,
& args_attr_upgrade . attr ,
& args_attr_num_glockd . attr ,
& args_attr_posix_acl . attr ,
& args_attr_quota . attr ,
& args_attr_suiddir . attr ,
& args_attr_data . attr ,
& args_attr_noatime . attr ,
2006-09-05 18:53:09 +04:00
NULL ,
2006-01-16 19:50:04 +03:00
} ;
/*
* display counters from superblock
*/
struct counters_attr {
struct attribute attr ;
ssize_t ( * show ) ( struct gfs2_sbd * , char * ) ;
} ;
2006-02-23 13:11:47 +03:00
# define COUNTERS_ATTR(name, fmt) \
2006-01-16 19:50:04 +03:00
static ssize_t name # # _show ( struct gfs2_sbd * sdp , char * buf ) \
{ \
2006-09-07 01:57:06 +04:00
return snprintf ( buf , PAGE_SIZE , fmt , \
( unsigned int ) atomic_read ( & sdp - > sd_ # # name ) ) ; \
2006-01-16 19:50:04 +03:00
} \
static struct counters_attr counters_attr_ # # name = __ATTR_RO ( name )
2006-02-23 13:11:47 +03:00
COUNTERS_ATTR ( glock_count , " %u \n " ) ;
COUNTERS_ATTR ( glock_held_count , " %u \n " ) ;
COUNTERS_ATTR ( inode_count , " %u \n " ) ;
COUNTERS_ATTR ( reclaimed , " %u \n " ) ;
2006-01-16 19:50:04 +03:00
static struct attribute * counters_attrs [ ] = {
& counters_attr_glock_count . attr ,
& counters_attr_glock_held_count . attr ,
& counters_attr_inode_count . attr ,
& counters_attr_reclaimed . attr ,
2006-09-05 18:53:09 +04:00
NULL ,
2006-01-16 19:50:04 +03:00
} ;
/*
* get and set struct gfs2_tune fields
*/
static ssize_t quota_scale_show ( struct gfs2_sbd * sdp , char * buf )
{
2006-09-07 01:57:06 +04:00
return snprintf ( buf , PAGE_SIZE , " %u %u \n " ,
sdp - > sd_tune . gt_quota_scale_num ,
sdp - > sd_tune . gt_quota_scale_den ) ;
2006-01-16 19:50:04 +03:00
}
static ssize_t quota_scale_store ( struct gfs2_sbd * sdp , const char * buf ,
size_t len )
{
struct gfs2_tune * gt = & sdp - > sd_tune ;
unsigned int x , y ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
if ( sscanf ( buf , " %u %u " , & x , & y ) ! = 2 | | ! y )
return - EINVAL ;
spin_lock ( & gt - > gt_spin ) ;
gt - > gt_quota_scale_num = x ;
gt - > gt_quota_scale_den = y ;
spin_unlock ( & gt - > gt_spin ) ;
return len ;
}
static ssize_t tune_set ( struct gfs2_sbd * sdp , unsigned int * field ,
int check_zero , const char * buf , size_t len )
{
struct gfs2_tune * gt = & sdp - > sd_tune ;
unsigned int x ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
x = simple_strtoul ( buf , NULL , 0 ) ;
if ( check_zero & & ! x )
return - EINVAL ;
spin_lock ( & gt - > gt_spin ) ;
* field = x ;
spin_unlock ( & gt - > gt_spin ) ;
return len ;
}
struct tune_attr {
struct attribute attr ;
ssize_t ( * show ) ( struct gfs2_sbd * , char * ) ;
ssize_t ( * store ) ( struct gfs2_sbd * , const char * , size_t ) ;
} ;
# define TUNE_ATTR_3(name, show, store) \
static struct tune_attr tune_attr_ # # name = __ATTR ( name , 0644 , show , store )
# define TUNE_ATTR_2(name, store) \
static ssize_t name # # _show ( struct gfs2_sbd * sdp , char * buf ) \
{ \
2006-09-07 01:57:06 +04:00
return snprintf ( buf , PAGE_SIZE , " %u \n " , sdp - > sd_tune . gt_ # # name ) ; \
2006-01-16 19:50:04 +03:00
} \
TUNE_ATTR_3 ( name , name # # _show , store )
# define TUNE_ATTR(name, check_zero) \
static ssize_t name # # _store ( struct gfs2_sbd * sdp , const char * buf , size_t len ) \
{ \
return tune_set ( sdp , & sdp - > sd_tune . gt_ # # name , check_zero , buf , len ) ; \
} \
TUNE_ATTR_2 ( name , name # # _store )
# define TUNE_ATTR_DAEMON(name, process) \
static ssize_t name # # _store ( struct gfs2_sbd * sdp , const char * buf , size_t len ) \
{ \
ssize_t r = tune_set ( sdp , & sdp - > sd_tune . gt_ # # name , 1 , buf , len ) ; \
wake_up_process ( sdp - > sd_ # # process ) ; \
return r ; \
} \
TUNE_ATTR_2 ( name , name # # _store )
TUNE_ATTR ( demote_secs , 0 ) ;
TUNE_ATTR ( incore_log_blocks , 0 ) ;
TUNE_ATTR ( log_flush_secs , 0 ) ;
TUNE_ATTR ( jindex_refresh_secs , 0 ) ;
TUNE_ATTR ( quota_warn_period , 0 ) ;
TUNE_ATTR ( quota_quantum , 0 ) ;
TUNE_ATTR ( atime_quantum , 0 ) ;
TUNE_ATTR ( max_readahead , 0 ) ;
TUNE_ATTR ( complain_secs , 0 ) ;
TUNE_ATTR ( reclaim_limit , 0 ) ;
TUNE_ATTR ( prefetch_secs , 0 ) ;
TUNE_ATTR ( statfs_slow , 0 ) ;
TUNE_ATTR ( new_files_jdata , 0 ) ;
TUNE_ATTR ( new_files_directio , 0 ) ;
TUNE_ATTR ( quota_simul_sync , 1 ) ;
TUNE_ATTR ( quota_cache_secs , 1 ) ;
TUNE_ATTR ( max_atomic_write , 1 ) ;
TUNE_ATTR ( stall_secs , 1 ) ;
TUNE_ATTR ( greedy_default , 1 ) ;
TUNE_ATTR ( greedy_quantum , 1 ) ;
TUNE_ATTR ( greedy_max , 1 ) ;
TUNE_ATTR ( statfs_quantum , 1 ) ;
TUNE_ATTR_DAEMON ( scand_secs , scand_process ) ;
TUNE_ATTR_DAEMON ( recoverd_secs , recoverd_process ) ;
TUNE_ATTR_DAEMON ( logd_secs , logd_process ) ;
TUNE_ATTR_DAEMON ( quotad_secs , quotad_process ) ;
TUNE_ATTR_3 ( quota_scale , quota_scale_show , quota_scale_store ) ;
static struct attribute * tune_attrs [ ] = {
& tune_attr_demote_secs . attr ,
& tune_attr_incore_log_blocks . attr ,
& tune_attr_log_flush_secs . attr ,
& tune_attr_jindex_refresh_secs . attr ,
& tune_attr_quota_warn_period . attr ,
& tune_attr_quota_quantum . attr ,
& tune_attr_atime_quantum . attr ,
& tune_attr_max_readahead . attr ,
& tune_attr_complain_secs . attr ,
& tune_attr_reclaim_limit . attr ,
& tune_attr_prefetch_secs . attr ,
& tune_attr_statfs_slow . attr ,
& tune_attr_quota_simul_sync . attr ,
& tune_attr_quota_cache_secs . attr ,
& tune_attr_max_atomic_write . attr ,
& tune_attr_stall_secs . attr ,
& tune_attr_greedy_default . attr ,
& tune_attr_greedy_quantum . attr ,
& tune_attr_greedy_max . attr ,
& tune_attr_statfs_quantum . attr ,
& tune_attr_scand_secs . attr ,
& tune_attr_recoverd_secs . attr ,
& tune_attr_logd_secs . attr ,
& tune_attr_quotad_secs . attr ,
& tune_attr_quota_scale . attr ,
& tune_attr_new_files_jdata . attr ,
& tune_attr_new_files_directio . attr ,
2006-09-05 18:53:09 +04:00
NULL ,
2006-01-16 19:50:04 +03:00
} ;
static struct attribute_group lockstruct_group = {
. name = " lockstruct " ,
2006-09-05 18:53:09 +04:00
. attrs = lockstruct_attrs ,
2006-01-16 19:50:04 +03:00
} ;
static struct attribute_group counters_group = {
. name = " counters " ,
2006-09-05 18:53:09 +04:00
. attrs = counters_attrs ,
2006-01-16 19:50:04 +03:00
} ;
static struct attribute_group args_group = {
. name = " args " ,
2006-09-05 18:53:09 +04:00
. attrs = args_attrs ,
2006-01-16 19:50:04 +03:00
} ;
static struct attribute_group tune_group = {
. name = " tune " ,
2006-09-05 18:53:09 +04:00
. attrs = tune_attrs ,
2006-01-16 19:50:04 +03:00
} ;
int gfs2_sys_fs_add ( struct gfs2_sbd * sdp )
{
int error ;
sdp - > sd_kobj . kset = & gfs2_kset ;
sdp - > sd_kobj . ktype = & gfs2_ktype ;
error = kobject_set_name ( & sdp - > sd_kobj , " %s " , sdp - > sd_table_name ) ;
if ( error )
goto fail ;
error = kobject_register ( & sdp - > sd_kobj ) ;
if ( error )
goto fail ;
error = sysfs_create_group ( & sdp - > sd_kobj , & lockstruct_group ) ;
if ( error )
goto fail_reg ;
error = sysfs_create_group ( & sdp - > sd_kobj , & counters_group ) ;
if ( error )
goto fail_lockstruct ;
error = sysfs_create_group ( & sdp - > sd_kobj , & args_group ) ;
if ( error )
goto fail_counters ;
error = sysfs_create_group ( & sdp - > sd_kobj , & tune_group ) ;
if ( error )
goto fail_args ;
return 0 ;
2006-09-04 20:04:26 +04:00
fail_args :
2006-01-16 19:50:04 +03:00
sysfs_remove_group ( & sdp - > sd_kobj , & args_group ) ;
2006-09-04 20:04:26 +04:00
fail_counters :
2006-01-16 19:50:04 +03:00
sysfs_remove_group ( & sdp - > sd_kobj , & counters_group ) ;
2006-09-04 20:04:26 +04:00
fail_lockstruct :
2006-01-16 19:50:04 +03:00
sysfs_remove_group ( & sdp - > sd_kobj , & lockstruct_group ) ;
2006-09-04 20:04:26 +04:00
fail_reg :
2006-01-16 19:50:04 +03:00
kobject_unregister ( & sdp - > sd_kobj ) ;
2006-09-04 20:04:26 +04:00
fail :
2006-09-15 22:09:11 +04:00
fs_err ( sdp , " error %d adding sysfs files " , error ) ;
2006-01-16 19:50:04 +03:00
return error ;
}
void gfs2_sys_fs_del ( struct gfs2_sbd * sdp )
{
sysfs_remove_group ( & sdp - > sd_kobj , & tune_group ) ;
sysfs_remove_group ( & sdp - > sd_kobj , & args_group ) ;
sysfs_remove_group ( & sdp - > sd_kobj , & counters_group ) ;
sysfs_remove_group ( & sdp - > sd_kobj , & lockstruct_group ) ;
kobject_unregister ( & sdp - > sd_kobj ) ;
}
int gfs2_sys_init ( void )
{
gfs2_sys_margs = NULL ;
spin_lock_init ( & gfs2_sys_margs_lock ) ;
return kset_register ( & gfs2_kset ) ;
}
void gfs2_sys_uninit ( void )
{
kfree ( gfs2_sys_margs ) ;
kset_unregister ( & gfs2_kset ) ;
}