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 .
*
* Copyright ( C ) 2007 Oracle . All rights reserved .
*
* 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-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-02-02 02:03:57 +03:00
static struct ocfs2_locking_protocol * lproto ;
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-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 ;
}
/* Ok, the stack is pinned */
p - > sp_count + + ;
active_stack = p ;
rc = 0 ;
out :
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 ;
plugin - > sp_proto = lproto ;
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 ) ;
void ocfs2_stack_glue_set_locking_protocol ( struct ocfs2_locking_protocol * proto )
{
struct ocfs2_stack_plugin * p ;
BUG_ON ( proto = = NULL ) ;
spin_lock ( & ocfs2_stack_lock ) ;
BUG_ON ( active_stack ! = NULL ) ;
lproto = proto ;
list_for_each_entry ( p , & ocfs2_stack_list , sp_list ) {
p - > sp_proto = lproto ;
}
spin_unlock ( & ocfs2_stack_lock ) ;
}
EXPORT_SYMBOL_GPL ( ocfs2_stack_glue_set_locking_protocol ) ;
2008-02-01 23:15:37 +03:00
2008-01-30 04:37:32 +03:00
2008-02-02 01:51:03 +03:00
int ocfs2_dlm_lock ( struct ocfs2_cluster_connection * conn ,
int mode ,
union ocfs2_dlm_lksb * lksb ,
u32 flags ,
void * name ,
unsigned int namelen ,
void * astarg )
{
2008-02-02 02:03:57 +03:00
BUG_ON ( lproto = = NULL ) ;
2008-02-01 23:14:57 +03:00
2008-02-02 02:03:57 +03:00
return active_stack - > sp_ops - > dlm_lock ( conn , mode , lksb , flags ,
name , namelen , astarg ) ;
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 ,
union ocfs2_dlm_lksb * lksb ,
u32 flags ,
void * astarg )
{
2008-02-02 02:03:57 +03:00
BUG_ON ( lproto = = NULL ) ;
2008-02-02 01:51:03 +03:00
2008-02-02 02:03:57 +03:00
return active_stack - > sp_ops - > dlm_unlock ( conn , lksb , flags , astarg ) ;
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
2008-02-02 01:51:03 +03:00
int ocfs2_dlm_lock_status ( union ocfs2_dlm_lksb * lksb )
{
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
2008-02-01 23:16:57 +03:00
/*
* Why don ' t we cast to ocfs2_meta_lvb ? The " clean " answer is that we
* don ' t cast at the glue level . The real answer is that the header
* ordering is nigh impossible .
*/
2008-02-02 01:51:03 +03:00
void * ocfs2_dlm_lvb ( union ocfs2_dlm_lksb * lksb )
{
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
2008-02-02 01:51:03 +03:00
void ocfs2_dlm_dump_lksb ( union ocfs2_dlm_lksb * lksb )
{
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-02-02 02:17:30 +03:00
int ocfs2_cluster_connect ( const char * stack_name ,
const char * group ,
2008-02-02 01:39:35 +03:00
int grouplen ,
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 ;
}
new_conn = kzalloc ( sizeof ( struct ocfs2_cluster_connection ) ,
GFP_KERNEL ) ;
if ( ! new_conn ) {
rc = - ENOMEM ;
goto out ;
}
memcpy ( new_conn - > cc_name , group , grouplen ) ;
new_conn - > cc_namelen = grouplen ;
new_conn - > cc_recovery_handler = recovery_handler ;
new_conn - > cc_recovery_data = recovery_data ;
/* 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
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-02-02 02:03:57 +03:00
ret = active_stack - > sp_ops - > disconnect ( conn , hangup_pending ) ;
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-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-02-02 02:03:57 +03:00
active_stack - > sp_ops - > hangup ( group , grouplen ) ;
/* 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
2008-02-02 01:51:03 +03:00
int ocfs2_cluster_this_node ( unsigned int * node )
{
2008-02-02 02:03:57 +03:00
return active_stack - > sp_ops - > this_node ( 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 ) ;
if ( lproto )
ret = snprintf ( buf , PAGE_SIZE , " %u.%u \n " ,
lproto - > lp_max_version . pv_major ,
lproto - > lp_max_version . pv_minor ) ;
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 ;
}
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-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 )
{
lproto = NULL ;
2008-02-01 10:56:17 +03:00
ocfs2_sysfs_exit ( ) ;
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 ) ;