2002-02-11 18:42:34 +03:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 Red Hat , Inc . All rights reserved .
2002-02-11 18:42:34 +03:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
2002-02-11 18:42:34 +03:00
*
2004-03-30 23:35:44 +04: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 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2002-02-11 18:42:34 +03:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2002-02-11 18:42:34 +03:00
# include "locking.h"
# include "locking_types.h"
# include "lvm-string.h"
# include "activate.h"
2002-11-01 22:57:25 +03:00
# include "toolcontext.h"
2004-03-26 23:49:35 +03:00
# include "memlock.h"
2002-02-11 18:42:34 +03:00
# include <signal.h>
2002-11-01 22:57:25 +03:00
# include <sys/stat.h>
# include <limits.h>
2003-07-05 02:34:56 +04:00
# include <unistd.h>
2002-02-11 18:42:34 +03:00
static struct locking_type _locking ;
2002-03-15 19:07:38 +03:00
static sigset_t _oldset ;
2002-02-11 18:42:34 +03:00
2003-11-21 22:54:40 +03:00
static int _vg_lock_count = 0 ; /* Number of locks held */
static int _vg_write_lock_held = 0 ; /* VG write lock held? */
2002-03-15 19:07:38 +03:00
static int _signals_blocked = 0 ;
2002-02-11 18:42:34 +03:00
2003-01-04 00:10:28 +03:00
static void _block_signals ( int flags )
2002-02-11 18:42:34 +03:00
{
2002-03-15 19:07:38 +03:00
sigset_t set ;
2002-02-11 18:42:34 +03:00
2002-03-15 19:07:38 +03:00
if ( _signals_blocked )
2002-02-11 18:42:34 +03:00
return ;
2002-03-15 19:07:38 +03:00
if ( sigfillset ( & set ) ) {
log_sys_error ( " sigfillset " , " _block_signals " ) ;
return ;
}
if ( sigprocmask ( SIG_SETMASK , & set , & _oldset ) ) {
log_sys_error ( " sigprocmask " , " _block_signals " ) ;
return ;
}
2002-02-11 18:42:34 +03:00
2002-03-15 19:07:38 +03:00
_signals_blocked = 1 ;
2002-02-11 18:42:34 +03:00
return ;
}
2002-03-15 19:07:38 +03:00
static void _unblock_signals ( void )
2002-02-11 18:42:34 +03:00
{
2002-03-15 19:07:38 +03:00
/* Don't unblock signals while any locks are held */
2003-11-21 22:54:40 +03:00
if ( ! _signals_blocked | | _vg_lock_count )
2002-02-11 18:42:34 +03:00
return ;
2002-03-15 19:07:38 +03:00
if ( sigprocmask ( SIG_SETMASK , & _oldset , NULL ) ) {
log_sys_error ( " sigprocmask " , " _block_signals " ) ;
return ;
}
2002-02-11 18:42:34 +03:00
2002-03-15 19:07:38 +03:00
_signals_blocked = 0 ;
2002-02-11 18:42:34 +03:00
return ;
}
2004-03-26 23:49:35 +03:00
static void _lock_memory ( int flags )
{
if ( ! ( _locking . flags & LCK_PRE_MEMLOCK ) )
return ;
if ( ( flags & ( LCK_SCOPE_MASK | LCK_TYPE_MASK ) ) = = LCK_LV_SUSPEND )
memlock_inc ( ) ;
}
static void _unlock_memory ( int flags )
{
if ( ! ( _locking . flags & LCK_PRE_MEMLOCK ) )
return ;
if ( ( flags & ( LCK_SCOPE_MASK | LCK_TYPE_MASK ) ) = = LCK_LV_RESUME )
memlock_dec ( ) ;
}
2003-05-06 16:03:13 +04:00
void reset_locking ( void )
{
2003-11-21 22:54:40 +03:00
int was_locked = _vg_lock_count ;
2003-05-06 16:03:13 +04:00
2003-11-21 22:54:40 +03:00
_vg_lock_count = 0 ;
_vg_write_lock_held = 0 ;
2003-05-06 16:03:13 +04:00
_locking . reset_locking ( ) ;
if ( was_locked )
_unblock_signals ( ) ;
}
2003-11-21 22:54:40 +03:00
static inline void _update_vg_lock_count ( int flags )
2002-02-11 18:42:34 +03:00
{
2003-11-21 22:54:40 +03:00
if ( ( flags & LCK_SCOPE_MASK ) ! = LCK_VG )
return ;
2002-04-04 15:18:45 +04:00
if ( ( flags & LCK_TYPE_MASK ) = = LCK_UNLOCK )
2003-11-21 22:54:40 +03:00
_vg_lock_count - - ;
2002-02-11 18:42:34 +03:00
else
2003-11-21 22:54:40 +03:00
_vg_lock_count + + ;
/* We don't bother to reset this until all VG locks are dropped */
if ( ( flags & LCK_TYPE_MASK ) = = LCK_WRITE )
_vg_write_lock_held = 1 ;
else if ( ! _vg_lock_count )
_vg_write_lock_held = 0 ;
2002-02-11 18:42:34 +03:00
}
/*
* Select a locking type
*/
2004-03-08 21:28:45 +03:00
int init_locking ( int type , struct config_tree * cft )
2002-02-11 18:42:34 +03:00
{
2005-03-22 01:55:12 +03:00
init_lockingfailed ( 0 ) ;
2002-02-11 18:42:34 +03:00
switch ( type ) {
case 0 :
2004-03-08 21:28:45 +03:00
init_no_locking ( & _locking , cft ) ;
2002-03-25 21:50:37 +03:00
log_print ( " WARNING: Locking disabled. Be careful! "
2002-02-11 18:42:34 +03:00
" This could corrupt your metadata. " ) ;
2002-07-11 00:43:32 +04:00
return 1 ;
2002-02-11 18:42:34 +03:00
case 1 :
2004-03-08 21:28:45 +03:00
if ( ! init_file_locking ( & _locking , cft ) )
2002-07-11 00:43:32 +04:00
break ;
2002-02-11 18:42:34 +03:00
log_very_verbose ( " File-based locking enabled. " ) ;
2002-07-11 00:43:32 +04:00
return 1 ;
2002-04-08 20:04:50 +04:00
2003-03-24 21:08:53 +03:00
# ifdef HAVE_LIBDL
2002-02-11 18:42:34 +03:00
case 2 :
2004-03-08 21:28:45 +03:00
if ( ! init_external_locking ( & _locking , cft ) )
2002-07-11 00:43:32 +04:00
break ;
2002-04-08 20:04:50 +04:00
log_very_verbose ( " External locking enabled. " ) ;
2002-07-11 00:43:32 +04:00
return 1 ;
2003-03-24 21:08:53 +03:00
# endif
2002-04-08 20:04:50 +04:00
2004-06-24 12:02:38 +04:00
# ifdef CLUSTER_LOCKING_INTERNAL
case 3 :
if ( ! init_cluster_locking ( & _locking , cft ) )
break ;
log_very_verbose ( " Cluster locking enabled. " ) ;
return 1 ;
# endif
2002-02-11 18:42:34 +03:00
default :
log_error ( " Unknown locking type requested. " ) ;
return 0 ;
}
2002-07-11 00:43:32 +04:00
if ( ! ignorelockingfailure ( ) )
return 0 ;
2002-11-01 22:57:25 +03:00
/* FIXME Ensure only read ops are permitted */
2002-07-11 00:43:32 +04:00
log_verbose ( " Locking disabled - only read operations permitted. " ) ;
2004-03-08 21:28:45 +03:00
init_no_locking ( & _locking , cft ) ;
2005-03-22 01:55:12 +03:00
init_lockingfailed ( 1 ) ;
2002-07-11 00:43:32 +04:00
2002-02-11 18:42:34 +03:00
return 1 ;
}
void fin_locking ( void )
{
_locking . fin_locking ( ) ;
}
2002-11-01 22:57:25 +03:00
/*
* Does the LVM1 driver know of this VG name ?
*/
int check_lvm1_vg_inactive ( struct cmd_context * cmd , const char * vgname )
{
struct stat info ;
char path [ PATH_MAX ] ;
2002-11-18 17:01:16 +03:00
/* We'll allow operations on orphans */
if ( ! * vgname )
return 1 ;
if ( lvm_snprintf ( path , sizeof ( path ) , " %s/lvm/VGs/%s " , cmd - > proc_dir ,
vgname ) < 0 ) {
2002-11-01 22:57:25 +03:00
log_error ( " LVM1 proc VG pathname too long for %s " , vgname ) ;
return 0 ;
}
if ( stat ( path , & info ) = = 0 ) {
log_error ( " %s exists: Is the original LVM driver using "
" this volume group? " , path ) ;
return 0 ;
} else if ( errno ! = ENOENT & & errno ! = ENOTDIR ) {
log_sys_error ( " stat " , path ) ;
return 0 ;
}
return 1 ;
}
2002-02-11 18:42:34 +03:00
/*
2002-03-15 19:07:38 +03:00
* VG locking is by VG name .
* FIXME This should become VG uuid .
2002-02-11 18:42:34 +03:00
*/
2002-12-20 02:25:55 +03:00
static int _lock_vol ( struct cmd_context * cmd , const char * resource , int flags )
2002-03-05 23:03:09 +03:00
{
2003-01-04 00:10:28 +03:00
_block_signals ( flags ) ;
2004-03-26 23:49:35 +03:00
_lock_memory ( flags ) ;
2002-03-05 23:03:09 +03:00
if ( ! ( _locking . lock_resource ( cmd , resource , flags ) ) ) {
2004-03-26 23:49:35 +03:00
_unlock_memory ( flags ) ;
2002-03-15 19:07:38 +03:00
_unblock_signals ( ) ;
2002-03-05 23:03:09 +03:00
return 0 ;
}
2003-11-21 22:54:40 +03:00
_update_vg_lock_count ( flags ) ;
2004-03-26 23:49:35 +03:00
_unlock_memory ( flags ) ;
2002-03-15 19:07:38 +03:00
_unblock_signals ( ) ;
2002-03-05 23:03:09 +03:00
return 1 ;
}
2002-02-25 15:56:16 +03:00
int lock_vol ( struct cmd_context * cmd , const char * vol , int flags )
2002-02-11 18:42:34 +03:00
{
char resource [ 258 ] ;
switch ( flags & LCK_SCOPE_MASK ) {
2002-11-01 22:57:25 +03:00
case LCK_VG :
/* Lock VG to change on-disk metadata. */
/* If LVM1 driver knows about the VG, it can't be accessed. */
if ( ! check_lvm1_vg_inactive ( cmd , vol ) )
return 0 ;
case LCK_LV :
/* Suspend LV if it's active. */
2002-12-20 02:25:55 +03:00
strncpy ( resource , vol , sizeof ( resource ) ) ;
2002-02-11 18:42:34 +03:00
break ;
default :
log_error ( " Unrecognised lock scope: %d " ,
flags & LCK_SCOPE_MASK ) ;
return 0 ;
}
2002-03-05 23:03:09 +03:00
if ( ! _lock_vol ( cmd , resource , flags ) )
2002-02-11 18:42:34 +03:00
return 0 ;
2002-03-05 23:03:09 +03:00
/* Perform immediate unlock unless LCK_HOLD set */
2002-04-04 15:18:45 +04:00
if ( ! ( flags & LCK_HOLD ) & & ( ( flags & LCK_TYPE_MASK ) ! = LCK_UNLOCK ) ) {
2002-03-15 19:07:38 +03:00
if ( ! _lock_vol ( cmd , resource ,
2002-04-04 15:18:45 +04:00
( flags & ~ LCK_TYPE_MASK ) | LCK_UNLOCK ) )
2002-03-05 23:03:09 +03:00
return 0 ;
}
2002-02-11 18:42:34 +03:00
return 1 ;
}
2003-11-21 22:54:40 +03:00
2004-03-26 23:49:35 +03:00
/* Unlock list of LVs */
2004-05-05 16:03:07 +04:00
int resume_lvs ( struct cmd_context * cmd , struct list * lvs )
2004-03-26 23:49:35 +03:00
{
struct list * lvh ;
struct logical_volume * lv ;
list_iterate ( lvh , lvs ) {
lv = list_item ( lvh , struct lv_list ) - > lv ;
2004-05-05 16:03:07 +04:00
resume_lv ( cmd , lv - > lvid . s ) ;
2004-03-26 23:49:35 +03:00
}
return 1 ;
}
/* Lock a list of LVs */
2004-05-05 16:03:07 +04:00
int suspend_lvs ( struct cmd_context * cmd , struct list * lvs )
2004-03-26 23:49:35 +03:00
{
struct list * lvh ;
struct logical_volume * lv ;
list_iterate ( lvh , lvs ) {
lv = list_item ( lvh , struct lv_list ) - > lv ;
2004-05-05 16:03:07 +04:00
if ( ! suspend_lv ( cmd , lv - > lvid . s ) ) {
2004-03-26 23:49:35 +03:00
log_error ( " Failed to suspend %s " , lv - > name ) ;
list_uniterate ( lvh , lvs , lvh ) {
lv = list_item ( lvh , struct lv_list ) - > lv ;
2004-05-05 16:03:07 +04:00
resume_lv ( cmd , lv - > lvid . s ) ;
}
return 0 ;
}
}
return 1 ;
}
/* Lock a list of LVs */
int activate_lvs_excl ( struct cmd_context * cmd , struct list * lvs )
{
struct list * lvh ;
struct logical_volume * lv ;
list_iterate ( lvh , lvs ) {
lv = list_item ( lvh , struct lv_list ) - > lv ;
if ( ! activate_lv_excl ( cmd , lv - > lvid . s ) ) {
log_error ( " Failed to activate %s " , lv - > name ) ;
list_uniterate ( lvh , lvs , lvh ) {
lv = list_item ( lvh , struct lv_list ) - > lv ;
activate_lv ( cmd , lv - > lvid . s ) ;
2004-03-26 23:49:35 +03:00
}
return 0 ;
}
}
return 1 ;
}
2003-11-21 22:54:40 +03:00
int vg_write_lock_held ( void )
{
return _vg_write_lock_held ;
}
2005-03-22 01:55:12 +03:00
int locking_is_clustered ( void )
{
return ( _locking . flags & LCK_CLUSTERED ) ? 1 : 0 ;
}