2002-02-11 18:42:34 +03:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2011-02-18 17:16:11 +03:00
* Copyright ( C ) 2004 - 2011 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
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2002-02-11 18:42:34 +03:00
*/
2018-05-14 12:30:20 +03:00
# include "lib/misc/lib.h"
# include "lib/locking/locking.h"
2002-02-11 18:42:34 +03:00
# include "locking_types.h"
2018-05-14 12:30:20 +03:00
# include "lib/misc/lvm-string.h"
# include "lib/activate/activate.h"
# include "lib/commands/toolcontext.h"
# include "lib/mm/memlock.h"
# include "lib/config/defaults.h"
# include "lib/cache/lvmcache.h"
# include "lib/misc/lvm-signal.h"
2002-02-11 18:42:34 +03:00
2008-11-04 18:07:45 +03:00
# include <assert.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 ;
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? */
2009-07-25 03:28:55 +04:00
static int _blocking_supported = 0 ;
2018-06-07 00:31:59 +03:00
static int _file_locking_readonly = 0 ;
static int _file_locking_sysinit = 0 ;
2002-02-11 18:42:34 +03:00
2014-05-01 23:07:17 +04:00
static void _unblock_signals ( void )
{
/* Don't unblock signals while any locks are held */
if ( ! _vg_lock_count )
unblock_signals ( ) ;
}
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
2018-06-07 00:31:59 +03:00
/* file locking disabled */
if ( ! _locking . flags )
return ;
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
2010-01-13 20:40:17 +03:00
if ( _locking . reset_locking )
_locking . reset_locking ( ) ;
2003-05-06 16:03:13 +04:00
if ( was_locked )
_unblock_signals ( ) ;
2011-02-18 17:16:11 +03:00
memlock_reset ( ) ;
2003-05-06 16:03:13 +04:00
}
2009-07-14 15:01:26 +04:00
static void _update_vg_lock_count ( const char * resource , uint32_t flags )
2002-02-11 18:42:34 +03:00
{
2009-07-14 15:01:26 +04:00
/* Ignore locks not associated with updating VG metadata */
2009-02-22 19:13:57 +03:00
if ( ( flags & LCK_SCOPE_MASK ) ! = LCK_VG | |
2009-07-14 15:01:26 +04:00
( flags & LCK_CACHE ) | |
! strcmp ( resource , VG_GLOBAL ) )
2003-11-21 22:54:40 +03:00
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
2009-02-03 19:23:19 +03:00
* type : locking type ; if < 0 , then read config tree value
2002-02-11 18:42:34 +03:00
*/
2018-06-07 00:31:59 +03:00
int init_locking ( struct cmd_context * cmd , int file_locking_sysinit , int file_locking_readonly )
2002-02-11 18:42:34 +03:00
{
2018-06-07 00:31:59 +03:00
int suppress_messages = 0 ;
2011-08-11 19:27:46 +04:00
if ( getenv ( " LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES " ) )
2010-02-15 19:46:56 +03:00
suppress_messages = 1 ;
2018-06-07 00:31:59 +03:00
if ( file_locking_sysinit )
suppress_messages = 1 ;
2009-07-25 03:28:55 +04:00
2013-06-25 14:31:53 +04:00
_blocking_supported = find_config_tree_bool ( cmd , global_wait_for_locks_CFG , NULL ) ;
2018-06-07 00:31:59 +03:00
_file_locking_readonly = file_locking_readonly ;
_file_locking_sysinit = file_locking_sysinit ;
2018-05-23 18:15:39 +03:00
2018-06-05 18:47:01 +03:00
log_very_verbose ( " %sFile-based locking selected. " , _blocking_supported ? " " : " Non-blocking " ) ;
2018-05-23 18:15:39 +03:00
2018-06-05 18:47:01 +03:00
if ( ! init_file_locking ( & _locking , cmd , suppress_messages ) )
log_error_suppress ( suppress_messages , " File-based locking initialisation failed. " ) ;
2002-07-11 00:43:32 +04:00
2002-02-11 18:42:34 +03:00
return 1 ;
}
void fin_locking ( void )
{
2018-06-07 00:31:59 +03:00
/* file locking disabled */
if ( ! _locking . flags )
return ;
2002-02-11 18:42:34 +03:00
_locking . fin_locking ( ) ;
}
/*
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
*/
2018-06-06 00:47:24 +03:00
static int _lock_vol ( struct cmd_context * cmd , const char * resource , uint32_t flags )
2002-03-05 23:03:09 +03:00
{
2011-08-10 20:07:53 +04:00
uint32_t lck_type = flags & LCK_TYPE_MASK ;
uint32_t lck_scope = flags & LCK_SCOPE_MASK ;
2008-04-07 23:17:29 +04:00
int ret = 0 ;
2014-05-01 23:07:17 +04:00
block_signals ( flags ) ;
2002-03-05 23:03:09 +03:00
2007-11-17 00:16:20 +03:00
assert ( resource ) ;
2008-05-09 22:45:15 +04:00
if ( ! * resource ) {
2009-12-16 22:22:11 +03:00
log_error ( INTERNAL_ERROR " Use of P_orphans is deprecated. " ) ;
2013-07-06 12:58:56 +04:00
goto out ;
2008-05-09 22:45:15 +04:00
}
2010-05-19 06:36:33 +04:00
if ( ( is_orphan_vg ( resource ) | | is_global_vg ( resource ) ) & & ( flags & LCK_CACHE ) ) {
2018-02-19 17:30:55 +03:00
log_error ( INTERNAL_ERROR " P_%s referenced. " , resource ) ;
2013-07-06 12:58:56 +04:00
goto out ;
2008-05-09 22:45:15 +04:00
}
2018-06-07 00:31:59 +03:00
if ( ( lck_type = = LCK_WRITE ) & & ( lck_scope = = LCK_VG ) & & ! ( flags & LCK_CACHE ) & &
2010-10-25 15:20:54 +04:00
strcmp ( resource , VG_GLOBAL ) ) {
2018-06-07 00:31:59 +03:00
/* read only locking set in lvm.conf metadata_read_only */
if ( cmd - > metadata_read_only ) {
log_error ( " Operation prohibited while global/metadata_read_only is set. " ) ;
goto out ;
}
/* read only locking set with option --readonly */
if ( _file_locking_readonly ) {
log_error ( " Read-only locking specified. Write locks are prohibited. " ) ;
goto out ;
}
/* read only locking (except activation) set with option --sysinit */
/* FIXME: sysinit is intended to allow activation, add that exception here */
if ( _file_locking_sysinit ) {
log_error ( " Read-only sysinit locking specified. Write locks are prohibited. " ) ;
goto out ;
}
2010-10-25 15:20:54 +04:00
}
2018-06-06 00:47:24 +03:00
if ( ( ret = _locking . lock_resource ( cmd , resource , flags , NULL ) ) ) {
2011-08-10 20:07:53 +04:00
if ( lck_scope = = LCK_VG & & ! ( flags & LCK_CACHE ) ) {
if ( lck_type ! = LCK_UNLOCK )
lvmcache_lock_vgname ( resource , lck_type = = LCK_READ ) ;
2010-10-13 19:40:38 +04:00
dev_reset_error_count ( cmd ) ;
2008-04-07 23:17:29 +04:00
}
2009-07-14 15:01:26 +04:00
_update_vg_lock_count ( resource , flags ) ;
2010-04-13 05:54:32 +04:00
} else
stack ;
2002-03-05 23:03:09 +03:00
2011-08-10 20:07:53 +04:00
/* If unlocking, always remove lock from lvmcache even if operation failed. */
if ( lck_scope = = LCK_VG & & ! ( flags & LCK_CACHE ) & & lck_type = = LCK_UNLOCK ) {
lvmcache_unlock_vgname ( resource ) ;
if ( ! ret )
_update_vg_lock_count ( resource , flags ) ;
}
2013-07-06 12:58:56 +04:00
out :
2002-03-15 19:07:38 +03:00
_unblock_signals ( ) ;
2002-03-05 23:03:09 +03:00
2008-04-07 23:17:29 +04:00
return ret ;
2002-03-05 23:03:09 +03:00
}
2014-09-22 17:50:07 +04:00
int lock_vol ( struct cmd_context * cmd , const char * vol , uint32_t flags , const struct logical_volume * lv )
2002-02-11 18:42:34 +03:00
{
2010-07-09 19:34:40 +04:00
char resource [ 258 ] __attribute__ ( ( aligned ( 8 ) ) ) ;
2011-01-13 17:56:17 +03:00
int lck_type = flags & LCK_TYPE_MASK ;
2009-11-23 13:55:14 +03:00
2018-06-07 00:31:59 +03:00
/* file locking disabled */
if ( ! _locking . flags )
return 1 ;
2007-11-16 00:30:52 +03:00
if ( flags = = LCK_NONE ) {
2013-01-08 02:30:29 +04:00
log_debug_locking ( INTERNAL_ERROR " %s: LCK_NONE lock requested " , vol ) ;
2007-11-16 00:30:52 +03:00
return 1 ;
}
2002-02-11 18:42:34 +03:00
switch ( flags & LCK_SCOPE_MASK ) {
2002-11-01 22:57:25 +03:00
case LCK_VG :
2010-03-31 21:23:56 +04:00
if ( ! _blocking_supported )
2009-05-13 17:02:52 +04:00
flags | = LCK_NONBLOCK ;
2010-05-19 05:16:40 +04:00
/* Global VG_ORPHANS lock covers all orphan formats. */
if ( is_orphan_vg ( vol ) )
vol = VG_ORPHANS ;
2009-07-24 22:15:06 +04:00
break ;
2002-02-11 18:42:34 +03:00
default :
log_error ( " Unrecognised lock scope: %d " ,
flags & LCK_SCOPE_MASK ) ;
return 0 ;
}
2018-02-19 17:30:55 +03:00
if ( ! dm_strncpy ( resource , vol , sizeof ( resource ) ) ) {
log_error ( INTERNAL_ERROR " Resource name %s is too long. " , vol ) ;
return 0 ;
}
2009-07-24 22:15:06 +04:00
2018-06-06 00:47:24 +03:00
if ( ! _lock_vol ( cmd , resource , flags ) )
2011-01-13 17:56:17 +03:00
return_0 ;
2002-02-11 18:42:34 +03:00
2008-05-08 22:35:58 +04:00
/*
* If a real lock was acquired ( i . e . not LCK_CACHE ) ,
* perform an immediate unlock unless LCK_HOLD was requested .
*/
2011-01-13 17:56:17 +03:00
if ( ( lck_type = = LCK_NULL ) | | ( lck_type = = LCK_UNLOCK ) | |
( flags & ( LCK_CACHE | LCK_HOLD ) ) )
return 1 ;
2018-06-06 00:47:24 +03:00
if ( ! _lock_vol ( cmd , resource , ( flags & ~ LCK_TYPE_MASK ) | LCK_UNLOCK ) )
2011-01-13 17:56:17 +03:00
return_0 ;
2002-02-11 18:42:34 +03:00
return 1 ;
}
2003-11-21 22:54:40 +03:00
2004-05-05 16:03:07 +04:00
/* Lock a list of LVs */
2018-01-31 12:53:09 +03:00
int activate_lvs ( struct cmd_context * cmd , struct dm_list * lvs , unsigned exclusive )
2004-05-05 16:03:07 +04:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * lvh ;
2005-06-01 20:51:55 +04:00
struct lv_list * lvl ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , lvs ) {
2018-06-05 21:21:28 +03:00
if ( ! activate_lv ( cmd , lvl - > lv ) ) {
2018-01-31 12:53:09 +03:00
log_error ( " Failed to activate %s " , display_lvname ( lvl - > lv ) ) ;
2018-06-05 21:21:28 +03:00
2008-11-04 01:14:30 +03:00
dm_list_uniterate ( lvh , lvs , & lvl - > list ) {
lvl = dm_list_item ( lvh , struct lv_list ) ;
2017-11-14 13:35:50 +03:00
if ( ! deactivate_lv ( cmd , lvl - > lv ) )
2010-01-06 00:08:34 +03:00
stack ;
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 )
{
2018-06-07 00:31:59 +03:00
return 0 ;
2005-03-22 01:55:12 +03:00
}
2011-02-18 17:16:11 +03:00
int sync_local_dev_names ( struct cmd_context * cmd )
{
memlock_unlock ( cmd ) ;
2011-04-29 00:29:59 +04:00
2013-03-18 00:29:58 +04:00
return lock_vol ( cmd , VG_SYNC_NAMES , LCK_VG_SYNC_LOCAL , NULL ) ;
2011-02-18 17:16:11 +03:00
}
int sync_dev_names ( struct cmd_context * cmd )
{
memlock_unlock ( cmd ) ;
2011-04-29 00:29:59 +04:00
2013-03-18 00:29:58 +04:00
return lock_vol ( cmd , VG_SYNC_NAMES , LCK_VG_SYNC , NULL ) ;
2011-02-18 17:16:11 +03:00
}
2018-06-06 00:47:24 +03:00