2015-03-05 23:00:44 +03:00
/*
2015-07-03 18:34:40 +03:00
* Copyright ( C ) 2014 - 2015 Red Hat , Inc .
2015-03-05 23:00:44 +03: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 Lesser General Public License v .2 .1 .
*/
# define _XOPEN_SOURCE 500 /* pthread */
# define _ISOC99_SOURCE
2018-05-14 12:30:20 +03:00
# include "tools/tool.h"
2015-03-05 23:00:44 +03:00
# include "daemon-server.h"
2018-05-14 12:30:20 +03:00
# include "lib/mm/xlate.h"
2015-03-05 23:00:44 +03:00
# include "lvmlockd-internal.h"
2018-05-14 12:30:20 +03:00
# include "daemons/lvmlockd/lvmlockd-client.h"
2015-03-05 23:00:44 +03:00
/*
* Using synchronous _wait dlm apis so do not define _REENTRANT and
* link with non - threaded version of library , libdlm_lt .
*/
# include "libdlm.h"
2019-03-20 21:20:26 +03:00
# include "libdlmcontrol.h"
2015-03-05 23:00:44 +03:00
2015-07-06 19:30:18 +03:00
# include <stddef.h>
# include <poll.h>
# include <errno.h>
# include <endian.h>
# include <fcntl.h>
# include <byteswap.h>
# include <syslog.h>
# include <dirent.h>
2015-03-05 23:00:44 +03:00
struct lm_dlm {
dlm_lshandle_t * dh ;
} ;
struct rd_dlm {
struct dlm_lksb lksb ;
struct val_blk * vb ;
} ;
int lm_data_size_dlm ( void )
{
return sizeof ( struct rd_dlm ) ;
}
/*
* lock_args format
*
* vg_lock_args format for dlm is
* vg_version_string : undefined : cluster_name
*
* lv_lock_args are not used for dlm
*
* version_string is MAJOR . MINOR . PATCH
* undefined may contain " : "
*/
# define VG_LOCK_ARGS_MAJOR 1
# define VG_LOCK_ARGS_MINOR 0
# define VG_LOCK_ARGS_PATCH 0
2015-08-26 00:10:12 +03:00
static int dlm_has_lvb_bug ;
2015-03-05 23:00:44 +03:00
static int cluster_name_from_args ( char * vg_args , char * clustername )
{
return last_string_from_args ( vg_args , clustername ) ;
}
static int check_args_version ( char * vg_args )
{
unsigned int major = 0 ;
int rv ;
rv = version_from_args ( vg_args , & major , NULL , NULL ) ;
if ( rv < 0 ) {
log_error ( " check_args_version %s error %d " , vg_args , rv ) ;
return rv ;
}
if ( major > VG_LOCK_ARGS_MAJOR ) {
log_error ( " check_args_version %s major %d %d " , vg_args , major , VG_LOCK_ARGS_MAJOR ) ;
return - 1 ;
}
return 0 ;
}
/* This will be set after dlm_controld is started. */
# define DLM_CLUSTER_NAME_PATH " / sys / kernel / config / dlm / cluster / cluster_name"
static int read_cluster_name ( char * clustername )
{
char * n ;
int fd ;
int rv ;
if ( daemon_test ) {
sprintf ( clustername , " %s " , " test " ) ;
return 0 ;
}
fd = open ( DLM_CLUSTER_NAME_PATH , O_RDONLY ) ;
if ( fd < 0 ) {
log_debug ( " read_cluster_name: open error %d, check dlm_controld " , fd ) ;
return fd ;
}
2015-07-09 19:28:59 +03:00
rv = read ( fd , clustername , MAX_ARGS ) ;
2015-03-05 23:00:44 +03:00
if ( rv < 0 ) {
log_error ( " read_cluster_name: cluster name read error %d, check dlm_controld " , fd ) ;
2024-05-04 13:25:36 +03:00
goto out ;
2015-03-05 23:00:44 +03:00
}
2021-09-21 19:13:05 +03:00
clustername [ rv ] = 0 ;
2015-03-05 23:00:44 +03:00
n = strstr ( clustername , " \n " ) ;
if ( n )
* n = ' \0 ' ;
2024-05-04 13:25:36 +03:00
rv = 0 ;
out :
2015-07-09 16:15:15 +03:00
if ( close ( fd ) )
2024-05-04 13:25:36 +03:00
log_error ( " read_cluster_name: close_error %d " , fd ) ;
return rv ;
2015-03-05 23:00:44 +03:00
}
2019-05-02 20:41:00 +03:00
# define MAX_VERSION 16
2015-03-05 23:00:44 +03:00
int lm_init_vg_dlm ( char * ls_name , char * vg_name , uint32_t flags , char * vg_args )
{
2015-07-09 19:28:59 +03:00
char clustername [ MAX_ARGS + 1 ] ;
2019-05-02 20:41:00 +03:00
char lock_args_version [ MAX_VERSION + 1 ] ;
2015-03-05 23:00:44 +03:00
int rv ;
memset ( clustername , 0 , sizeof ( clustername ) ) ;
memset ( lock_args_version , 0 , sizeof ( lock_args_version ) ) ;
2019-05-02 20:41:00 +03:00
snprintf ( lock_args_version , MAX_VERSION , " %u.%u.%u " ,
2015-03-05 23:00:44 +03:00
VG_LOCK_ARGS_MAJOR , VG_LOCK_ARGS_MINOR , VG_LOCK_ARGS_PATCH ) ;
rv = read_cluster_name ( clustername ) ;
if ( rv < 0 )
return - EMANAGER ;
if ( strlen ( clustername ) + strlen ( lock_args_version ) + 2 > MAX_ARGS ) {
log_error ( " init_vg_dlm args too long " ) ;
return - EARGS ;
}
2019-05-02 20:41:00 +03:00
rv = snprintf ( vg_args , MAX_ARGS , " %s:%s " , lock_args_version , clustername ) ;
if ( rv > = MAX_ARGS )
log_debug ( " init_vg_dlm vg_args may be too long %d %s " , rv , vg_args ) ;
2015-03-05 23:00:44 +03:00
rv = 0 ;
log_debug ( " init_vg_dlm done %s vg_args %s " , ls_name , vg_args ) ;
return rv ;
}
int lm_prepare_lockspace_dlm ( struct lockspace * ls )
{
2015-07-09 19:28:59 +03:00
char sys_clustername [ MAX_ARGS + 1 ] ;
char arg_clustername [ MAX_ARGS + 1 ] ;
2015-08-26 00:10:12 +03:00
uint32_t major = 0 , minor = 0 , patch = 0 ;
2015-03-05 23:00:44 +03:00
struct lm_dlm * lmd ;
int rv ;
2016-01-15 00:57:09 +03:00
if ( daemon_test )
goto skip_args ;
2015-03-05 23:00:44 +03:00
memset ( sys_clustername , 0 , sizeof ( sys_clustername ) ) ;
memset ( arg_clustername , 0 , sizeof ( arg_clustername ) ) ;
rv = read_cluster_name ( sys_clustername ) ;
if ( rv < 0 )
return - EMANAGER ;
2015-08-26 00:10:12 +03:00
rv = dlm_kernel_version ( & major , & minor , & patch ) ;
if ( rv < 0 ) {
log_error ( " prepare_lockspace_dlm kernel_version not detected %d " , rv ) ;
dlm_has_lvb_bug = 1 ;
}
if ( ( major = = 6 ) & & ( minor = = 0 ) & & ( patch = = 1 ) ) {
log_debug ( " dlm kernel version %u.%u.%u has lvb bug " , major , minor , patch ) ;
dlm_has_lvb_bug = 1 ;
}
2015-03-05 23:00:44 +03:00
if ( ! ls - > vg_args [ 0 ] ) {
/* global lockspace has no vg args */
goto skip_args ;
}
rv = check_args_version ( ls - > vg_args ) ;
if ( rv < 0 )
return - EARGS ;
rv = cluster_name_from_args ( ls - > vg_args , arg_clustername ) ;
if ( rv < 0 ) {
log_error ( " prepare_lockspace_dlm %s no cluster name from args %s " , ls - > name , ls - > vg_args ) ;
return - EARGS ;
}
if ( strcmp ( sys_clustername , arg_clustername ) ) {
log_error ( " prepare_lockspace_dlm %s mismatching cluster names sys %s arg %s " ,
ls - > name , sys_clustername , arg_clustername ) ;
return - EARGS ;
}
skip_args :
lmd = malloc ( sizeof ( struct lm_dlm ) ) ;
if ( ! lmd )
return - ENOMEM ;
ls - > lm_data = lmd ;
return 0 ;
}
2022-09-30 11:34:51 +03:00
# define DLM_COMMS_PATH " / sys / kernel / config / dlm / cluster / comms"
# define LOCK_LINE_MAX 1024
2022-10-11 20:35:38 +03:00
static int get_local_nodeid ( void )
2022-09-30 11:34:51 +03:00
{
struct dirent * de ;
DIR * ls_dir ;
2023-08-31 19:47:42 +03:00
char ls_comms_path [ PATH_MAX ] = { 0 } ;
char path [ PATH_MAX ] = { 0 } ;
2023-03-08 20:11:32 +03:00
FILE * file ;
2022-09-30 11:34:51 +03:00
char line [ LOCK_LINE_MAX ] ;
2023-03-08 20:11:32 +03:00
char * str1 , * str2 ;
2022-09-30 11:34:51 +03:00
int rv = - 1 , val ;
2023-08-31 19:47:42 +03:00
snprintf ( ls_comms_path , sizeof ( ls_comms_path ) , " %s " , DLM_COMMS_PATH ) ;
2022-09-30 11:34:51 +03:00
if ( ! ( ls_dir = opendir ( ls_comms_path ) ) )
return - ECONNREFUSED ;
while ( ( de = readdir ( ls_dir ) ) ) {
if ( de - > d_name [ 0 ] = = ' . ' )
continue ;
2023-08-31 19:47:42 +03:00
snprintf ( path , sizeof ( path ) , " %s/%s/local " ,
DLM_COMMS_PATH , de - > d_name ) ;
2023-03-08 20:11:32 +03:00
if ( ! ( file = fopen ( ls_comms_path , " r " ) ) )
2022-09-30 11:34:51 +03:00
continue ;
2023-08-31 19:47:42 +03:00
str1 = fgets ( line , sizeof ( line ) , file ) ;
if ( fclose ( file ) )
log_sys_debug ( " fclose " , path ) ;
2023-03-08 20:11:32 +03:00
if ( str1 ) {
2022-09-30 11:34:51 +03:00
rv = sscanf ( line , " %d " , & val ) ;
if ( ( rv = = 1 ) & & ( val = = 1 ) ) {
2023-08-31 19:47:42 +03:00
snprintf ( path , sizeof ( path ) , " %s/%s/nodeid " ,
DLM_COMMS_PATH , de - > d_name ) ;
2023-03-08 20:11:32 +03:00
2023-08-31 19:47:42 +03:00
if ( ! ( file = fopen ( path , " r " ) ) )
2022-09-30 11:34:51 +03:00
continue ;
2023-08-31 19:47:42 +03:00
str2 = fgets ( line , sizeof ( line ) , file ) ;
if ( fclose ( file ) )
log_sys_debug ( " fclose " , path ) ;
2023-03-08 20:11:32 +03:00
if ( str2 ) {
2022-09-30 11:34:51 +03:00
rv = sscanf ( line , " %d " , & val ) ;
if ( rv = = 1 ) {
2023-08-31 19:47:42 +03:00
if ( closedir ( ls_dir ) )
log_sys_debug ( " closedir " , ls_comms_path ) ;
2022-09-30 11:34:51 +03:00
return val ;
}
}
}
}
}
if ( closedir ( ls_dir ) )
2023-08-31 19:47:42 +03:00
log_sys_debug ( " closedir " , ls_comms_path ) ;
2022-12-01 18:53:57 +03:00
return rv ;
2022-09-30 11:34:51 +03:00
}
int lm_purge_locks_dlm ( struct lockspace * ls )
{
struct lm_dlm * lmd = ( struct lm_dlm * ) ls - > lm_data ;
int nodeid ;
int rv = - 1 ;
if ( ! lmd | | ! lmd - > dh ) {
log_error ( " purge_locks_dlm %s no dlm_handle_t error " , ls - > name ) ;
goto fail ;
}
nodeid = get_local_nodeid ( ) ;
if ( nodeid < 0 ) {
log_error ( " failed to get local nodeid " ) ;
goto fail ;
}
if ( dlm_ls_purge ( lmd - > dh , nodeid , 0 ) ) {
log_error ( " purge_locks_dlm %s error " , ls - > name ) ;
goto fail ;
}
rv = 0 ;
fail :
return rv ;
}
2024-06-18 21:26:09 +03:00
int lm_add_lockspace_dlm ( struct lockspace * ls , int adopt_only , int adopt_ok )
2015-03-05 23:00:44 +03:00
{
struct lm_dlm * lmd = ( struct lm_dlm * ) ls - > lm_data ;
if ( daemon_test )
return 0 ;
2024-06-18 21:26:09 +03:00
if ( adopt_only | | adopt_ok ) {
2015-03-05 23:00:44 +03:00
lmd - > dh = dlm_open_lockspace ( ls - > name ) ;
2024-06-18 21:26:09 +03:00
if ( ! lmd - > dh & & adopt_ok )
lmd - > dh = dlm_new_lockspace ( ls - > name , 0600 , DLM_LSFL_NEWEXCL ) ;
if ( ! lmd - > dh )
log_error ( " add_lockspace_dlm adopt_only %d adopt_ok %d %s error " ,
adopt_only , adopt_ok , ls - > name ) ;
} else {
2015-03-05 23:00:44 +03:00
lmd - > dh = dlm_new_lockspace ( ls - > name , 0600 , DLM_LSFL_NEWEXCL ) ;
2024-06-18 21:26:09 +03:00
if ( ! lmd - > dh )
log_error ( " add_lockspace_dlm %s error " , ls - > name ) ;
}
2015-03-05 23:00:44 +03:00
if ( ! lmd - > dh ) {
free ( lmd ) ;
ls - > lm_data = NULL ;
return - 1 ;
}
return 0 ;
}
int lm_rem_lockspace_dlm ( struct lockspace * ls , int free_vg )
{
struct lm_dlm * lmd = ( struct lm_dlm * ) ls - > lm_data ;
int rv ;
if ( daemon_test )
goto out ;
/*
* If free_vg is set , it means we are doing vgremove , and we may want
* to tell any other nodes to leave the lockspace . This is not really
* necessary since there should be no harm in having an unused
* lockspace sitting around . A new " notification lock " would need to
* be added with a callback to signal this .
*/
rv = dlm_release_lockspace ( ls - > name , lmd - > dh , 1 ) ;
if ( rv < 0 ) {
log_error ( " rem_lockspace_dlm error %d " , rv ) ;
return rv ;
}
out :
free ( lmd ) ;
ls - > lm_data = NULL ;
return 0 ;
}
static int lm_add_resource_dlm ( struct lockspace * ls , struct resource * r , int with_lock_nl )
{
struct lm_dlm * lmd = ( struct lm_dlm * ) ls - > lm_data ;
struct rd_dlm * rdd = ( struct rd_dlm * ) r - > lm_data ;
uint32_t flags = 0 ;
char * buf ;
int rv ;
if ( r - > type = = LD_RT_GL | | r - > type = = LD_RT_VG ) {
2018-12-23 01:33:23 +03:00
buf = zalloc ( sizeof ( struct val_blk ) + DLM_LVB_LEN ) ;
2015-03-05 23:00:44 +03:00
if ( ! buf )
return - ENOMEM ;
rdd - > vb = ( struct val_blk * ) buf ;
rdd - > lksb . sb_lvbptr = buf + sizeof ( struct val_blk ) ;
flags | = LKF_VALBLK ;
}
if ( ! with_lock_nl )
goto out ;
/* because this is a new NL lock request */
flags | = LKF_EXPEDITE ;
if ( daemon_test )
goto out ;
rv = dlm_ls_lock_wait ( lmd - > dh , LKM_NLMODE , & rdd - > lksb , flags ,
r - > name , strlen ( r - > name ) ,
0 , NULL , NULL , NULL ) ;
if ( rv < 0 ) {
2024-06-14 20:37:02 +03:00
log_error ( " %s:%s add_resource_dlm lock error %d " , ls - > name , r - > name , rv ) ;
2015-03-05 23:00:44 +03:00
return rv ;
}
out :
return 0 ;
}
int lm_rem_resource_dlm ( struct lockspace * ls , struct resource * r )
{
struct lm_dlm * lmd = ( struct lm_dlm * ) ls - > lm_data ;
struct rd_dlm * rdd = ( struct rd_dlm * ) r - > lm_data ;
struct dlm_lksb * lksb ;
int rv = 0 ;
if ( daemon_test )
goto out ;
lksb = & rdd - > lksb ;
if ( ! lksb - > sb_lkid )
goto out ;
rv = dlm_ls_unlock_wait ( lmd - > dh , lksb - > sb_lkid , 0 , lksb ) ;
if ( rv < 0 ) {
2024-06-14 20:37:02 +03:00
log_error ( " %s:%s rem_resource_dlm unlock error %d " , ls - > name , r - > name , rv ) ;
2015-03-05 23:00:44 +03:00
}
out :
2021-02-27 16:14:25 +03:00
free ( rdd - > vb ) ;
2015-03-05 23:00:44 +03:00
memset ( rdd , 0 , sizeof ( struct rd_dlm ) ) ;
r - > lm_init = 0 ;
return rv ;
}
static int to_dlm_mode ( int ld_mode )
{
switch ( ld_mode ) {
case LD_LK_EX :
return LKM_EXMODE ;
case LD_LK_SH :
return LKM_PRMODE ;
} ;
return - 1 ;
}
static int lm_adopt_dlm ( struct lockspace * ls , struct resource * r , int ld_mode ,
2015-09-09 22:40:48 +03:00
struct val_blk * vb_out )
2015-03-05 23:00:44 +03:00
{
struct lm_dlm * lmd = ( struct lm_dlm * ) ls - > lm_data ;
struct rd_dlm * rdd = ( struct rd_dlm * ) r - > lm_data ;
struct dlm_lksb * lksb ;
uint32_t flags = 0 ;
int mode ;
int rv ;
2015-09-09 22:40:48 +03:00
memset ( vb_out , 0 , sizeof ( struct val_blk ) ) ;
2015-03-05 23:00:44 +03:00
if ( ! r - > lm_init ) {
rv = lm_add_resource_dlm ( ls , r , 0 ) ;
if ( rv < 0 )
return rv ;
r - > lm_init = 1 ;
}
lksb = & rdd - > lksb ;
flags | = LKF_PERSISTENT ;
flags | = LKF_ORPHAN ;
if ( rdd - > vb )
flags | = LKF_VALBLK ;
mode = to_dlm_mode ( ld_mode ) ;
if ( mode < 0 ) {
log_error ( " adopt_dlm invalid mode %d " , ld_mode ) ;
rv = - EINVAL ;
goto fail ;
}
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s adopt_dlm " , ls - > name , r - > name ) ;
2015-03-05 23:00:44 +03:00
if ( daemon_test )
return 0 ;
/*
* dlm returns 0 for success , - EAGAIN if an orphan is
* found with another mode , and - ENOENT if no orphan .
*
2024-05-07 14:38:10 +03:00
* cast / bast / param are ( void ( * ) ( void * ) ) 1 because the kernel
2015-03-05 23:00:44 +03:00
* returns errors if some are null .
*/
rv = dlm_ls_lockx ( lmd - > dh , mode , lksb , flags ,
r - > name , strlen ( r - > name ) , 0 ,
2024-05-07 14:38:10 +03:00
( void ( * ) ( void * ) ) 1 , ( void ( * ) ( void * ) ) 1 , ( void ( * ) ( void * ) ) 1 ,
2015-03-05 23:00:44 +03:00
NULL , NULL ) ;
2020-05-04 21:35:03 +03:00
if ( rv = = - 1 & & ( errno = = EAGAIN ) ) {
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s adopt_dlm adopt mode %d try other mode " ,
2015-03-05 23:00:44 +03:00
ls - > name , r - > name , ld_mode ) ;
2024-06-18 21:26:09 +03:00
rv = - EADOPT_RETRY ;
2015-03-05 23:00:44 +03:00
goto fail ;
}
2020-05-04 21:35:03 +03:00
if ( rv = = - 1 & & ( errno = = ENOENT ) ) {
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s adopt_dlm adopt mode %d no lock " ,
2020-05-04 21:35:03 +03:00
ls - > name , r - > name , ld_mode ) ;
2024-06-18 21:26:09 +03:00
rv = - EADOPT_NONE ;
2020-05-04 21:35:03 +03:00
goto fail ;
}
2015-03-05 23:00:44 +03:00
if ( rv < 0 ) {
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s adopt_dlm mode %d flags %x error %d errno %d " ,
2015-03-05 23:00:44 +03:00
ls - > name , r - > name , mode , flags , rv , errno ) ;
goto fail ;
}
/*
* FIXME : For GL / VG locks we probably want to read the lvb ,
* especially if adopting an ex lock , because when we
* release this adopted ex lock we may want to write new
* lvb values based on the current lvb values ( at lease
* in the GL case where we increment the current values . )
*
* It should be possible to read the lvb by requesting
* this lock in the same mode it ' s already in .
*/
return rv ;
fail :
lm_rem_resource_dlm ( ls , r ) ;
return rv ;
}
/*
* Use PERSISTENT so that if lvmlockd exits while holding locks ,
* the locks will remain orphaned in the dlm , still protecting what
* they were acquired to protect .
*/
int lm_lock_dlm ( struct lockspace * ls , struct resource * r , int ld_mode ,
2024-06-18 21:26:09 +03:00
struct val_blk * vb_out , int adopt_only , int adopt_ok )
2015-03-05 23:00:44 +03:00
{
struct lm_dlm * lmd = ( struct lm_dlm * ) ls - > lm_data ;
struct rd_dlm * rdd = ( struct rd_dlm * ) r - > lm_data ;
struct dlm_lksb * lksb ;
struct val_blk vb ;
uint32_t flags = 0 ;
int mode ;
int rv ;
2024-06-18 21:26:09 +03:00
if ( adopt_ok ) {
log_debug ( " %s:%s lock_dlm adopt_ok not supported " , ls - > name , r - > name ) ;
return - 1 ;
}
if ( adopt_only ) {
log_debug ( " %s:%s lock_dlm adopt_only " , ls - > name , r - > name ) ;
2015-03-05 23:00:44 +03:00
/* When adopting, we don't follow the normal method
of acquiring a NL lock then converting it to the
desired mode . */
2015-09-09 22:40:48 +03:00
return lm_adopt_dlm ( ls , r , ld_mode , vb_out ) ;
2015-03-05 23:00:44 +03:00
}
if ( ! r - > lm_init ) {
rv = lm_add_resource_dlm ( ls , r , 1 ) ;
if ( rv < 0 )
return rv ;
r - > lm_init = 1 ;
}
lksb = & rdd - > lksb ;
flags | = LKF_CONVERT ;
flags | = LKF_NOQUEUE ;
flags | = LKF_PERSISTENT ;
if ( rdd - > vb )
flags | = LKF_VALBLK ;
mode = to_dlm_mode ( ld_mode ) ;
if ( mode < 0 ) {
log_error ( " lock_dlm invalid mode %d " , ld_mode ) ;
return - EINVAL ;
}
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s lock_dlm " , ls - > name , r - > name ) ;
2015-03-05 23:00:44 +03:00
if ( daemon_test ) {
2016-01-15 00:57:09 +03:00
if ( rdd - > vb ) {
vb_out - > version = le16_to_cpu ( rdd - > vb - > version ) ;
vb_out - > flags = le16_to_cpu ( rdd - > vb - > flags ) ;
vb_out - > r_version = le32_to_cpu ( rdd - > vb - > r_version ) ;
}
2015-03-05 23:00:44 +03:00
return 0 ;
}
2015-08-26 00:10:12 +03:00
/*
* The dlm lvb bug means that converting NL - > EX will not return
* the latest lvb , so we have to convert NL - > PR - > EX to reread it .
*/
if ( dlm_has_lvb_bug & & ( ld_mode = = LD_LK_EX ) ) {
rv = dlm_ls_lock_wait ( lmd - > dh , LKM_PRMODE , lksb , flags ,
r - > name , strlen ( r - > name ) ,
0 , NULL , NULL , NULL ) ;
if ( rv = = - 1 ) {
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s lock_dlm acquire mode PR for %d rv %d " ,
2015-08-26 00:10:12 +03:00
ls - > name , r - > name , mode , rv ) ;
goto lockrv ;
}
/* Fall through to request EX. */
}
2015-03-05 23:00:44 +03:00
rv = dlm_ls_lock_wait ( lmd - > dh , mode , lksb , flags ,
r - > name , strlen ( r - > name ) ,
0 , NULL , NULL , NULL ) ;
2015-08-26 00:10:12 +03:00
lockrv :
2015-08-24 23:54:25 +03:00
if ( rv = = - 1 & & errno = = EAGAIN ) {
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s lock_dlm acquire mode %d rv EAGAIN " , ls - > name , r - > name , mode ) ;
2015-03-05 23:00:44 +03:00
return - EAGAIN ;
}
if ( rv < 0 ) {
2024-06-14 20:37:02 +03:00
log_error ( " %s:%s lock_dlm acquire error %d errno %d " , ls - > name , r - > name , rv , errno ) ;
2017-11-16 01:00:41 +03:00
return - ELMERR ;
2015-03-05 23:00:44 +03:00
}
if ( rdd - > vb ) {
if ( lksb - > sb_flags & DLM_SBF_VALNOTVALID ) {
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s lock_dlm VALNOTVALID " , ls - > name , r - > name ) ;
2015-03-05 23:00:44 +03:00
memset ( rdd - > vb , 0 , sizeof ( struct val_blk ) ) ;
2015-09-09 22:40:48 +03:00
memset ( vb_out , 0 , sizeof ( struct val_blk ) ) ;
2015-03-05 23:00:44 +03:00
goto out ;
}
2015-09-09 22:40:48 +03:00
/*
* ' vb ' contains disk endian values , not host endian .
* It is copied directly to rdd - > vb which is also kept
* in disk endian form .
* vb_out is returned to the caller in host endian form .
*/
2015-03-05 23:00:44 +03:00
memcpy ( & vb , lksb - > sb_lvbptr , sizeof ( struct val_blk ) ) ;
2015-09-09 22:40:48 +03:00
memcpy ( rdd - > vb , & vb , sizeof ( vb ) ) ;
2015-03-05 23:00:44 +03:00
2015-09-09 22:40:48 +03:00
vb_out - > version = le16_to_cpu ( vb . version ) ;
vb_out - > flags = le16_to_cpu ( vb . flags ) ;
vb_out - > r_version = le32_to_cpu ( vb . r_version ) ;
2015-03-05 23:00:44 +03:00
}
out :
return 0 ;
}
int lm_convert_dlm ( struct lockspace * ls , struct resource * r ,
int ld_mode , uint32_t r_version )
{
struct lm_dlm * lmd = ( struct lm_dlm * ) ls - > lm_data ;
struct rd_dlm * rdd = ( struct rd_dlm * ) r - > lm_data ;
struct dlm_lksb * lksb = & rdd - > lksb ;
2024-03-25 16:33:40 +03:00
int mode ;
2015-03-05 23:00:44 +03:00
uint32_t flags = 0 ;
int rv ;
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s convert_dlm " , ls - > name , r - > name ) ;
2015-03-05 23:00:44 +03:00
flags | = LKF_CONVERT ;
flags | = LKF_NOQUEUE ;
flags | = LKF_PERSISTENT ;
if ( rdd - > vb & & r_version & & ( r - > mode = = LD_LK_EX ) ) {
if ( ! rdd - > vb - > version ) {
/* first time vb has been written */
rdd - > vb - > version = cpu_to_le16 ( VAL_BLK_VERSION ) ;
}
rdd - > vb - > r_version = cpu_to_le32 ( r_version ) ;
memcpy ( lksb - > sb_lvbptr , rdd - > vb , sizeof ( struct val_blk ) ) ;
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s convert_dlm set r_version %u " ,
2015-03-05 23:00:44 +03:00
ls - > name , r - > name , r_version ) ;
flags | = LKF_VALBLK ;
}
2024-03-25 16:33:40 +03:00
if ( ( mode = to_dlm_mode ( ld_mode ) ) < 0 ) {
log_error ( " lm_convert_dlm invalid mode %d " , ld_mode ) ;
return - EINVAL ;
}
2015-03-05 23:00:44 +03:00
if ( daemon_test )
return 0 ;
rv = dlm_ls_lock_wait ( lmd - > dh , mode , lksb , flags ,
r - > name , strlen ( r - > name ) ,
0 , NULL , NULL , NULL ) ;
2015-08-24 23:54:25 +03:00
if ( rv = = - 1 & & errno = = EAGAIN ) {
2015-03-05 23:00:44 +03:00
/* FIXME: When does this happen? Should something different be done? */
2024-06-14 20:37:02 +03:00
log_error ( " %s:%s convert_dlm mode %d rv EAGAIN " , ls - > name , r - > name , mode ) ;
2015-03-05 23:00:44 +03:00
return - EAGAIN ;
}
if ( rv < 0 ) {
2024-06-14 20:37:02 +03:00
log_error ( " %s:%s convert_dlm error %d " , ls - > name , r - > name , rv ) ;
2017-11-16 01:00:41 +03:00
rv = - ELMERR ;
2015-03-05 23:00:44 +03:00
}
return rv ;
}
int lm_unlock_dlm ( struct lockspace * ls , struct resource * r ,
2015-08-26 18:01:05 +03:00
uint32_t r_version , uint32_t lmu_flags )
2015-03-05 23:00:44 +03:00
{
struct lm_dlm * lmd = ( struct lm_dlm * ) ls - > lm_data ;
struct rd_dlm * rdd = ( struct rd_dlm * ) r - > lm_data ;
struct dlm_lksb * lksb = & rdd - > lksb ;
2015-09-09 22:40:48 +03:00
struct val_blk vb_prev ;
struct val_blk vb_next ;
2015-03-05 23:00:44 +03:00
uint32_t flags = 0 ;
2015-09-09 22:40:48 +03:00
int new_vb = 0 ;
2015-03-05 23:00:44 +03:00
int rv ;
/*
* Do not set PERSISTENT , because we don ' t need an orphan
* NL lock to protect anything .
*/
flags | = LKF_CONVERT ;
2015-08-26 18:01:05 +03:00
if ( rdd - > vb & & ( r - > mode = = LD_LK_EX ) ) {
2015-09-09 22:40:48 +03:00
/* vb_prev and vb_next are in disk endian form */
memcpy ( & vb_prev , rdd - > vb , sizeof ( struct val_blk ) ) ;
memcpy ( & vb_next , rdd - > vb , sizeof ( struct val_blk ) ) ;
if ( ! vb_prev . version ) {
vb_next . version = cpu_to_le16 ( VAL_BLK_VERSION ) ;
new_vb = 1 ;
2015-03-05 23:00:44 +03:00
}
2015-08-26 18:01:05 +03:00
2015-09-09 22:40:48 +03:00
if ( ( lmu_flags & LMUF_FREE_VG ) & & ( r - > type = = LD_RT_VG ) ) {
vb_next . flags = cpu_to_le16 ( VBF_REMOVED ) ;
new_vb = 1 ;
}
2015-08-26 18:01:05 +03:00
2015-09-09 22:40:48 +03:00
if ( r_version ) {
vb_next . r_version = cpu_to_le32 ( r_version ) ;
new_vb = 1 ;
}
2015-03-05 23:00:44 +03:00
2015-09-09 22:40:48 +03:00
if ( new_vb ) {
memcpy ( rdd - > vb , & vb_next , sizeof ( struct val_blk ) ) ;
memcpy ( lksb - > sb_lvbptr , & vb_next , sizeof ( struct val_blk ) ) ;
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s unlock_dlm vb old %x %x %u new %x %x %u " ,
2015-09-09 22:40:48 +03:00
ls - > name , r - > name ,
le16_to_cpu ( vb_prev . version ) ,
le16_to_cpu ( vb_prev . flags ) ,
le32_to_cpu ( vb_prev . r_version ) ,
le16_to_cpu ( vb_next . version ) ,
le16_to_cpu ( vb_next . flags ) ,
le32_to_cpu ( vb_next . r_version ) ) ;
} else {
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s unlock_dlm vb unchanged " , ls - > name , r - > name ) ;
2015-09-09 22:40:48 +03:00
}
2015-03-05 23:00:44 +03:00
flags | = LKF_VALBLK ;
2015-09-09 22:40:48 +03:00
} else {
2024-06-14 20:37:02 +03:00
log_debug ( " %s:%s unlock_dlm " , ls - > name , r - > name ) ;
2015-03-05 23:00:44 +03:00
}
if ( daemon_test )
return 0 ;
rv = dlm_ls_lock_wait ( lmd - > dh , LKM_NLMODE , lksb , flags ,
r - > name , strlen ( r - > name ) ,
0 , NULL , NULL , NULL ) ;
if ( rv < 0 ) {
2024-06-14 20:37:02 +03:00
log_error ( " %s:%s unlock_dlm error %d " , ls - > name , r - > name , rv ) ;
2017-11-16 01:00:41 +03:00
rv = - ELMERR ;
2015-03-05 23:00:44 +03:00
}
return rv ;
}
/*
* This list could be read from dlm_controld via libdlmcontrol ,
* but it ' s simpler to get it from sysfs .
*/
# define DLM_LOCKSPACES_PATH " / sys / kernel / config / dlm / cluster / spaces"
2015-09-11 22:06:46 +03:00
/*
* FIXME : this should be implemented differently .
* It ' s not nice to use an aspect of the dlm clustering
* implementation , which could change . It would be
* better to do something like use a special lock in the
* lockspace that was held PR by all nodes , and then an
* EX request on it could check if it ' s started ( and
* possibly also notify others to stop it automatically ) .
* Or , possibly an enhancement to libdlm that would give
* info about lockspace members .
*
* ( We could let the VG be removed while others still
* have the lockspace running , which largely works , but
* introduces problems if another VG with the same name is
* recreated while others still have the lockspace running
* for the previous VG . We ' d also want a way to clean up
* the stale lockspaces on the others eventually . )
*/
int lm_hosts_dlm ( struct lockspace * ls , int notify )
{
char ls_nodes_path [ PATH_MAX ] ;
struct dirent * de ;
DIR * ls_dir ;
int count = 0 ;
2016-01-15 00:57:09 +03:00
if ( daemon_test )
return 0 ;
2015-09-11 22:06:46 +03:00
memset ( ls_nodes_path , 0 , sizeof ( ls_nodes_path ) ) ;
2018-02-12 23:50:07 +03:00
snprintf ( ls_nodes_path , PATH_MAX , " %s/%s/nodes " ,
2015-09-11 22:06:46 +03:00
DLM_LOCKSPACES_PATH , ls - > name ) ;
if ( ! ( ls_dir = opendir ( ls_nodes_path ) ) )
return - ECONNREFUSED ;
while ( ( de = readdir ( ls_dir ) ) ) {
if ( de - > d_name [ 0 ] = = ' . ' )
continue ;
count + + ;
}
if ( closedir ( ls_dir ) )
2024-05-04 13:25:36 +03:00
log_error ( " lm_hosts_dlm: closedir failed " ) ;
2015-09-11 22:06:46 +03:00
if ( ! count ) {
log_error ( " lm_hosts_dlm found no nodes in %s " , ls_nodes_path ) ;
return 0 ;
}
/*
* Assume that a count of one node represents ourself ,
* and any value over one represents other nodes .
*/
return count - 1 ;
}
2015-03-05 23:00:44 +03:00
int lm_get_lockspaces_dlm ( struct list_head * ls_rejoin )
{
struct lockspace * ls ;
struct dirent * de ;
DIR * ls_dir ;
2024-05-04 13:25:36 +03:00
int ret = 0 ;
2015-03-05 23:00:44 +03:00
if ( ! ( ls_dir = opendir ( DLM_LOCKSPACES_PATH ) ) )
return - ECONNREFUSED ;
while ( ( de = readdir ( ls_dir ) ) ) {
if ( de - > d_name [ 0 ] = = ' . ' )
continue ;
if ( strncmp ( de - > d_name , LVM_LS_PREFIX , strlen ( LVM_LS_PREFIX ) ) )
continue ;
if ( ! ( ls = alloc_lockspace ( ) ) ) {
2024-05-04 13:25:36 +03:00
ret = - ENOMEM ;
goto out ;
2015-03-05 23:00:44 +03:00
}
ls - > lm_type = LD_LM_DLM ;
2024-04-03 22:01:40 +03:00
dm_strncpy ( ls - > name , de - > d_name , sizeof ( ls - > name ) ) ;
dm_strncpy ( ls - > vg_name , ls - > name + strlen ( LVM_LS_PREFIX ) , sizeof ( ls - > vg_name ) ) ;
2015-03-05 23:00:44 +03:00
list_add_tail ( & ls - > list , ls_rejoin ) ;
}
2024-05-04 13:25:36 +03:00
out :
2015-08-04 10:49:23 +03:00
if ( closedir ( ls_dir ) )
2024-05-04 13:25:36 +03:00
log_error ( " lm_get_lockspace_dlm: closedir failed " ) ;
return ret ;
2015-03-05 23:00:44 +03:00
}
int lm_is_running_dlm ( void )
{
2015-07-09 19:28:59 +03:00
char sys_clustername [ MAX_ARGS + 1 ] ;
2015-03-05 23:00:44 +03:00
int rv ;
2016-01-15 00:57:09 +03:00
if ( daemon_test )
return gl_use_dlm ;
2015-03-05 23:00:44 +03:00
memset ( sys_clustername , 0 , sizeof ( sys_clustername ) ) ;
rv = read_cluster_name ( sys_clustername ) ;
if ( rv < 0 )
return 0 ;
return 1 ;
}
2015-09-09 22:40:48 +03:00
2019-03-20 21:20:26 +03:00
# ifdef LOCKDDLM_CONTROL_SUPPORT
int lm_refresh_lv_start_dlm ( struct action * act )
{
2021-08-02 23:49:39 +03:00
char path [ PATH_MAX ] = { 0 } ;
2019-03-20 21:20:26 +03:00
char command [ DLMC_RUN_COMMAND_LEN ] ;
char run_uuid [ DLMC_RUN_UUID_LEN ] ;
2019-03-22 22:28:02 +03:00
char * p , * vgname , * lvname ;
2019-03-20 21:20:26 +03:00
int rv ;
2019-03-22 22:28:02 +03:00
/* split /dev/vgname/lvname into vgname and lvname strings */
2024-04-03 22:01:40 +03:00
dm_strncpy ( path , act - > path , sizeof ( path ) ) ;
2019-03-22 22:28:02 +03:00
/* skip past dev */
2021-09-21 19:24:30 +03:00
if ( ! ( p = strchr ( path + 1 , ' / ' ) ) )
return - EINVAL ;
2019-03-22 22:28:02 +03:00
/* skip past slashes */
while ( * p = = ' / ' )
p + + ;
/* start of vgname */
vgname = p ;
/* skip past vgname */
while ( * p ! = ' / ' )
p + + ;
/* terminate vgname */
* p = ' \0 ' ;
p + + ;
/* skip past slashes */
while ( * p = = ' / ' )
p + + ;
lvname = p ;
2019-03-20 21:20:26 +03:00
memset ( command , 0 , sizeof ( command ) ) ;
memset ( run_uuid , 0 , sizeof ( run_uuid ) ) ;
2019-03-22 22:28:02 +03:00
/* todo: add --readonly */
2019-03-20 21:20:26 +03:00
snprintf ( command , DLMC_RUN_COMMAND_LEN ,
2019-04-04 21:19:08 +03:00
" lvm lvchange --refresh --partial --nolocking %s/%s " ,
vgname , lvname ) ;
2019-03-20 21:20:26 +03:00
rv = dlmc_run_start ( command , strlen ( command ) , 0 ,
DLMC_FLAG_RUN_START_NODE_NONE ,
run_uuid ) ;
if ( rv < 0 ) {
log_debug ( " refresh_lv run_start error %d " , rv ) ;
return rv ;
}
log_debug ( " refresh_lv run_start %s " , run_uuid ) ;
/* Bit of a hack here, we don't need path once started,
but we do need to save the run_uuid somewhere , so just
replace the path with the uuid . */
free ( act - > path ) ;
act - > path = strdup ( run_uuid ) ;
return 0 ;
}
int lm_refresh_lv_check_dlm ( struct action * act )
{
uint32_t check_status = 0 ;
int rv ;
/* NB act->path was replaced with run_uuid */
rv = dlmc_run_check ( act - > path , strlen ( act - > path ) , 0 ,
DLMC_FLAG_RUN_CHECK_CLEAR ,
& check_status ) ;
if ( rv < 0 ) {
log_debug ( " refresh_lv check error %d " , rv ) ;
return rv ;
}
log_debug ( " refresh_lv check %s status %x " , act - > path , check_status ) ;
if ( ! ( check_status & DLMC_RUN_STATUS_DONE ) )
return - EAGAIN ;
if ( check_status & DLMC_RUN_STATUS_FAILED )
return - 1 ;
return 0 ;
}
# else /* LOCKDDLM_CONTROL_SUPPORT */
int lm_refresh_lv_start_dlm ( struct action * act )
{
return 0 ;
}
int lm_refresh_lv_check_dlm ( struct action * act )
{
return 0 ;
}
# endif /* LOCKDDLM_CONTROL_SUPPORT */