2004-06-24 12:02:38 +04:00
/*
* Copyright ( C ) 2002 - 2004 Sistina Software , Inc . All rights reserved .
2009-02-23 00:14:37 +03:00
* Copyright ( C ) 2004 - 2009 Red Hat , Inc . All rights reserved .
2004-06-24 12:02:38 +04:00
*
* This file is part of LVM2 .
*
* 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
*/
2008-11-04 19:41:47 +03:00
# define _GNU_SOURCE
# define _FILE_OFFSET_BITS 64
# include <configure.h>
2004-06-24 12:02:38 +04:00
# include <pthread.h>
# include <sys/types.h>
# include <sys/utsname.h>
# include <sys/ioctl.h>
# include <sys/socket.h>
# include <sys/stat.h>
# include <stdio.h>
# include <stdlib.h>
# include <stdint.h>
# include <fcntl.h>
# include <string.h>
# include <stddef.h>
# include <stdint.h>
# include <unistd.h>
# include <errno.h>
# include <syslog.h>
# include <assert.h>
2007-04-27 21:46:16 +04:00
# include <libdevmapper.h>
# include <libdlm.h>
2004-06-24 12:02:38 +04:00
2005-11-09 12:24:10 +03:00
# include "lvm-types.h"
2004-06-24 12:02:38 +04:00
# include "clvm.h"
# include "clvmd-comms.h"
# include "clvmd.h"
# include "lvm-functions.h"
/* LVM2 headers */
# include "toolcontext.h"
2007-08-23 16:44:09 +04:00
# include "lvmcache.h"
2008-11-04 19:41:47 +03:00
# include "lvm-logging.h"
# include "lvm-globals.h"
2004-06-24 12:02:38 +04:00
# include "activate.h"
# include "locking.h"
2007-12-04 18:39:26 +03:00
# include "archiver.h"
2006-05-15 16:32:08 +04:00
# include "defaults.h"
2009-12-09 22:30:56 +03:00
# include "memlock.h"
2004-06-24 12:02:38 +04:00
static struct cmd_context * cmd = NULL ;
2005-11-09 12:24:10 +03:00
static struct dm_hash_table * lv_hash = NULL ;
2004-09-22 16:10:34 +04:00
static pthread_mutex_t lv_hash_lock ;
2007-04-24 19:13:13 +04:00
static pthread_mutex_t lvm_lock ;
2006-10-05 17:55:50 +04:00
static char last_error [ 1024 ] ;
2007-12-05 16:17:18 +03:00
static int suspended = 0 ;
2004-06-24 12:02:38 +04:00
struct lv_info {
int lock_id ;
int lock_mode ;
} ;
2008-06-05 18:24:28 +04:00
static const char * decode_locking_cmd ( unsigned char cmdl )
{
static char buf [ 128 ] ;
const char * type ;
const char * scope ;
const char * command ;
switch ( cmdl & LCK_TYPE_MASK ) {
2010-01-05 19:03:37 +03:00
case LCK_NULL :
type = " NULL " ;
2008-06-05 18:24:28 +04:00
break ;
2010-01-05 19:03:37 +03:00
case LCK_READ :
type = " READ " ;
2008-06-05 18:24:28 +04:00
break ;
2010-01-05 19:03:37 +03:00
case LCK_PREAD :
type = " PREAD " ;
2008-06-05 18:24:28 +04:00
break ;
2010-01-05 19:03:37 +03:00
case LCK_WRITE :
type = " WRITE " ;
2008-06-05 18:24:28 +04:00
break ;
2010-01-05 19:03:37 +03:00
case LCK_EXCL :
type = " EXCL " ;
2008-06-05 18:24:28 +04:00
break ;
2010-01-05 19:03:37 +03:00
case LCK_UNLOCK :
type = " UNLOCK " ;
2008-06-05 18:24:28 +04:00
break ;
default :
type = " unknown " ;
break ;
}
switch ( cmdl & LCK_SCOPE_MASK ) {
2010-01-05 19:03:37 +03:00
case LCK_VG :
scope = " VG " ;
command = " LCK_VG " ;
2008-06-05 18:24:28 +04:00
break ;
2010-01-05 19:03:37 +03:00
case LCK_LV :
2008-06-05 18:24:28 +04:00
scope = " LV " ;
2010-01-05 19:03:37 +03:00
switch ( cmdl & LCK_MASK ) {
case LCK_LV_EXCLUSIVE & LCK_MASK :
command = " LCK_LV_EXCLUSIVE " ;
break ;
case LCK_LV_SUSPEND & LCK_MASK :
command = " LCK_LV_SUSPEND " ;
break ;
case LCK_LV_RESUME & LCK_MASK :
command = " LCK_LV_RESUME " ;
break ;
case LCK_LV_ACTIVATE & LCK_MASK :
command = " LCK_LV_ACTIVATE " ;
break ;
case LCK_LV_DEACTIVATE & LCK_MASK :
command = " LCK_LV_DEACTIVATE " ;
break ;
default :
command = " unknown " ;
break ;
}
2008-06-05 18:24:28 +04:00
break ;
default :
scope = " unknown " ;
command = " unknown " ;
break ;
}
sprintf ( buf , " 0x%x %s (%s|%s%s%s%s%s%s) " , cmdl , command , type , scope ,
cmdl & LCK_NONBLOCK ? " |NONBLOCK " : " " ,
cmdl & LCK_HOLD ? " |HOLD " : " " ,
cmdl & LCK_LOCAL ? " |LOCAL " : " " ,
cmdl & LCK_CLUSTER_VG ? " |CLUSTER_VG " : " " ,
cmdl & LCK_CACHE ? " |CACHE " : " " ) ;
return buf ;
}
static const char * decode_flags ( unsigned char flags )
{
static char buf [ 128 ] ;
2009-10-01 18:14:17 +04:00
sprintf ( buf , " 0x%x (%s%s%s%s) " , flags ,
2009-06-12 12:30:19 +04:00
flags & LCK_PARTIAL_MODE ? " PARTIAL_MODE " : " " ,
2008-06-05 18:24:28 +04:00
flags & LCK_MIRROR_NOSYNC_MODE ? " MIRROR_NOSYNC " : " " ,
2009-10-01 18:14:17 +04:00
flags & LCK_DMEVENTD_MONITOR_MODE ? " DMEVENTD_MONITOR " : " " ,
flags & LCK_CONVERT ? " CONVERT " : " " ) ;
2008-06-05 18:24:28 +04:00
return buf ;
}
2006-10-05 17:55:50 +04:00
char * get_last_lvm_error ( )
{
return last_error ;
}
2009-04-21 17:11:28 +04:00
/*
* Hash lock info helpers
*/
static struct lv_info * lookup_info ( const char * resource )
2004-06-24 12:02:38 +04:00
{
struct lv_info * lvi ;
2004-09-22 16:10:34 +04:00
pthread_mutex_lock ( & lv_hash_lock ) ;
2005-11-09 12:24:10 +03:00
lvi = dm_hash_lookup ( lv_hash , resource ) ;
2004-09-22 16:10:34 +04:00
pthread_mutex_unlock ( & lv_hash_lock ) ;
2009-04-21 17:11:28 +04:00
return lvi ;
}
static void insert_info ( const char * resource , struct lv_info * lvi )
{
pthread_mutex_lock ( & lv_hash_lock ) ;
dm_hash_insert ( lv_hash , resource , lvi ) ;
pthread_mutex_unlock ( & lv_hash_lock ) ;
}
static void remove_info ( const char * resource )
{
pthread_mutex_lock ( & lv_hash_lock ) ;
dm_hash_remove ( lv_hash , resource ) ;
pthread_mutex_unlock ( & lv_hash_lock ) ;
}
/*
* Return the mode a lock is currently held at ( or - 1 if not held )
*/
static int get_current_lock ( char * resource )
{
struct lv_info * lvi ;
if ( ( lvi = lookup_info ( resource ) ) )
2004-06-24 12:02:38 +04:00
return lvi - > lock_mode ;
2009-04-21 17:11:28 +04:00
return - 1 ;
}
void init_lvhash ( )
{
/* Create hash table for keeping LV locks & status */
lv_hash = dm_hash_create ( 100 ) ;
pthread_mutex_init ( & lv_hash_lock , NULL ) ;
pthread_mutex_init ( & lvm_lock , NULL ) ;
2004-06-24 12:02:38 +04:00
}
/* Called at shutdown to tidy the lockspace */
2009-04-21 17:11:28 +04:00
void destroy_lvhash ( )
2004-06-24 12:02:38 +04:00
{
2005-11-09 12:24:10 +03:00
struct dm_hash_node * v ;
2009-04-21 17:11:28 +04:00
struct lv_info * lvi ;
char * resource ;
int status ;
2004-09-22 16:10:34 +04:00
pthread_mutex_lock ( & lv_hash_lock ) ;
2009-04-21 17:11:28 +04:00
2005-11-09 12:24:10 +03:00
dm_hash_iterate ( v , lv_hash ) {
2009-04-21 17:11:28 +04:00
lvi = dm_hash_get_data ( lv_hash , v ) ;
resource = dm_hash_get_key ( lv_hash , v ) ;
2004-06-24 12:02:38 +04:00
2009-04-21 17:11:28 +04:00
if ( ( status = sync_unlock ( resource , lvi - > lock_id ) ) )
DEBUGLOG ( " unlock_all. unlock failed(%d): %s \n " ,
status , strerror ( errno ) ) ;
free ( lvi ) ;
2004-06-24 12:02:38 +04:00
}
2009-04-21 17:11:28 +04:00
dm_hash_destroy ( lv_hash ) ;
lv_hash = NULL ;
2004-09-22 16:10:34 +04:00
pthread_mutex_unlock ( & lv_hash_lock ) ;
2004-06-24 12:02:38 +04:00
}
/* Gets a real lock and keeps the info in the hash table */
int hold_lock ( char * resource , int mode , int flags )
{
int status ;
int saved_errno ;
struct lv_info * lvi ;
2009-10-01 18:14:17 +04:00
/* Mask off invalid options */
flags & = LKF_NOQUEUE | LKF_CONVERT ;
2004-06-24 12:02:38 +04:00
2009-10-01 18:14:17 +04:00
lvi = lookup_info ( resource ) ;
2009-12-09 21:45:12 +03:00
if ( lvi & & lvi - > lock_mode = = mode ) {
DEBUGLOG ( " hold_lock, lock mode %d already held \n " , mode ) ;
return 0 ;
}
2009-10-01 18:14:17 +04:00
/* Only allow explicit conversions */
if ( lvi & & ! ( flags & LKF_CONVERT ) ) {
errno = EBUSY ;
return - 1 ;
}
if ( lvi ) {
2004-06-24 12:02:38 +04:00
/* Already exists - convert it */
status =
2009-10-01 18:14:17 +04:00
sync_lock ( resource , mode , flags , & lvi - > lock_id ) ;
2004-06-24 12:02:38 +04:00
saved_errno = errno ;
if ( ! status )
lvi - > lock_mode = mode ;
if ( status ) {
DEBUGLOG ( " hold_lock. convert to %d failed: %s \n " , mode ,
strerror ( errno ) ) ;
}
errno = saved_errno ;
} else {
lvi = malloc ( sizeof ( struct lv_info ) ) ;
if ( ! lvi )
return - 1 ;
lvi - > lock_mode = mode ;
2009-12-09 21:55:53 +03:00
status = sync_lock ( resource , mode , flags & ~ LKF_CONVERT , & lvi - > lock_id ) ;
2004-06-24 12:02:38 +04:00
saved_errno = errno ;
if ( status ) {
free ( lvi ) ;
DEBUGLOG ( " hold_lock. lock at %d failed: %s \n " , mode ,
strerror ( errno ) ) ;
2009-04-21 17:11:28 +04:00
} else
insert_info ( resource , lvi ) ;
2004-06-24 12:02:38 +04:00
errno = saved_errno ;
}
return status ;
}
/* Unlock and remove it from the hash table */
int hold_unlock ( char * resource )
{
struct lv_info * lvi ;
int status ;
int saved_errno ;
2009-04-21 17:11:28 +04:00
if ( ! ( lvi = lookup_info ( resource ) ) ) {
2004-06-24 12:02:38 +04:00
DEBUGLOG ( " hold_unlock, lock not already held \n " ) ;
return 0 ;
}
status = sync_unlock ( resource , lvi - > lock_id ) ;
saved_errno = errno ;
if ( ! status ) {
2009-04-21 17:11:28 +04:00
remove_info ( resource ) ;
2004-06-24 12:02:38 +04:00
free ( lvi ) ;
} else {
DEBUGLOG ( " hold_unlock. unlock failed(%d): %s \n " , status ,
strerror ( errno ) ) ;
}
errno = saved_errno ;
return status ;
}
/* Watch the return codes here.
liblvm API functions return 1 ( true ) for success , 0 ( false ) for failure and don ' t set errno .
libdlm API functions return 0 for success , - 1 for failure and do set errno .
These functions here return 0 for success or > 0 for failure ( where the retcode is errno )
*/
/* Activate LV exclusive or non-exclusive */
2005-08-16 12:25:09 +04:00
static int do_activate_lv ( char * resource , unsigned char lock_flags , int mode )
2004-06-24 12:02:38 +04:00
{
int oldmode ;
int status ;
int activate_lv ;
2005-08-15 03:18:28 +04:00
int exclusive = 0 ;
2004-06-24 12:02:38 +04:00
struct lvinfo lvi ;
/* Is it already open ? */
oldmode = get_current_lock ( resource ) ;
2009-12-09 22:00:16 +03:00
if ( oldmode = = mode & & ( lock_flags & LCK_CLUSTER_VG ) ) {
DEBUGLOG ( " do_activate_lv, lock already held at %d \n " , oldmode ) ;
2004-06-24 12:02:38 +04:00
return 0 ; /* Nothing to do */
}
/* Does the config file want us to activate this LV ? */
if ( ! lv_activation_filter ( cmd , resource , & activate_lv ) )
return EIO ;
if ( ! activate_lv )
return 0 ; /* Success, we did nothing! */
/* Do we need to activate exclusively? */
2005-08-15 03:18:28 +04:00
if ( ( activate_lv = = 2 ) | | ( mode = = LKM_EXMODE ) ) {
exclusive = 1 ;
2004-06-24 12:02:38 +04:00
mode = LKM_EXMODE ;
2005-08-15 03:18:28 +04:00
}
2004-06-24 12:02:38 +04:00
2009-12-09 21:55:53 +03:00
/*
* Try to get the lock if it ' s a clustered volume group .
* Use lock conversion only if requested , to prevent implicit conversion
* of exclusive lock to shared one during activation .
*/
2005-08-16 12:25:09 +04:00
if ( lock_flags & LCK_CLUSTER_VG ) {
2009-10-01 18:14:17 +04:00
status = hold_lock ( resource , mode , LKF_NOQUEUE | ( lock_flags & LCK_CONVERT ? LKF_CONVERT : 0 ) ) ;
2006-10-05 17:55:50 +04:00
if ( status ) {
/* Return an LVM-sensible error for this.
* Forcing EIO makes the upper level return this text
* rather than the strerror text for EAGAIN .
*/
if ( errno = = EAGAIN ) {
sprintf ( last_error , " Volume is busy on another node " ) ;
errno = EIO ;
}
2005-08-16 12:25:09 +04:00
return errno ;
2006-10-05 17:55:50 +04:00
}
2005-08-16 12:25:09 +04:00
}
2004-06-24 12:02:38 +04:00
/* If it's suspended then resume it */
2007-11-14 16:37:51 +03:00
if ( ! lv_info_by_lvid ( cmd , resource , & lvi , 0 , 0 ) )
2004-06-24 12:02:38 +04:00
return EIO ;
if ( lvi . suspended )
if ( ! lv_resume ( cmd , resource ) )
return EIO ;
/* Now activate it */
2005-08-15 03:18:28 +04:00
if ( ! lv_activate ( cmd , resource , exclusive ) )
2004-06-24 12:02:38 +04:00
return EIO ;
return 0 ;
}
/* Resume the LV if it was active */
2009-12-09 22:00:16 +03:00
static int do_resume_lv ( char * resource , unsigned char lock_flags )
2004-06-24 12:02:38 +04:00
{
int oldmode ;
/* Is it open ? */
oldmode = get_current_lock ( resource ) ;
2009-12-09 22:00:16 +03:00
if ( oldmode = = - 1 & & ( lock_flags & LCK_CLUSTER_VG ) ) {
2006-10-24 22:49:31 +04:00
DEBUGLOG ( " do_resume_lv, lock not already held \n " ) ;
2004-06-24 12:02:38 +04:00
return 0 ; /* We don't need to do anything */
}
if ( ! lv_resume_if_active ( cmd , resource ) )
return EIO ;
return 0 ;
}
/* Suspend the device if active */
2009-12-09 22:00:16 +03:00
static int do_suspend_lv ( char * resource , unsigned char lock_flags )
2004-06-24 12:02:38 +04:00
{
int oldmode ;
struct lvinfo lvi ;
/* Is it open ? */
oldmode = get_current_lock ( resource ) ;
2009-12-09 22:00:16 +03:00
if ( oldmode = = - 1 & & ( lock_flags & LCK_CLUSTER_VG ) ) {
DEBUGLOG ( " do_suspend_lv, lock not already held \n " ) ;
2004-06-24 12:02:38 +04:00
return 0 ; /* Not active, so it's OK */
}
/* Only suspend it if it exists */
2007-11-14 16:37:51 +03:00
if ( ! lv_info_by_lvid ( cmd , resource , & lvi , 0 , 0 ) )
2004-06-24 12:02:38 +04:00
return EIO ;
if ( lvi . exists ) {
if ( ! lv_suspend_if_active ( cmd , resource ) ) {
return EIO ;
}
}
return 0 ;
}
2005-08-16 12:25:09 +04:00
static int do_deactivate_lv ( char * resource , unsigned char lock_flags )
2004-06-24 12:02:38 +04:00
{
int oldmode ;
int status ;
/* Is it open ? */
oldmode = get_current_lock ( resource ) ;
2005-08-16 12:25:09 +04:00
if ( oldmode = = - 1 & & ( lock_flags & LCK_CLUSTER_VG ) ) {
2004-06-24 12:02:38 +04:00
DEBUGLOG ( " do_deactivate_lock, lock not already held \n " ) ;
return 0 ; /* We don't need to do anything */
}
if ( ! lv_deactivate ( cmd , resource ) )
return EIO ;
2005-08-16 12:25:09 +04:00
if ( lock_flags & LCK_CLUSTER_VG ) {
status = hold_unlock ( resource ) ;
if ( status )
return errno ;
}
2004-06-24 12:02:38 +04:00
return 0 ;
}
2009-05-19 14:38:58 +04:00
const char * do_lock_query ( char * resource )
{
int mode ;
const char * type = NULL ;
mode = get_current_lock ( resource ) ;
switch ( mode ) {
case LKM_NLMODE : type = " NL " ; break ;
case LKM_CRMODE : type = " CR " ; break ;
case LKM_CWMODE : type = " CW " ; break ;
case LKM_PRMODE : type = " PR " ; break ;
case LKM_PWMODE : type = " PW " ; break ;
case LKM_EXMODE : type = " EX " ; break ;
}
DEBUGLOG ( " do_lock_query: resource '%s', mode %i (%s) \n " , resource , mode , type ? : " ? " ) ;
return type ;
}
2004-06-24 12:02:38 +04:00
/* This is the LOCK_LV part that happens on all nodes in the cluster -
it is responsible for the interaction with device - mapper and LVM */
int do_lock_lv ( unsigned char command , unsigned char lock_flags , char * resource )
{
int status = 0 ;
2009-12-09 22:01:27 +03:00
DEBUGLOG ( " do_lock_lv: resource '%s', cmd = %s, flags = %s, memlock = %d \n " ,
resource , decode_locking_cmd ( command ) , decode_flags ( lock_flags ) , memlock ( ) ) ;
2004-06-24 12:02:38 +04:00
if ( ! cmd - > config_valid | | config_files_changed ( cmd ) ) {
/* Reinitialise various settings inc. logging, filters */
2008-04-04 12:53:47 +04:00
if ( do_refresh_cache ( ) ) {
2004-06-24 12:02:38 +04:00
log_error ( " Updated config file invalid. Aborting. " ) ;
return EINVAL ;
}
}
2009-03-05 19:25:35 +03:00
pthread_mutex_lock ( & lvm_lock ) ;
2006-05-11 23:05:21 +04:00
if ( lock_flags & LCK_MIRROR_NOSYNC_MODE )
init_mirror_in_sync ( 1 ) ;
2007-01-20 01:21:45 +03:00
if ( ! ( lock_flags & LCK_DMEVENTD_MONITOR_MODE ) )
init_dmeventd_monitor ( 0 ) ;
2006-05-12 23:16:48 +04:00
2009-06-12 12:30:19 +04:00
cmd - > partial_activation = ( lock_flags & LCK_PARTIAL_MODE ) ? 1 : 0 ;
2010-01-19 16:25:00 +03:00
/* clvmd should never try to read suspended device */
init_ignore_suspended_devices ( 1 ) ;
2009-08-05 18:18:35 +04:00
switch ( command & LCK_MASK ) {
case LCK_LV_EXCLUSIVE :
2005-08-16 12:25:09 +04:00
status = do_activate_lv ( resource , lock_flags , LKM_EXMODE ) ;
2004-06-24 12:02:38 +04:00
break ;
2009-08-05 18:18:35 +04:00
case LCK_LV_SUSPEND :
2009-12-09 22:00:16 +03:00
status = do_suspend_lv ( resource , lock_flags ) ;
2007-12-05 16:17:18 +03:00
if ( ! status )
suspended + + ;
2004-06-24 12:02:38 +04:00
break ;
case LCK_UNLOCK :
2009-08-05 18:18:35 +04:00
case LCK_LV_RESUME : /* if active */
2009-12-09 22:00:16 +03:00
status = do_resume_lv ( resource , lock_flags ) ;
2007-12-05 16:17:18 +03:00
if ( ! status )
suspended - - ;
2004-06-24 12:02:38 +04:00
break ;
2009-08-05 18:18:35 +04:00
case LCK_LV_ACTIVATE :
2005-08-16 12:25:09 +04:00
status = do_activate_lv ( resource , lock_flags , LKM_CRMODE ) ;
2004-06-24 12:02:38 +04:00
break ;
2009-08-05 18:18:35 +04:00
case LCK_LV_DEACTIVATE :
2005-08-16 12:25:09 +04:00
status = do_deactivate_lv ( resource , lock_flags ) ;
2004-06-24 12:02:38 +04:00
break ;
default :
DEBUGLOG ( " Invalid LV command 0x%x \n " , command ) ;
status = EINVAL ;
break ;
}
2006-05-12 23:16:48 +04:00
if ( lock_flags & LCK_MIRROR_NOSYNC_MODE )
init_mirror_in_sync ( 0 ) ;
2007-01-20 01:21:45 +03:00
if ( ! ( lock_flags & LCK_DMEVENTD_MONITOR_MODE ) )
init_dmeventd_monitor ( DEFAULT_DMEVENTD_MONITOR ) ;
2006-05-12 23:16:48 +04:00
2009-06-12 12:30:19 +04:00
cmd - > partial_activation = 0 ;
2004-06-24 12:02:38 +04:00
/* clean the pool for another command */
2005-10-17 03:03:59 +04:00
dm_pool_empty ( cmd - > mem ) ;
2007-04-24 19:13:13 +04:00
pthread_mutex_unlock ( & lvm_lock ) ;
2004-06-24 12:02:38 +04:00
2009-12-09 22:01:27 +03:00
DEBUGLOG ( " Command return is %d, memlock is %d \n " , status , memlock ( ) ) ;
2004-06-24 12:02:38 +04:00
return status ;
}
/* Functions to do on the local node only BEFORE the cluster-wide stuff above happens */
int pre_lock_lv ( unsigned char command , unsigned char lock_flags , char * resource )
{
/* Nearly all the stuff happens cluster-wide. Apart from SUSPEND. Here we get the
lock out on this node ( because we are the node modifying the metadata )
before suspending cluster - wide .
2009-12-09 21:55:53 +03:00
LKF_CONVERT is used always , local node is going to modify metadata
2004-06-24 12:02:38 +04:00
*/
2009-12-09 22:00:16 +03:00
if ( ( command & ( LCK_SCOPE_MASK | LCK_TYPE_MASK ) ) = = LCK_LV_SUSPEND & &
( lock_flags & LCK_CLUSTER_VG ) ) {
2008-06-05 18:24:28 +04:00
DEBUGLOG ( " pre_lock_lv: resource '%s', cmd = %s, flags = %s \n " ,
resource , decode_locking_cmd ( command ) , decode_flags ( lock_flags ) ) ;
2004-06-24 12:02:38 +04:00
2009-12-09 21:55:53 +03:00
if ( hold_lock ( resource , LKM_PWMODE , LKF_NOQUEUE | LKF_CONVERT ) )
2004-06-24 12:02:38 +04:00
return errno ;
}
return 0 ;
}
/* Functions to do on the local node only AFTER the cluster-wide stuff above happens */
int post_lock_lv ( unsigned char command , unsigned char lock_flags ,
char * resource )
{
2007-04-24 19:13:13 +04:00
int status ;
2004-06-24 12:02:38 +04:00
/* Opposite of above, done on resume after a metadata update */
2009-12-09 22:00:16 +03:00
if ( ( command & ( LCK_SCOPE_MASK | LCK_TYPE_MASK ) ) = = LCK_LV_RESUME & &
( lock_flags & LCK_CLUSTER_VG ) ) {
2004-06-24 12:02:38 +04:00
int oldmode ;
DEBUGLOG
2008-06-05 18:24:28 +04:00
( " post_lock_lv: resource '%s', cmd = %s, flags = %s \n " ,
resource , decode_locking_cmd ( command ) , decode_flags ( lock_flags ) ) ;
2004-06-24 12:02:38 +04:00
/* If the lock state is PW then restore it to what it was */
oldmode = get_current_lock ( resource ) ;
if ( oldmode = = LKM_PWMODE ) {
struct lvinfo lvi ;
2007-04-24 19:13:13 +04:00
pthread_mutex_lock ( & lvm_lock ) ;
2007-11-14 16:37:51 +03:00
status = lv_info_by_lvid ( cmd , resource , & lvi , 0 , 0 ) ;
2007-04-24 19:13:13 +04:00
pthread_mutex_unlock ( & lvm_lock ) ;
if ( ! status )
2004-06-24 12:02:38 +04:00
return EIO ;
if ( lvi . exists ) {
2009-12-09 21:55:53 +03:00
if ( hold_lock ( resource , LKM_CRMODE , LKF_CONVERT ) )
2004-06-24 12:02:38 +04:00
return errno ;
} else {
if ( hold_unlock ( resource ) )
return errno ;
}
}
}
return 0 ;
}
2008-04-04 12:53:47 +04:00
/* Check if a VG is in use by LVM1 so we don't stomp on it */
2007-08-07 13:06:05 +04:00
int do_check_lvm1 ( const char * vgname )
2004-06-24 12:02:38 +04:00
{
int status ;
status = check_lvm1_vg_inactive ( cmd , vgname ) ;
return status = = 1 ? 0 : EBUSY ;
}
2006-10-04 12:22:16 +04:00
int do_refresh_cache ( )
{
DEBUGLOG ( " Refreshing context \n " ) ;
log_notice ( " Refreshing context " ) ;
2007-08-23 16:19:13 +04:00
2009-03-05 19:25:35 +03:00
pthread_mutex_lock ( & lvm_lock ) ;
2009-10-22 21:45:23 +04:00
if ( ! refresh_toolcontext ( cmd ) ) {
pthread_mutex_unlock ( & lvm_lock ) ;
return - 1 ;
}
2007-08-23 16:19:13 +04:00
init_full_scan_done ( 0 ) ;
2010-01-19 16:25:00 +03:00
init_ignore_suspended_devices ( 1 ) ;
2007-08-23 16:44:09 +04:00
lvmcache_label_scan ( cmd , 2 ) ;
2009-03-05 19:25:35 +03:00
dm_pool_empty ( cmd - > mem ) ;
pthread_mutex_unlock ( & lvm_lock ) ;
2007-08-23 16:19:13 +04:00
2009-10-22 21:45:23 +04:00
return 0 ;
2006-10-04 12:22:16 +04:00
}
2005-03-07 20:03:44 +03:00
/* Only called at gulm startup. Drop any leftover VG or P_orphan locks
that might be hanging around if we died for any reason
*/
static void drop_vg_locks ( )
{
char vg [ 128 ] ;
char line [ 255 ] ;
FILE * vgs =
popen
2008-04-08 17:03:13 +04:00
( " lvm pvs --config 'log{command_names=0 prefix= \" \" }' --nolocking --noheadings -o vg_name " , " r " ) ;
2005-03-07 20:03:44 +03:00
2008-05-09 23:26:58 +04:00
sync_unlock ( " P_ " VG_ORPHANS , LCK_EXCL ) ;
sync_unlock ( " P_ " VG_GLOBAL , LCK_EXCL ) ;
2005-03-07 20:03:44 +03:00
if ( ! vgs )
return ;
while ( fgets ( line , sizeof ( line ) , vgs ) ) {
char * vgend ;
char * vgstart ;
if ( line [ strlen ( line ) - 1 ] = = ' \n ' )
line [ strlen ( line ) - 1 ] = ' \0 ' ;
vgstart = line + strspn ( line , " " ) ;
vgend = vgstart + strcspn ( vgstart , " " ) ;
* vgend = ' \0 ' ;
if ( strncmp ( vgstart , " WARNING: " , 8 ) = = 0 )
continue ;
sprintf ( vg , " V_%s " , vgstart ) ;
sync_unlock ( vg , LCK_EXCL ) ;
}
2007-01-25 17:37:48 +03:00
if ( fclose ( vgs ) )
DEBUGLOG ( " vgs fclose failed: %s \n " , strerror ( errno ) ) ;
2005-03-07 20:03:44 +03:00
}
2008-05-09 19:13:20 +04:00
/*
2010-01-05 19:05:12 +03:00
* Handle VG lock - drop metadata or update lvmcache state
2008-05-09 19:13:20 +04:00
*/
2010-01-05 19:05:12 +03:00
void do_lock_vg ( unsigned char command , unsigned char lock_flags , char * resource )
2008-05-09 19:13:20 +04:00
{
2010-01-05 19:09:33 +03:00
uint32_t lock_cmd = command ;
2010-01-05 19:05:12 +03:00
char * vgname = resource + 2 ;
DEBUGLOG ( " do_lock_vg: resource '%s', cmd = %s, flags = %s, memlock = %d \n " ,
resource , decode_locking_cmd ( command ) , decode_flags ( lock_flags ) , memlock ( ) ) ;
/* P_#global causes a full cache refresh */
if ( ! strcmp ( resource , " P_ " VG_GLOBAL ) ) {
do_refresh_cache ( ) ;
return ;
}
2010-01-05 19:09:33 +03:00
lock_cmd & = ( LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_HOLD ) ;
/*
* Check if LCK_CACHE should be set . All P_ locks except # are cache related .
*/
if ( strncmp ( resource , " P_# " , 3 ) & & ! strncmp ( resource , " P_ " , 2 ) )
lock_cmd | = LCK_CACHE ;
2008-05-09 19:13:20 +04:00
pthread_mutex_lock ( & lvm_lock ) ;
2010-01-05 19:09:33 +03:00
switch ( lock_cmd ) {
case LCK_VG_COMMIT :
DEBUGLOG ( " vg_commit notification for VG %s \n " , vgname ) ;
lvmcache_commit_metadata ( vgname ) ;
break ;
case LCK_VG_REVERT :
DEBUGLOG ( " vg_revert notification for VG %s \n " , vgname ) ;
lvmcache_drop_metadata ( vgname , 1 ) ;
break ;
case LCK_VG_DROP_CACHE :
default :
DEBUGLOG ( " Invalidating cached metadata for VG %s \n " , vgname ) ;
lvmcache_drop_metadata ( vgname , 0 ) ;
}
2008-05-09 19:13:20 +04:00
pthread_mutex_unlock ( & lvm_lock ) ;
}
2005-02-07 17:45:38 +03:00
/*
* Ideally , clvmd should be started before any LVs are active
* but this may not be the case . . .
* I suppose this also comes in handy if clvmd crashes , not that it would !
*/
static void * get_initial_state ( )
2004-06-24 12:02:38 +04:00
{
2005-08-16 12:25:09 +04:00
char lv [ 64 ] , vg [ 64 ] , flags [ 25 ] , vg_flags [ 25 ] ;
2005-02-07 17:45:38 +03:00
char uuid [ 65 ] ;
char line [ 255 ] ;
FILE * lvs =
popen
2008-04-08 17:03:13 +04:00
( " lvm lvs --config 'log{command_names=0 prefix= \" \" }' --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr " ,
2005-02-07 17:45:38 +03:00
" r " ) ;
2004-06-24 12:02:38 +04:00
2005-02-07 17:45:38 +03:00
if ( ! lvs )
return NULL ;
while ( fgets ( line , sizeof ( line ) , lvs ) ) {
2005-08-16 12:25:09 +04:00
if ( sscanf ( line , " %s %s %s %s \n " , vg , lv , flags , vg_flags ) = = 4 ) {
2004-10-04 13:23:52 +04:00
2004-06-24 12:02:38 +04:00
/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
2005-02-07 17:45:38 +03:00
if ( strlen ( vg ) = = 38 & & /* is is a valid UUID ? */
2005-08-16 12:25:09 +04:00
( flags [ 4 ] = = ' a ' | | flags [ 4 ] = = ' s ' ) & & /* is it active or suspended? */
vg_flags [ 5 ] = = ' c ' ) { /* is it clustered ? */
2004-06-24 12:02:38 +04:00
/* Convert hyphen-separated UUIDs into one */
memcpy ( & uuid [ 0 ] , & vg [ 0 ] , 6 ) ;
memcpy ( & uuid [ 6 ] , & vg [ 7 ] , 4 ) ;
memcpy ( & uuid [ 10 ] , & vg [ 12 ] , 4 ) ;
memcpy ( & uuid [ 14 ] , & vg [ 17 ] , 4 ) ;
memcpy ( & uuid [ 18 ] , & vg [ 22 ] , 4 ) ;
memcpy ( & uuid [ 22 ] , & vg [ 27 ] , 4 ) ;
memcpy ( & uuid [ 26 ] , & vg [ 32 ] , 6 ) ;
memcpy ( & uuid [ 32 ] , & lv [ 0 ] , 6 ) ;
memcpy ( & uuid [ 38 ] , & lv [ 7 ] , 4 ) ;
memcpy ( & uuid [ 42 ] , & lv [ 12 ] , 4 ) ;
memcpy ( & uuid [ 46 ] , & lv [ 17 ] , 4 ) ;
memcpy ( & uuid [ 50 ] , & lv [ 22 ] , 4 ) ;
memcpy ( & uuid [ 54 ] , & lv [ 27 ] , 4 ) ;
memcpy ( & uuid [ 58 ] , & lv [ 32 ] , 6 ) ;
uuid [ 64 ] = ' \0 ' ;
DEBUGLOG ( " getting initial lock for %s \n " , uuid ) ;
hold_lock ( uuid , LKM_CRMODE , LKF_NOQUEUE ) ;
}
}
}
2007-01-25 17:37:48 +03:00
if ( fclose ( lvs ) )
DEBUGLOG ( " lvs fclose failed: %s \n " , strerror ( errno ) ) ;
2005-02-07 17:45:38 +03:00
return NULL ;
2004-06-24 12:02:38 +04:00
}
2009-07-16 03:57:54 +04:00
static void lvm2_log_fn ( int level , const char * file , int line , int dm_errno ,
2006-10-05 17:55:50 +04:00
const char * message )
{
2007-08-24 12:29:39 +04:00
/* Send messages to the normal LVM2 logging system too,
2007-12-04 18:39:26 +03:00
so we get debug output when it ' s asked for .
2007-08-24 12:29:39 +04:00
We need to NULL the function ptr otherwise it will just call
back into here ! */
init_log_fn ( NULL ) ;
2009-07-16 03:57:54 +04:00
print_log ( level , file , line , dm_errno , " %s " , message ) ;
2007-08-24 12:29:39 +04:00
init_log_fn ( lvm2_log_fn ) ;
2006-10-05 17:55:50 +04:00
/*
2007-04-24 19:13:13 +04:00
* Ignore non - error messages , but store the latest one for returning
2006-10-05 17:55:50 +04:00
* to the user .
*/
if ( level ! = _LOG_ERR & & level ! = _LOG_FATAL )
return ;
2006-10-06 14:06:37 +04:00
strncpy ( last_error , message , sizeof ( last_error ) ) ;
last_error [ sizeof ( last_error ) - 1 ] = ' \0 ' ;
2006-10-05 17:55:50 +04:00
}
2005-02-02 14:42:29 +03:00
/* This checks some basic cluster-LVM configuration stuff */
static void check_config ( )
{
int locking_type ;
2006-05-16 20:48:31 +04:00
locking_type = find_config_tree_int ( cmd , " global/locking_type " , 1 ) ;
2005-02-02 14:42:29 +03:00
if ( locking_type = = 3 ) /* compiled-in cluster support */
return ;
if ( locking_type = = 2 ) { /* External library, check name */
2005-02-14 12:07:14 +03:00
const char * libname ;
2005-02-02 14:42:29 +03:00
2006-05-16 20:48:31 +04:00
libname = find_config_tree_str ( cmd , " global/locking_library " ,
2005-02-02 14:42:29 +03:00
" " ) ;
2005-02-14 12:07:14 +03:00
if ( strstr ( libname , " liblvm2clusterlock.so " ) )
2005-02-02 14:42:29 +03:00
return ;
log_error ( " Incorrect LVM locking library specified in lvm.conf, cluster operations may not work. " ) ;
return ;
}
log_error ( " locking_type not set correctly in lvm.conf, cluster operations will not work. " ) ;
}
2007-12-04 18:39:26 +03:00
/* Backups up the LVM metadata if it's changed */
2007-12-05 16:17:18 +03:00
void lvm_do_backup ( const char * vgname )
2007-12-04 18:39:26 +03:00
{
struct volume_group * vg ;
2009-11-23 13:44:50 +03:00
int consistent = 0 ;
2007-12-04 18:39:26 +03:00
2007-12-05 16:17:18 +03:00
DEBUGLOG ( " Triggering backup of VG metadata for %s. suspended=%d \n " , vgname , suspended ) ;
2007-12-04 18:39:26 +03:00
2009-03-05 19:25:35 +03:00
pthread_mutex_lock ( & lvm_lock ) ;
2009-11-23 13:44:50 +03:00
vg = vg_read_internal ( cmd , vgname , NULL /*vgid*/ , & consistent ) ;
2009-03-05 19:25:35 +03:00
2009-11-23 13:44:50 +03:00
if ( vg & & consistent )
2009-03-05 19:25:35 +03:00
check_current_backup ( vg ) ;
else
2007-12-04 18:39:26 +03:00
log_error ( " Error backing up metadata, can't find VG for group %s " , vgname ) ;
2009-03-05 19:25:35 +03:00
2009-04-10 14:00:04 +04:00
vg_release ( vg ) ;
2009-03-05 19:25:35 +03:00
dm_pool_empty ( cmd - > mem ) ;
pthread_mutex_unlock ( & lvm_lock ) ;
2007-12-04 18:39:26 +03:00
}
2004-06-24 12:02:38 +04:00
/* Called to initialise the LVM context of the daemon */
2005-03-07 20:03:44 +03:00
int init_lvm ( int using_gulm )
2004-06-24 12:02:38 +04:00
{
2009-02-23 00:14:37 +03:00
if ( ! ( cmd = create_toolcontext ( 1 , NULL ) ) ) {
2004-06-24 12:02:38 +04:00
log_error ( " Failed to allocate command context " ) ;
return 0 ;
}
2009-07-16 04:36:59 +04:00
if ( stored_errno ( ) ) {
destroy_toolcontext ( cmd ) ;
return 0 ;
}
2004-06-24 12:02:38 +04:00
/* Use LOG_DAEMON for syslog messages instead of LOG_USER */
init_syslog ( LOG_DAEMON ) ;
2007-08-24 12:29:39 +04:00
openlog ( " clvmd " , LOG_PID , LOG_DAEMON ) ;
2009-07-13 23:49:48 +04:00
cmd - > cmd_line = " clvmd " ;
2004-06-24 12:02:38 +04:00
2005-02-02 14:42:29 +03:00
/* Check lvm.conf is setup for cluster-LVM */
check_config ( ) ;
2010-01-19 16:25:00 +03:00
init_ignore_suspended_devices ( 1 ) ;
2005-02-02 14:42:29 +03:00
2005-03-07 20:03:44 +03:00
/* Remove any non-LV locks that may have been left around */
if ( using_gulm )
drop_vg_locks ( ) ;
2004-06-24 12:02:38 +04:00
get_initial_state ( ) ;
2006-10-05 17:55:50 +04:00
/* Trap log messages so we can pass them back to the user */
init_log_fn ( lvm2_log_fn ) ;
2004-06-24 12:02:38 +04:00
return 1 ;
}
2009-06-15 16:15:23 +04:00
void destroy_lvm ( void )
{
if ( cmd )
destroy_toolcontext ( cmd ) ;
cmd = NULL ;
}