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/module.h>
# include <linux/init.h>
# include <linux/string.h>
# include <linux/slab.h>
# include <linux/wait.h>
# include <linux/sched.h>
# include <linux/kmod.h>
# include <linux/fs.h>
# include <linux/delay.h>
2006-09-19 09:56:29 +04:00
# include <linux/lm_interface.h>
2006-01-16 19:50:04 +03:00
struct lmh_wrapper {
struct list_head lw_list ;
2006-09-08 18:17:58 +04:00
const struct lm_lockops * lw_ops ;
2006-01-16 19:50:04 +03:00
} ;
2009-01-07 19:21:34 +03:00
struct nolock_lockspace {
unsigned int nl_lvb_size ;
} ;
/**
* nolock_get_lock - get a lm_lock_t given a descripton of the lock
* @ lockspace : the lockspace the lock lives in
* @ name : the name of the lock
* @ lockp : return the lm_lock_t here
*
* Returns : 0 on success , - EXXX on failure
*/
static int nolock_get_lock ( void * lockspace , struct lm_lockname * name ,
void * * lockp )
{
* lockp = lockspace ;
return 0 ;
}
/**
* nolock_put_lock - get rid of a lock structure
* @ lock : the lock to throw away
*
*/
static void nolock_put_lock ( void * lock )
{
}
/**
* nolock_hold_lvb - hold on to a lock value block
* @ lock : the lock the LVB is associated with
* @ lvbp : return the lm_lvb_t here
*
* Returns : 0 on success , - EXXX on failure
*/
static int nolock_hold_lvb ( void * lock , char * * lvbp )
{
struct nolock_lockspace * nl = lock ;
int error = 0 ;
* lvbp = kzalloc ( nl - > nl_lvb_size , GFP_KERNEL ) ;
if ( ! * lvbp )
error = - ENOMEM ;
return error ;
}
/**
* nolock_unhold_lvb - release a LVB
* @ lock : the lock the LVB is associated with
* @ lvb : the lock value block
*
*/
static void nolock_unhold_lvb ( void * lock , char * lvb )
{
kfree ( lvb ) ;
}
2008-05-23 17:46:04 +04:00
static int nolock_mount ( char * table_name , char * host_data ,
lm_callback_t cb , void * cb_data ,
unsigned int min_lvb_size , int flags ,
struct lm_lockstruct * lockstruct ,
struct kobject * fskobj ) ;
2009-01-07 19:21:34 +03:00
static void nolock_unmount ( void * lockspace ) ;
2008-05-23 17:46:04 +04:00
2006-01-16 19:50:04 +03:00
/* List of registered low-level locking protocols. A file system selects one
of them by name at mount time , e . g . lock_nolock , lock_dlm . */
2008-05-23 17:46:04 +04:00
static const struct lm_lockops nolock_ops = {
. lm_proto_name = " lock_nolock " ,
. lm_mount = nolock_mount ,
2009-01-07 19:21:34 +03:00
. lm_unmount = nolock_unmount ,
. lm_get_lock = nolock_get_lock ,
. lm_put_lock = nolock_put_lock ,
. lm_hold_lvb = nolock_hold_lvb ,
. lm_unhold_lvb = nolock_unhold_lvb ,
2008-05-23 17:46:04 +04:00
} ;
static struct lmh_wrapper nolock_proto = {
. lw_list = LIST_HEAD_INIT ( nolock_proto . lw_list ) ,
. lw_ops = & nolock_ops ,
} ;
2006-09-04 17:49:55 +04:00
static LIST_HEAD ( lmh_list ) ;
static DEFINE_MUTEX ( lmh_lock ) ;
2006-01-16 19:50:04 +03:00
2008-05-23 17:46:04 +04:00
static int nolock_mount ( char * table_name , char * host_data ,
lm_callback_t cb , void * cb_data ,
unsigned int min_lvb_size , int flags ,
struct lm_lockstruct * lockstruct ,
struct kobject * fskobj )
{
char * c ;
unsigned int jid ;
2009-01-07 19:21:34 +03:00
struct nolock_lockspace * nl ;
2008-05-23 17:46:04 +04:00
c = strstr ( host_data , " jid= " ) ;
if ( ! c )
jid = 0 ;
else {
c + = 4 ;
sscanf ( c , " %u " , & jid ) ;
}
2009-01-07 19:21:34 +03:00
nl = kzalloc ( sizeof ( struct nolock_lockspace ) , GFP_KERNEL ) ;
if ( ! nl )
return - ENOMEM ;
nl - > nl_lvb_size = min_lvb_size ;
2008-05-23 17:46:04 +04:00
lockstruct - > ls_jid = jid ;
lockstruct - > ls_first = 1 ;
lockstruct - > ls_lvb_size = min_lvb_size ;
2009-01-07 19:21:34 +03:00
lockstruct - > ls_lockspace = nl ;
2008-05-23 17:46:04 +04:00
lockstruct - > ls_ops = & nolock_ops ;
lockstruct - > ls_flags = LM_LSFLAG_LOCAL ;
return 0 ;
}
2009-01-07 19:21:34 +03:00
static void nolock_unmount ( void * lockspace )
{
struct nolock_lockspace * nl = lockspace ;
kfree ( nl ) ;
}
2006-01-16 19:50:04 +03:00
/**
2006-08-07 19:12:30 +04:00
* gfs2_register_lockproto - Register a low - level locking protocol
2006-01-16 19:50:04 +03:00
* @ proto : the protocol definition
*
* Returns : 0 on success , - EXXX on failure
*/
2006-09-08 18:17:58 +04:00
int gfs2_register_lockproto ( const struct lm_lockops * proto )
2006-01-16 19:50:04 +03:00
{
struct lmh_wrapper * lw ;
2006-04-21 23:10:46 +04:00
mutex_lock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
list_for_each_entry ( lw , & lmh_list , lw_list ) {
if ( ! strcmp ( lw - > lw_ops - > lm_proto_name , proto - > lm_proto_name ) ) {
2006-04-21 23:10:46 +04:00
mutex_unlock ( & lmh_lock ) ;
2006-02-27 18:57:14 +03:00
printk ( KERN_INFO " GFS2: protocol %s already exists \n " ,
2006-01-16 19:50:04 +03:00
proto - > lm_proto_name ) ;
return - EEXIST ;
}
}
2006-02-27 18:57:14 +03:00
lw = kzalloc ( sizeof ( struct lmh_wrapper ) , GFP_KERNEL ) ;
2006-01-16 19:50:04 +03:00
if ( ! lw ) {
2006-04-21 23:10:46 +04:00
mutex_unlock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
return - ENOMEM ;
}
lw - > lw_ops = proto ;
list_add ( & lw - > lw_list , & lmh_list ) ;
2006-04-21 23:10:46 +04:00
mutex_unlock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
return 0 ;
}
/**
2006-08-07 19:12:30 +04:00
* gfs2_unregister_lockproto - Unregister a low - level locking protocol
2006-01-16 19:50:04 +03:00
* @ proto : the protocol definition
*
*/
2006-09-08 18:17:58 +04:00
void gfs2_unregister_lockproto ( const struct lm_lockops * proto )
2006-01-16 19:50:04 +03:00
{
struct lmh_wrapper * lw ;
2006-04-21 23:10:46 +04:00
mutex_lock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
list_for_each_entry ( lw , & lmh_list , lw_list ) {
if ( ! strcmp ( lw - > lw_ops - > lm_proto_name , proto - > lm_proto_name ) ) {
list_del ( & lw - > lw_list ) ;
2006-04-21 23:10:46 +04:00
mutex_unlock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
kfree ( lw ) ;
return ;
}
}
2006-04-21 23:10:46 +04:00
mutex_unlock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
2006-02-27 18:57:14 +03:00
printk ( KERN_WARNING " GFS2: can't unregister lock protocol %s \n " ,
2006-01-16 19:50:04 +03:00
proto - > lm_proto_name ) ;
}
/**
* gfs2_mount_lockproto - Mount a lock protocol
* @ proto_name - the name of the protocol
* @ table_name - the name of the lock space
* @ host_data - data specific to this host
* @ cb - the callback to the code using the lock module
2006-09-07 23:50:20 +04:00
* @ sdp - The GFS2 superblock
2006-01-16 19:50:04 +03:00
* @ min_lvb_size - the mininum LVB size that the caller can deal with
* @ flags - LM_MFLAG_ *
* @ lockstruct - a structure returned describing the mount
*
* Returns : 0 on success , - EXXX on failure
*/
int gfs2_mount_lockproto ( char * proto_name , char * table_name , char * host_data ,
2006-09-08 18:17:58 +04:00
lm_callback_t cb , void * cb_data ,
2006-01-16 19:50:04 +03:00
unsigned int min_lvb_size , int flags ,
struct lm_lockstruct * lockstruct ,
struct kobject * fskobj )
{
struct lmh_wrapper * lw = NULL ;
int try = 0 ;
int error , found ;
2008-05-23 17:46:04 +04:00
2006-08-07 19:12:30 +04:00
retry :
2006-04-21 23:10:46 +04:00
mutex_lock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
2008-05-23 17:46:04 +04:00
if ( list_empty ( & nolock_proto . lw_list ) )
2008-06-02 12:08:47 +04:00
list_add ( & nolock_proto . lw_list , & lmh_list ) ;
2008-05-23 17:46:04 +04:00
2006-01-16 19:50:04 +03:00
found = 0 ;
list_for_each_entry ( lw , & lmh_list , lw_list ) {
if ( ! strcmp ( lw - > lw_ops - > lm_proto_name , proto_name ) ) {
found = 1 ;
break ;
}
}
if ( ! found ) {
if ( ! try & & capable ( CAP_SYS_MODULE ) ) {
try = 1 ;
2006-04-21 23:10:46 +04:00
mutex_unlock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
request_module ( proto_name ) ;
goto retry ;
}
2006-02-27 18:57:14 +03:00
printk ( KERN_INFO " GFS2: can't find protocol %s \n " , proto_name ) ;
2006-01-16 19:50:04 +03:00
error = - ENOENT ;
goto out ;
}
2008-05-23 17:46:04 +04:00
if ( lw - > lw_ops - > lm_owner & &
! try_module_get ( lw - > lw_ops - > lm_owner ) ) {
2006-01-16 19:50:04 +03:00
try = 0 ;
2006-04-21 23:10:46 +04:00
mutex_unlock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
msleep ( 1000 ) ;
goto retry ;
}
2006-09-08 18:17:58 +04:00
error = lw - > lw_ops - > lm_mount ( table_name , host_data , cb , cb_data ,
2006-01-16 19:50:04 +03:00
min_lvb_size , flags , lockstruct , fskobj ) ;
if ( error )
module_put ( lw - > lw_ops - > lm_owner ) ;
2006-08-07 19:12:30 +04:00
out :
2006-04-21 23:10:46 +04:00
mutex_unlock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
return error ;
}
void gfs2_unmount_lockproto ( struct lm_lockstruct * lockstruct )
{
2006-04-21 23:10:46 +04:00
mutex_lock ( & lmh_lock ) ;
2008-05-23 17:46:04 +04:00
if ( lockstruct - > ls_ops - > lm_unmount )
lockstruct - > ls_ops - > lm_unmount ( lockstruct - > ls_lockspace ) ;
2006-01-16 19:50:04 +03:00
if ( lockstruct - > ls_ops - > lm_owner )
module_put ( lockstruct - > ls_ops - > lm_owner ) ;
2006-04-21 23:10:46 +04:00
mutex_unlock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
}
/**
* gfs2_withdraw_lockproto - abnormally unmount a lock module
* @ lockstruct : the lockstruct passed into mount
*
*/
void gfs2_withdraw_lockproto ( struct lm_lockstruct * lockstruct )
{
2006-04-21 23:10:46 +04:00
mutex_lock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
lockstruct - > ls_ops - > lm_withdraw ( lockstruct - > ls_lockspace ) ;
if ( lockstruct - > ls_ops - > lm_owner )
module_put ( lockstruct - > ls_ops - > lm_owner ) ;
2006-04-21 23:10:46 +04:00
mutex_unlock ( & lmh_lock ) ;
2006-01-16 19:50:04 +03:00
}
2006-08-07 19:12:30 +04:00
EXPORT_SYMBOL_GPL ( gfs2_register_lockproto ) ;
EXPORT_SYMBOL_GPL ( gfs2_unregister_lockproto ) ;
2006-01-16 19:50:04 +03:00