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"
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-06 20:37:51 +04:00
# define LCK_MASK (LCK_TYPE_MASK | LCK_SCOPE_MASK)
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 ) {
case LCK_NULL :
type = " NULL " ;
break ;
case LCK_READ :
type = " READ " ;
break ;
case LCK_PREAD :
type = " PREAD " ;
break ;
case LCK_WRITE :
type = " WRITE " ;
break ;
case LCK_EXCL :
type = " EXCL " ;
break ;
case LCK_UNLOCK :
type = " UNLOCK " ;
break ;
default :
type = " unknown " ;
break ;
}
switch ( cmdl & LCK_SCOPE_MASK ) {
case LCK_VG :
scope = " VG " ;
break ;
case LCK_LV :
scope = " LV " ;
break ;
default :
scope = " unknown " ;
break ;
}
2008-06-06 20:37:51 +04:00
switch ( cmdl & LCK_MASK ) {
case LCK_LV_EXCLUSIVE & LCK_MASK :
2008-06-05 18:24:28 +04:00
command = " LCK_LV_EXCLUSIVE " ;
break ;
2008-06-06 20:37:51 +04:00
case LCK_LV_SUSPEND & LCK_MASK :
2008-06-05 18:24:28 +04:00
command = " LCK_LV_SUSPEND " ;
break ;
2008-06-06 20:37:51 +04:00
case LCK_LV_RESUME & LCK_MASK :
2008-06-05 18:24:28 +04:00
command = " LCK_LV_RESUME " ;
break ;
2008-06-06 20:37:51 +04:00
case LCK_LV_ACTIVATE & LCK_MASK :
2008-06-05 18:24:28 +04:00
command = " LCK_LV_ACTIVATE " ;
break ;
2008-06-06 20:37:51 +04:00
case LCK_LV_DEACTIVATE & LCK_MASK :
2008-06-05 18:24:28 +04:00
command = " LCK_LV_DEACTIVATE " ;
break ;
default :
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 ] ;
2008-09-19 19:44:03 +04:00
sprintf ( buf , " 0x%x (%s%s) " , flags ,
2008-06-05 18:24:28 +04:00
flags & LCK_MIRROR_NOSYNC_MODE ? " MIRROR_NOSYNC " : " " ,
flags & LCK_DMEVENTD_MONITOR_MODE ? " DMEVENTD_MONITOR " : " " ) ;
return buf ;
}
2006-10-05 17:55:50 +04:00
char * get_last_lvm_error ( )
{
return last_error ;
}
2004-06-24 12:02:38 +04:00
/* 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 ;
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 ) ;
2004-06-24 12:02:38 +04:00
if ( lvi ) {
return lvi - > lock_mode ;
} else {
return - 1 ;
}
}
/* Called at shutdown to tidy the lockspace */
void unlock_all ( )
{
2005-11-09 12:24:10 +03:00
struct dm_hash_node * v ;
2004-09-22 16:10:34 +04:00
pthread_mutex_lock ( & lv_hash_lock ) ;
2005-11-09 12:24:10 +03:00
dm_hash_iterate ( v , lv_hash ) {
struct lv_info * lvi = dm_hash_get_data ( lv_hash , v ) ;
2004-06-24 12:02:38 +04:00
2005-11-09 12:24:10 +03:00
sync_unlock ( dm_hash_get_key ( lv_hash , v ) , lvi - > lock_id ) ;
2004-06-24 12:02:38 +04:00
}
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 ;
flags & = LKF_NOQUEUE ; /* Only LKF_NOQUEUE is valid here */
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 ) ;
2004-06-24 12:02:38 +04:00
if ( lvi ) {
/* Already exists - convert it */
status =
sync_lock ( resource , mode , LKF_CONVERT | flags ,
& lvi - > lock_id ) ;
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 ;
status = sync_lock ( resource , mode , flags , & lvi - > lock_id ) ;
saved_errno = errno ;
if ( status ) {
free ( lvi ) ;
DEBUGLOG ( " hold_lock. lock at %d failed: %s \n " , mode ,
strerror ( errno ) ) ;
} else {
2004-09-22 16:10:34 +04:00
pthread_mutex_lock ( & lv_hash_lock ) ;
2005-11-09 12:24:10 +03:00
dm_hash_insert ( lv_hash , resource , lvi ) ;
2004-09-22 16:10:34 +04:00
pthread_mutex_unlock ( & lv_hash_lock ) ;
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 ;
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 ) ;
2004-06-24 12:02:38 +04:00
if ( ! lvi ) {
DEBUGLOG ( " hold_unlock, lock not already held \n " ) ;
return 0 ;
}
status = sync_unlock ( resource , lvi - > lock_id ) ;
saved_errno = errno ;
if ( ! status ) {
2004-09-22 16:10:34 +04:00
pthread_mutex_lock ( & lv_hash_lock ) ;
2005-11-09 12:24:10 +03:00
dm_hash_remove ( lv_hash , resource ) ;
2004-09-22 16:10:34 +04:00
pthread_mutex_unlock ( & lv_hash_lock ) ;
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 ) ;
if ( oldmode = = mode ) {
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
2005-08-16 12:25:09 +04:00
/* Try to get the lock if it's a clustered volume group */
if ( lock_flags & LCK_CLUSTER_VG ) {
status = hold_lock ( resource , mode , LKF_NOQUEUE ) ;
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 */
static int do_resume_lv ( char * resource )
{
int oldmode ;
/* Is it open ? */
oldmode = get_current_lock ( resource ) ;
if ( oldmode = = - 1 ) {
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 */
static int do_suspend_lv ( char * resource )
{
int oldmode ;
struct lvinfo lvi ;
/* Is it open ? */
oldmode = get_current_lock ( resource ) ;
if ( oldmode = = - 1 ) {
DEBUGLOG ( " do_suspend_lv, lock held at %d \n " , oldmode ) ;
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 ;
}
/* 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 ;
2008-06-05 18:24:28 +04:00
DEBUGLOG ( " do_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 ( ! 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
2004-06-24 12:02:38 +04:00
switch ( command ) {
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 ;
case LCK_LV_SUSPEND :
status = do_suspend_lv ( resource ) ;
2007-12-05 16:17:18 +03:00
if ( ! status )
suspended + + ;
2004-06-24 12:02:38 +04:00
break ;
case LCK_UNLOCK :
case LCK_LV_RESUME : /* if active */
status = do_resume_lv ( resource ) ;
2007-12-05 16:17:18 +03:00
if ( ! status )
suspended - - ;
2004-06-24 12:02:38 +04:00
break ;
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 ;
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
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
DEBUGLOG ( " Command return is %d \n " , status ) ;
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 .
*/
if ( command = = LCK_LV_SUSPEND ) {
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
if ( hold_lock ( resource , LKM_PWMODE , LKF_NOQUEUE ) )
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 */
if ( command = = LCK_LV_RESUME ) {
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 ) {
if ( hold_lock ( resource , LKM_CRMODE , 0 ) )
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 ( )
{
2007-08-23 16:19:13 +04:00
int ret ;
2006-10-04 12:22:16 +04:00
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 ) ;
2007-08-23 16:19:13 +04:00
ret = refresh_toolcontext ( cmd ) ;
init_full_scan_done ( 0 ) ;
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
return ret = = 1 ? 0 : - 1 ;
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
/*
* Drop lvmcache metadata
*/
void drop_metadata ( const char * vgname )
{
2008-06-05 18:24:28 +04:00
DEBUGLOG ( " Dropping metadata for VG %s \n " , vgname ) ;
2008-05-09 19:13:20 +04:00
pthread_mutex_lock ( & lvm_lock ) ;
lvmcache_drop_metadata ( vgname ) ;
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
}
2006-10-05 17:55:50 +04:00
static void lvm2_log_fn ( int level , const char * file , int line ,
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 ) ;
print_log ( level , file , line , " %s " , message ) ;
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. " ) ;
}
2004-06-24 12:02:38 +04:00
void init_lvhash ( )
{
/* Create hash table for keeping LV locks & status */
2005-11-09 12:24:10 +03:00
lv_hash = dm_hash_create ( 100 ) ;
2004-09-22 16:10:34 +04:00
pthread_mutex_init ( & lv_hash_lock , NULL ) ;
2007-04-24 19:13:13 +04:00
pthread_mutex_init ( & lvm_lock , NULL ) ;
2004-06-24 12:02:38 +04:00
}
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 ;
2007-12-05 16:17:18 +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-01-26 22:01:32 +03:00
vg = vg_read_internal ( cmd , vgname , NULL /*vgid*/ , & consistent ) ;
2009-03-05 19:25:35 +03:00
if ( vg & & consistent )
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 ;
}
/* 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 ) ;
2007-12-04 18:39:26 +03:00
cmd - > cmd_line = ( char * ) " 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 ( ) ;
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 ;
}