2008-01-30 04:37:32 +03:00
/* -*- mode: c; c-basic-offset: 8; -*-
* vim : noexpandtab sw = 8 ts = 8 sts = 0 :
*
* stackglue . c
*
* Code which implements an OCFS2 specific interface to underlying
* cluster stacks .
*
2009-06-20 02:14:13 +04:00
* Copyright ( C ) 2007 , 2009 Oracle . All rights reserved .
2008-01-30 04:37:32 +03:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation , version 2.
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*/
2008-02-02 02:03:57 +03:00
# include <linux/list.h>
# include <linux/spinlock.h>
# include <linux/module.h>
2008-02-02 01:39:35 +03:00
# include <linux/slab.h>
2008-01-30 03:59:56 +03:00
# include <linux/kmod.h>
2008-02-01 10:56:17 +03:00
# include <linux/fs.h>
# include <linux/kobject.h>
# include <linux/sysfs.h>
2008-05-31 02:30:49 +04:00
# include <linux/sysctl.h>
2008-02-02 01:39:35 +03:00
2008-02-02 02:17:30 +03:00
# include "ocfs2_fs.h"
2008-02-02 02:03:57 +03:00
# include "stackglue.h"
2008-02-02 01:39:35 +03:00
2008-02-02 02:17:30 +03:00
# define OCFS2_STACK_PLUGIN_O2CB "o2cb"
# define OCFS2_STACK_PLUGIN_USER "user"
2008-05-31 02:43:58 +04:00
# define OCFS2_MAX_HB_CTL_PATH 256
2008-02-02 02:17:30 +03:00
2010-01-30 04:19:06 +03:00
static struct ocfs2_protocol_version locking_max_version ;
2008-02-02 02:03:57 +03:00
static DEFINE_SPINLOCK ( ocfs2_stack_lock ) ;
static LIST_HEAD ( ocfs2_stack_list ) ;
2008-02-02 02:17:30 +03:00
static char cluster_stack_name [ OCFS2_STACK_LABEL_LEN + 1 ] ;
2008-05-31 02:43:58 +04:00
static char ocfs2_hb_ctl_path [ OCFS2_MAX_HB_CTL_PATH ] = " /sbin/ocfs2_hb_ctl " ;
2008-01-31 02:38:24 +03:00
2008-02-02 02:03:57 +03:00
/*
* The stack currently in use . If not null , active_stack - > sp_count > 0 ,
* the module is pinned , and the locking protocol cannot be changed .
*/
static struct ocfs2_stack_plugin * active_stack ;
static struct ocfs2_stack_plugin * ocfs2_stack_lookup ( const char * name )
{
struct ocfs2_stack_plugin * p ;
assert_spin_locked ( & ocfs2_stack_lock ) ;
list_for_each_entry ( p , & ocfs2_stack_list , sp_list ) {
if ( ! strcmp ( p - > sp_name , name ) )
return p ;
}
return NULL ;
}
2008-02-02 02:17:30 +03:00
static int ocfs2_stack_driver_request ( const char * stack_name ,
const char * plugin_name )
2008-02-02 02:03:57 +03:00
{
int rc ;
struct ocfs2_stack_plugin * p ;
spin_lock ( & ocfs2_stack_lock ) ;
2008-02-02 02:17:30 +03:00
/*
* If the stack passed by the filesystem isn ' t the selected one ,
* we can ' t continue .
*/
if ( strcmp ( stack_name , cluster_stack_name ) ) {
rc = - EBUSY ;
goto out ;
}
2008-02-02 02:03:57 +03:00
if ( active_stack ) {
/*
* If the active stack isn ' t the one we want , it cannot
* be selected right now .
*/
2008-02-02 02:17:30 +03:00
if ( ! strcmp ( active_stack - > sp_name , plugin_name ) )
2008-02-02 02:03:57 +03:00
rc = 0 ;
else
rc = - EBUSY ;
goto out ;
}
2008-02-02 02:17:30 +03:00
p = ocfs2_stack_lookup ( plugin_name ) ;
2008-02-02 02:03:57 +03:00
if ( ! p | | ! try_module_get ( p - > sp_owner ) ) {
rc = - ENOENT ;
goto out ;
}
active_stack = p ;
rc = 0 ;
out :
2008-08-23 01:30:10 +04:00
/* If we found it, pin it */
if ( ! rc )
active_stack - > sp_count + + ;
2008-02-02 02:03:57 +03:00
spin_unlock ( & ocfs2_stack_lock ) ;
return rc ;
}
/*
* This function looks up the appropriate stack and makes it active . If
* there is no stack , it tries to load it . It will fail if the stack still
* cannot be found . It will also fail if a different stack is in use .
*/
2008-02-02 02:17:30 +03:00
static int ocfs2_stack_driver_get ( const char * stack_name )
2008-02-02 02:03:57 +03:00
{
int rc ;
2008-02-02 02:17:30 +03:00
char * plugin_name = OCFS2_STACK_PLUGIN_O2CB ;
/*
* Classic stack does not pass in a stack name . This is
* compatible with older tools as well .
*/
if ( ! stack_name | | ! * stack_name )
stack_name = OCFS2_STACK_PLUGIN_O2CB ;
if ( strlen ( stack_name ) ! = OCFS2_STACK_LABEL_LEN ) {
printk ( KERN_ERR
" ocfs2 passed an invalid cluster stack label: \" %s \" \n " ,
stack_name ) ;
return - EINVAL ;
}
2008-02-02 02:03:57 +03:00
2008-02-02 02:17:30 +03:00
/* Anything that isn't the classic stack is a user stack */
if ( strcmp ( stack_name , OCFS2_STACK_PLUGIN_O2CB ) )
plugin_name = OCFS2_STACK_PLUGIN_USER ;
rc = ocfs2_stack_driver_request ( stack_name , plugin_name ) ;
2008-02-02 02:03:57 +03:00
if ( rc = = - ENOENT ) {
2008-02-02 02:17:30 +03:00
request_module ( " ocfs2_stack_%s " , plugin_name ) ;
rc = ocfs2_stack_driver_request ( stack_name , plugin_name ) ;
2008-02-02 02:03:57 +03:00
}
if ( rc = = - ENOENT ) {
printk ( KERN_ERR
" ocfs2: Cluster stack driver \" %s \" cannot be found \n " ,
2008-02-02 02:17:30 +03:00
plugin_name ) ;
2008-02-02 02:03:57 +03:00
} else if ( rc = = - EBUSY ) {
printk ( KERN_ERR
2008-02-02 02:17:30 +03:00
" ocfs2: A different cluster stack is in use \n " ) ;
2008-02-02 02:03:57 +03:00
}
return rc ;
}
2008-01-30 04:37:32 +03:00
2008-02-02 02:03:57 +03:00
static void ocfs2_stack_driver_put ( void )
{
spin_lock ( & ocfs2_stack_lock ) ;
BUG_ON ( active_stack = = NULL ) ;
BUG_ON ( active_stack - > sp_count = = 0 ) ;
active_stack - > sp_count - - ;
if ( ! active_stack - > sp_count ) {
module_put ( active_stack - > sp_owner ) ;
active_stack = NULL ;
}
spin_unlock ( & ocfs2_stack_lock ) ;
}
int ocfs2_stack_glue_register ( struct ocfs2_stack_plugin * plugin )
{
int rc ;
spin_lock ( & ocfs2_stack_lock ) ;
if ( ! ocfs2_stack_lookup ( plugin - > sp_name ) ) {
plugin - > sp_count = 0 ;
2010-01-30 04:19:06 +03:00
plugin - > sp_max_proto = locking_max_version ;
2008-02-02 02:03:57 +03:00
list_add ( & plugin - > sp_list , & ocfs2_stack_list ) ;
printk ( KERN_INFO " ocfs2: Registered cluster interface %s \n " ,
plugin - > sp_name ) ;
rc = 0 ;
} else {
printk ( KERN_ERR " ocfs2: Stack \" %s \" already registered \n " ,
plugin - > sp_name ) ;
rc = - EEXIST ;
}
spin_unlock ( & ocfs2_stack_lock ) ;
return rc ;
}
EXPORT_SYMBOL_GPL ( ocfs2_stack_glue_register ) ;
void ocfs2_stack_glue_unregister ( struct ocfs2_stack_plugin * plugin )
{
struct ocfs2_stack_plugin * p ;
spin_lock ( & ocfs2_stack_lock ) ;
p = ocfs2_stack_lookup ( plugin - > sp_name ) ;
if ( p ) {
BUG_ON ( p ! = plugin ) ;
BUG_ON ( plugin = = active_stack ) ;
BUG_ON ( plugin - > sp_count ! = 0 ) ;
list_del_init ( & plugin - > sp_list ) ;
printk ( KERN_INFO " ocfs2: Unregistered cluster interface %s \n " ,
plugin - > sp_name ) ;
} else {
printk ( KERN_ERR " Stack \" %s \" is not registered \n " ,
plugin - > sp_name ) ;
}
spin_unlock ( & ocfs2_stack_lock ) ;
}
EXPORT_SYMBOL_GPL ( ocfs2_stack_glue_unregister ) ;
2010-01-30 04:19:06 +03:00
void ocfs2_stack_glue_set_max_proto_version ( struct ocfs2_protocol_version * max_proto )
2008-02-02 02:03:57 +03:00
{
struct ocfs2_stack_plugin * p ;
spin_lock ( & ocfs2_stack_lock ) ;
2010-01-30 04:19:06 +03:00
if ( memcmp ( max_proto , & locking_max_version ,
sizeof ( struct ocfs2_protocol_version ) ) ) {
BUG_ON ( locking_max_version . pv_major ! = 0 ) ;
2008-02-02 02:03:57 +03:00
2010-01-30 04:19:06 +03:00
locking_max_version = * max_proto ;
list_for_each_entry ( p , & ocfs2_stack_list , sp_list ) {
p - > sp_max_proto = locking_max_version ;
}
2008-02-02 02:03:57 +03:00
}
spin_unlock ( & ocfs2_stack_lock ) ;
}
2010-01-30 04:19:06 +03:00
EXPORT_SYMBOL_GPL ( ocfs2_stack_glue_set_max_proto_version ) ;
2008-02-01 23:15:37 +03:00
2008-01-30 04:37:32 +03:00
2008-02-21 01:29:27 +03:00
/*
2010-01-29 06:22:39 +03:00
* The ocfs2_dlm_lock ( ) and ocfs2_dlm_unlock ( ) functions take no argument
* for the ast and bast functions . They will pass the lksb to the ast
* and bast . The caller can wrap the lksb with their own structure to
* get more information .
2008-02-21 01:29:27 +03:00
*/
2008-02-02 01:51:03 +03:00
int ocfs2_dlm_lock ( struct ocfs2_cluster_connection * conn ,
int mode ,
2010-01-30 01:46:44 +03:00
struct ocfs2_dlm_lksb * lksb ,
2008-02-02 01:51:03 +03:00
u32 flags ,
void * name ,
2010-01-29 06:22:39 +03:00
unsigned int namelen )
2008-02-02 01:51:03 +03:00
{
2010-01-30 01:46:44 +03:00
if ( ! lksb - > lksb_conn )
lksb - > lksb_conn = conn ;
else
BUG_ON ( lksb - > lksb_conn ! = conn ) ;
2008-02-02 02:03:57 +03:00
return active_stack - > sp_ops - > dlm_lock ( conn , mode , lksb , flags ,
2010-01-29 06:22:39 +03:00
name , namelen ) ;
2008-01-30 04:37:32 +03:00
}
2008-02-02 02:03:57 +03:00
EXPORT_SYMBOL_GPL ( ocfs2_dlm_lock ) ;
2008-01-30 04:37:32 +03:00
2008-02-02 01:51:03 +03:00
int ocfs2_dlm_unlock ( struct ocfs2_cluster_connection * conn ,
2010-01-30 01:46:44 +03:00
struct ocfs2_dlm_lksb * lksb ,
2010-01-29 06:22:39 +03:00
u32 flags )
2008-02-02 01:51:03 +03:00
{
2010-01-30 01:46:44 +03:00
BUG_ON ( lksb - > lksb_conn = = NULL ) ;
2008-02-02 01:51:03 +03:00
2010-01-29 06:22:39 +03:00
return active_stack - > sp_ops - > dlm_unlock ( conn , lksb , flags ) ;
2008-02-01 23:16:57 +03:00
}
2008-02-02 02:03:57 +03:00
EXPORT_SYMBOL_GPL ( ocfs2_dlm_unlock ) ;
2008-02-01 23:16:57 +03:00
2010-01-30 01:46:44 +03:00
int ocfs2_dlm_lock_status ( struct ocfs2_dlm_lksb * lksb )
2008-02-02 01:51:03 +03:00
{
2008-02-02 02:03:57 +03:00
return active_stack - > sp_ops - > lock_status ( lksb ) ;
2008-02-02 01:51:03 +03:00
}
2008-02-02 02:03:57 +03:00
EXPORT_SYMBOL_GPL ( ocfs2_dlm_lock_status ) ;
2008-02-02 01:51:03 +03:00
2010-01-30 01:46:44 +03:00
int ocfs2_dlm_lvb_valid ( struct ocfs2_dlm_lksb * lksb )
2009-06-20 02:14:13 +04:00
{
return active_stack - > sp_ops - > lvb_valid ( lksb ) ;
}
EXPORT_SYMBOL_GPL ( ocfs2_dlm_lvb_valid ) ;
2010-01-30 01:46:44 +03:00
void * ocfs2_dlm_lvb ( struct ocfs2_dlm_lksb * lksb )
2008-02-02 01:51:03 +03:00
{
2008-02-02 02:03:57 +03:00
return active_stack - > sp_ops - > lock_lvb ( lksb ) ;
2008-01-30 03:59:55 +03:00
}
2008-02-02 02:03:57 +03:00
EXPORT_SYMBOL_GPL ( ocfs2_dlm_lvb ) ;
2008-01-30 03:59:55 +03:00
2010-01-30 01:46:44 +03:00
void ocfs2_dlm_dump_lksb ( struct ocfs2_dlm_lksb * lksb )
2008-02-02 01:51:03 +03:00
{
2008-02-02 02:03:57 +03:00
active_stack - > sp_ops - > dump_lksb ( lksb ) ;
2008-02-02 01:51:03 +03:00
}
2008-02-02 02:03:57 +03:00
EXPORT_SYMBOL_GPL ( ocfs2_dlm_dump_lksb ) ;
2008-02-02 01:51:03 +03:00
2008-07-22 01:29:16 +04:00
int ocfs2_stack_supports_plocks ( void )
{
2008-10-07 03:16:08 +04:00
return active_stack & & active_stack - > sp_ops - > plock ;
2008-07-22 01:29:16 +04:00
}
EXPORT_SYMBOL_GPL ( ocfs2_stack_supports_plocks ) ;
/*
* ocfs2_plock ( ) can only be safely called if
* ocfs2_stack_supports_plocks ( ) returned true
*/
int ocfs2_plock ( struct ocfs2_cluster_connection * conn , u64 ino ,
struct file * file , int cmd , struct file_lock * fl )
{
WARN_ON_ONCE ( active_stack - > sp_ops - > plock = = NULL ) ;
if ( active_stack - > sp_ops - > plock )
return active_stack - > sp_ops - > plock ( conn , ino , file , cmd , fl ) ;
return - EOPNOTSUPP ;
}
EXPORT_SYMBOL_GPL ( ocfs2_plock ) ;
2008-02-02 02:17:30 +03:00
int ocfs2_cluster_connect ( const char * stack_name ,
2014-01-22 03:48:21 +04:00
const char * cluster_name ,
int cluster_name_len ,
2008-02-02 02:17:30 +03:00
const char * group ,
2008-02-02 01:39:35 +03:00
int grouplen ,
2010-01-30 04:19:06 +03:00
struct ocfs2_locking_protocol * lproto ,
2008-02-02 01:39:35 +03:00
void ( * recovery_handler ) ( int node_num ,
void * recovery_data ) ,
void * recovery_data ,
struct ocfs2_cluster_connection * * conn )
{
int rc = 0 ;
struct ocfs2_cluster_connection * new_conn ;
BUG_ON ( group = = NULL ) ;
BUG_ON ( conn = = NULL ) ;
BUG_ON ( recovery_handler = = NULL ) ;
if ( grouplen > GROUP_NAME_MAX ) {
rc = - EINVAL ;
goto out ;
}
2010-01-30 04:19:06 +03:00
if ( memcmp ( & lproto - > lp_max_version , & locking_max_version ,
sizeof ( struct ocfs2_protocol_version ) ) ) {
rc = - EINVAL ;
goto out ;
}
2008-02-02 01:39:35 +03:00
new_conn = kzalloc ( sizeof ( struct ocfs2_cluster_connection ) ,
GFP_KERNEL ) ;
if ( ! new_conn ) {
rc = - ENOMEM ;
goto out ;
}
2014-01-22 03:48:21 +04:00
strlcpy ( new_conn - > cc_name , group , GROUP_NAME_MAX + 1 ) ;
2008-02-02 01:39:35 +03:00
new_conn - > cc_namelen = grouplen ;
2014-01-22 03:48:21 +04:00
strlcpy ( new_conn - > cc_cluster_name , cluster_name , CLUSTER_NAME_MAX + 1 ) ;
new_conn - > cc_cluster_name_len = cluster_name_len ;
2008-02-02 01:39:35 +03:00
new_conn - > cc_recovery_handler = recovery_handler ;
new_conn - > cc_recovery_data = recovery_data ;
2010-01-30 02:46:23 +03:00
new_conn - > cc_proto = lproto ;
2008-02-02 01:39:35 +03:00
/* Start the new connection at our maximum compatibility level */
2008-02-02 02:03:57 +03:00
new_conn - > cc_version = lproto - > lp_max_version ;
/* This will pin the stack driver if successful */
2008-02-02 02:17:30 +03:00
rc = ocfs2_stack_driver_get ( stack_name ) ;
2008-02-02 02:03:57 +03:00
if ( rc )
goto out_free ;
2008-02-02 01:39:35 +03:00
2008-02-02 02:03:57 +03:00
rc = active_stack - > sp_ops - > connect ( new_conn ) ;
2008-02-02 01:51:03 +03:00
if ( rc ) {
2008-02-02 02:03:57 +03:00
ocfs2_stack_driver_put ( ) ;
2008-02-02 01:39:35 +03:00
goto out_free ;
}
* conn = new_conn ;
out_free :
2008-02-02 01:51:03 +03:00
if ( rc )
2008-02-02 01:39:35 +03:00
kfree ( new_conn ) ;
out :
return rc ;
}
2008-02-02 02:03:57 +03:00
EXPORT_SYMBOL_GPL ( ocfs2_cluster_connect ) ;
2008-02-02 01:39:35 +03:00
2010-01-30 17:02:10 +03:00
/* The caller will ensure all nodes have the same cluster stack */
int ocfs2_cluster_connect_agnostic ( const char * group ,
int grouplen ,
struct ocfs2_locking_protocol * lproto ,
void ( * recovery_handler ) ( int node_num ,
void * recovery_data ) ,
void * recovery_data ,
struct ocfs2_cluster_connection * * conn )
{
char * stack_name = NULL ;
if ( cluster_stack_name [ 0 ] )
stack_name = cluster_stack_name ;
2014-01-22 03:48:21 +04:00
return ocfs2_cluster_connect ( stack_name , NULL , 0 , group , grouplen ,
lproto , recovery_handler , recovery_data ,
conn ) ;
2010-01-30 17:02:10 +03:00
}
EXPORT_SYMBOL_GPL ( ocfs2_cluster_connect_agnostic ) ;
2008-02-02 02:03:57 +03:00
/* If hangup_pending is 0, the stack driver will be dropped */
int ocfs2_cluster_disconnect ( struct ocfs2_cluster_connection * conn ,
int hangup_pending )
2008-02-02 01:51:03 +03:00
{
int ret ;
BUG_ON ( conn = = NULL ) ;
2008-05-31 02:58:26 +04:00
ret = active_stack - > sp_ops - > disconnect ( conn ) ;
2008-02-02 01:51:03 +03:00
/* XXX Should we free it anyway? */
2008-02-02 02:03:57 +03:00
if ( ! ret ) {
2008-02-02 01:51:03 +03:00
kfree ( conn ) ;
2008-02-02 02:03:57 +03:00
if ( ! hangup_pending )
ocfs2_stack_driver_put ( ) ;
}
2008-02-02 01:51:03 +03:00
return ret ;
}
2008-02-02 02:03:57 +03:00
EXPORT_SYMBOL_GPL ( ocfs2_cluster_disconnect ) ;
2008-02-02 01:51:03 +03:00
2008-05-31 02:43:58 +04:00
/*
* Leave the group for this filesystem . This is executed by a userspace
* program ( stored in ocfs2_hb_ctl_path ) .
*/
static void ocfs2_leave_group ( const char * group )
{
int ret ;
char * argv [ 5 ] , * envp [ 3 ] ;
argv [ 0 ] = ocfs2_hb_ctl_path ;
argv [ 1 ] = " -K " ;
argv [ 2 ] = " -u " ;
argv [ 3 ] = ( char * ) group ;
argv [ 4 ] = NULL ;
/* minimal command environment taken from cpu_run_sbin_hotplug */
envp [ 0 ] = " HOME=/ " ;
envp [ 1 ] = " PATH=/sbin:/bin:/usr/sbin:/usr/bin " ;
envp [ 2 ] = NULL ;
ret = call_usermodehelper ( argv [ 0 ] , argv , envp , UMH_WAIT_PROC ) ;
if ( ret < 0 ) {
printk ( KERN_ERR
" ocfs2: Error %d running user helper "
" \" %s %s %s %s \" \n " ,
ret , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] ) ;
}
}
/*
* Hangup is a required post - umount . ocfs2 - tools software expects the
* filesystem to call " ocfs2_hb_ctl " during unmount . This happens
* regardless of whether the DLM got started , so we can ' t do it
* in ocfs2_cluster_disconnect ( ) . The ocfs2_leave_group ( ) function does
* the actual work .
*/
2008-01-30 03:59:56 +03:00
void ocfs2_cluster_hangup ( const char * group , int grouplen )
{
BUG_ON ( group = = NULL ) ;
BUG_ON ( group [ grouplen ] ! = ' \0 ' ) ;
2008-05-31 02:43:58 +04:00
ocfs2_leave_group ( group ) ;
2008-02-02 02:03:57 +03:00
/* cluster_disconnect() was called with hangup_pending==1 */
ocfs2_stack_driver_put ( ) ;
2008-01-31 02:38:24 +03:00
}
2008-02-02 02:03:57 +03:00
EXPORT_SYMBOL_GPL ( ocfs2_cluster_hangup ) ;
2008-01-31 02:38:24 +03:00
2014-01-22 03:48:24 +04:00
int ocfs2_cluster_this_node ( struct ocfs2_cluster_connection * conn ,
unsigned int * node )
2008-02-02 01:51:03 +03:00
{
2014-01-22 03:48:24 +04:00
return active_stack - > sp_ops - > this_node ( conn , node ) ;
2008-02-02 01:51:03 +03:00
}
2008-02-02 02:03:57 +03:00
EXPORT_SYMBOL_GPL ( ocfs2_cluster_this_node ) ;
2008-02-02 01:51:03 +03:00
2008-02-02 02:03:57 +03:00
2008-02-01 10:56:17 +03:00
/*
* Sysfs bits
*/
static ssize_t ocfs2_max_locking_protocol_show ( struct kobject * kobj ,
struct kobj_attribute * attr ,
char * buf )
{
ssize_t ret = 0 ;
spin_lock ( & ocfs2_stack_lock ) ;
2010-01-30 04:19:06 +03:00
if ( locking_max_version . pv_major )
2008-02-01 10:56:17 +03:00
ret = snprintf ( buf , PAGE_SIZE , " %u.%u \n " ,
2010-01-30 04:19:06 +03:00
locking_max_version . pv_major ,
locking_max_version . pv_minor ) ;
2008-02-01 10:56:17 +03:00
spin_unlock ( & ocfs2_stack_lock ) ;
return ret ;
}
static struct kobj_attribute ocfs2_attr_max_locking_protocol =
__ATTR ( max_locking_protocol , S_IFREG | S_IRUGO ,
ocfs2_max_locking_protocol_show , NULL ) ;
static ssize_t ocfs2_loaded_cluster_plugins_show ( struct kobject * kobj ,
struct kobj_attribute * attr ,
char * buf )
2008-01-30 04:37:32 +03:00
{
2008-02-01 10:56:17 +03:00
ssize_t ret = 0 , total = 0 , remain = PAGE_SIZE ;
struct ocfs2_stack_plugin * p ;
spin_lock ( & ocfs2_stack_lock ) ;
list_for_each_entry ( p , & ocfs2_stack_list , sp_list ) {
ret = snprintf ( buf , remain , " %s \n " ,
p - > sp_name ) ;
if ( ret < 0 ) {
total = ret ;
break ;
}
if ( ret = = remain ) {
/* snprintf() didn't fit */
total = - E2BIG ;
break ;
}
total + = ret ;
remain - = ret ;
}
spin_unlock ( & ocfs2_stack_lock ) ;
return total ;
}
static struct kobj_attribute ocfs2_attr_loaded_cluster_plugins =
__ATTR ( loaded_cluster_plugins , S_IFREG | S_IRUGO ,
ocfs2_loaded_cluster_plugins_show , NULL ) ;
static ssize_t ocfs2_active_cluster_plugin_show ( struct kobject * kobj ,
struct kobj_attribute * attr ,
char * buf )
{
ssize_t ret = 0 ;
spin_lock ( & ocfs2_stack_lock ) ;
if ( active_stack ) {
ret = snprintf ( buf , PAGE_SIZE , " %s \n " ,
active_stack - > sp_name ) ;
if ( ret = = PAGE_SIZE )
ret = - E2BIG ;
}
spin_unlock ( & ocfs2_stack_lock ) ;
return ret ;
}
static struct kobj_attribute ocfs2_attr_active_cluster_plugin =
__ATTR ( active_cluster_plugin , S_IFREG | S_IRUGO ,
ocfs2_active_cluster_plugin_show , NULL ) ;
2008-02-02 02:17:30 +03:00
static ssize_t ocfs2_cluster_stack_show ( struct kobject * kobj ,
struct kobj_attribute * attr ,
char * buf )
{
ssize_t ret ;
spin_lock ( & ocfs2_stack_lock ) ;
ret = snprintf ( buf , PAGE_SIZE , " %s \n " , cluster_stack_name ) ;
spin_unlock ( & ocfs2_stack_lock ) ;
return ret ;
}
static ssize_t ocfs2_cluster_stack_store ( struct kobject * kobj ,
struct kobj_attribute * attr ,
const char * buf , size_t count )
{
size_t len = count ;
ssize_t ret ;
if ( len = = 0 )
return len ;
if ( buf [ len - 1 ] = = ' \n ' )
len - - ;
if ( ( len ! = OCFS2_STACK_LABEL_LEN ) | |
( strnlen ( buf , len ) ! = len ) )
return - EINVAL ;
spin_lock ( & ocfs2_stack_lock ) ;
if ( active_stack ) {
if ( ! strncmp ( buf , cluster_stack_name , len ) )
ret = count ;
else
ret = - EBUSY ;
} else {
memcpy ( cluster_stack_name , buf , len ) ;
ret = count ;
}
spin_unlock ( & ocfs2_stack_lock ) ;
return ret ;
}
static struct kobj_attribute ocfs2_attr_cluster_stack =
__ATTR ( cluster_stack , S_IFREG | S_IRUGO | S_IWUSR ,
ocfs2_cluster_stack_show ,
ocfs2_cluster_stack_store ) ;
2008-02-01 10:56:17 +03:00
static struct attribute * ocfs2_attrs [ ] = {
& ocfs2_attr_max_locking_protocol . attr ,
& ocfs2_attr_loaded_cluster_plugins . attr ,
& ocfs2_attr_active_cluster_plugin . attr ,
2008-02-02 02:17:30 +03:00
& ocfs2_attr_cluster_stack . attr ,
2008-02-01 10:56:17 +03:00
NULL ,
} ;
static struct attribute_group ocfs2_attr_group = {
. attrs = ocfs2_attrs ,
} ;
static struct kset * ocfs2_kset ;
static void ocfs2_sysfs_exit ( void )
{
kset_unregister ( ocfs2_kset ) ;
}
static int ocfs2_sysfs_init ( void )
{
int ret ;
ocfs2_kset = kset_create_and_add ( " ocfs2 " , NULL , fs_kobj ) ;
if ( ! ocfs2_kset )
return - ENOMEM ;
ret = sysfs_create_group ( & ocfs2_kset - > kobj , & ocfs2_attr_group ) ;
if ( ret )
goto error ;
2008-02-02 02:03:57 +03:00
return 0 ;
2008-02-01 10:56:17 +03:00
error :
kset_unregister ( ocfs2_kset ) ;
return ret ;
}
2008-05-31 02:30:49 +04:00
/*
* Sysctl bits
*
* The sysctl lives at / proc / sys / fs / ocfs2 / nm / hb_ctl_path . The ' nm ' doesn ' t
* make as much sense in a multiple cluster stack world , but it ' s safer
* and easier to preserve the name .
*/
# define FS_OCFS2_NM 1
2013-11-13 03:07:07 +04:00
static struct ctl_table ocfs2_nm_table [ ] = {
2008-05-31 02:30:49 +04:00
{
. procname = " hb_ctl_path " ,
. data = ocfs2_hb_ctl_path ,
. maxlen = OCFS2_MAX_HB_CTL_PATH ,
. mode = 0644 ,
2009-11-16 14:11:48 +03:00
. proc_handler = proc_dostring ,
2008-05-31 02:30:49 +04:00
} ,
2009-11-06 01:25:10 +03:00
{ }
2008-05-31 02:30:49 +04:00
} ;
2013-11-13 03:07:07 +04:00
static struct ctl_table ocfs2_mod_table [ ] = {
2008-05-31 02:30:49 +04:00
{
. procname = " nm " ,
. data = NULL ,
. maxlen = 0 ,
. mode = 0555 ,
. child = ocfs2_nm_table
} ,
2009-11-06 01:25:10 +03:00
{ }
2008-05-31 02:30:49 +04:00
} ;
2013-11-13 03:07:07 +04:00
static struct ctl_table ocfs2_kern_table [ ] = {
2008-05-31 02:30:49 +04:00
{
. procname = " ocfs2 " ,
. data = NULL ,
. maxlen = 0 ,
. mode = 0555 ,
. child = ocfs2_mod_table
} ,
2009-11-06 01:25:10 +03:00
{ }
2008-05-31 02:30:49 +04:00
} ;
2013-11-13 03:07:07 +04:00
static struct ctl_table ocfs2_root_table [ ] = {
2008-05-31 02:30:49 +04:00
{
. procname = " fs " ,
. data = NULL ,
. maxlen = 0 ,
. mode = 0555 ,
. child = ocfs2_kern_table
} ,
2009-11-06 01:25:10 +03:00
{ }
2008-05-31 02:30:49 +04:00
} ;
static struct ctl_table_header * ocfs2_table_header = NULL ;
/*
* Initialization
*/
2008-02-01 10:56:17 +03:00
static int __init ocfs2_stack_glue_init ( void )
{
2008-02-02 02:17:30 +03:00
strcpy ( cluster_stack_name , OCFS2_STACK_PLUGIN_O2CB ) ;
2008-05-31 02:30:49 +04:00
ocfs2_table_header = register_sysctl_table ( ocfs2_root_table ) ;
if ( ! ocfs2_table_header ) {
printk ( KERN_ERR
" ocfs2 stack glue: unable to register sysctl \n " ) ;
return - ENOMEM ; /* or something. */
}
2008-02-01 10:56:17 +03:00
return ocfs2_sysfs_init ( ) ;
2008-02-02 02:03:57 +03:00
}
2008-01-30 04:37:32 +03:00
2008-02-02 02:03:57 +03:00
static void __exit ocfs2_stack_glue_exit ( void )
{
2010-01-30 04:19:06 +03:00
memset ( & locking_max_version , 0 ,
sizeof ( struct ocfs2_protocol_version ) ) ;
locking_max_version . pv_major = 0 ;
locking_max_version . pv_minor = 0 ;
2008-02-01 10:56:17 +03:00
ocfs2_sysfs_exit ( ) ;
2008-05-31 02:30:49 +04:00
if ( ocfs2_table_header )
unregister_sysctl_table ( ocfs2_table_header ) ;
2008-01-30 04:37:32 +03:00
}
2008-02-02 02:03:57 +03:00
MODULE_AUTHOR ( " Oracle " ) ;
MODULE_DESCRIPTION ( " ocfs2 cluter stack glue layer " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( ocfs2_stack_glue_init ) ;
module_exit ( ocfs2_stack_glue_exit ) ;