1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-11-05 16:23:51 +03:00

Compare commits

...

1 Commits

Author SHA1 Message Date
David Teigland
37a628db52 lvmlockd: use persistent reservations for lock recovery in sanlock 2025-09-18 14:02:06 -05:00
22 changed files with 1987 additions and 193 deletions

View File

@@ -934,7 +934,7 @@ AC_MSG_RESULT([$BUILD_LOCKDSANLOCK])
dnl -- Look for sanlock libraries
AS_IF([test "$BUILD_LOCKDSANLOCK" = "yes"], [
LOCKDSANLOCK_SUPPORT=370
LOCKDSANLOCK_SUPPORT=410
PKG_CHECK_EXISTS(libsanlock_client >= 4.0.0, [LOCKDSANLOCK_SUPPORT=400])
PKG_CHECK_EXISTS(libsanlock_client >= 4.1.0, [LOCKDSANLOCK_SUPPORT=410])
PKG_CHECK_MODULES(LIBSANLOCKCLIENT, libsanlock_client >= 3.7.0, [BUILD_LVMLOCKD="yes"])

View File

@@ -15,7 +15,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SOURCES = lvmlockd-core.c
SOURCES = lvmlockd-core.c lvmlockd-helper.c
SOURCES2 = lvmlockctl.c
TARGETS = lvmlockd lvmlockctl

View File

@@ -60,4 +60,11 @@ static inline void lvmlockd_close(daemon_handle h)
#define EIOTIMEOUT 225
#define ELOCKREPAIR 226
#define LOCKARGS_VERSION 0x00000001 /* meta only */
#define LOCKARGS_LVMLOCK 0x00000002 /* meta only */
#define LOCKARGS_TIMEOUT 0x00000004 /* user only */
#define LOCKARGS_NOTIMEOUT 0x00000008 /* meta or user */
#define LOCKARGS_PERSIST 0x00000010 /* meta or user */
#define LOCKARGS_NOPERSIST 0x00000020 /* user only */
#endif /* _LVM_LVMLOCKD_CLIENT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -76,7 +76,7 @@ static int check_args_version(char *vg_args)
unsigned int major = 0;
int rv;
rv = version_from_args(vg_args, &major, NULL, NULL);
rv = lockd_lockargs_get_version(vg_args, &major, NULL, NULL);
if (rv < 0) {
log_error("check_args_version %s error %d", vg_args, rv);
return rv;

View File

@@ -0,0 +1,264 @@
/*
* Copyright 2025 Red Hat, Inc.
*
* 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 v2 or (at your option) any later version.
*/
#include <inttypes.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <poll.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#include <stdarg.h>
#include <signal.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <grp.h>
#include <syslog.h>
#include "lvmlockd-internal.h"
struct list_head commands; /* helper_msg_list entries */
static int _log_stderr;
#define log_helper(fmt, args...) \
do { \
if (_log_stderr) \
fprintf(stderr, fmt "\n", ##args); \
} while (0)
static void _save_command(struct helper_msg *msg)
{
struct helper_msg_list *ml;
ml = malloc(sizeof(struct helper_msg_list));
if (!ml)
return;
memcpy(&ml->msg, msg, sizeof(struct helper_msg));
list_add_tail(&ml->list, &commands);
}
static struct helper_msg_list *_get_command(int pid)
{
struct helper_msg_list *ml;
list_for_each_entry(ml, &commands, list) {
if (ml->msg.pid == pid)
return ml;
}
return NULL;
}
static int read_msg(int fd, struct helper_msg *msg)
{
int rv;
retry:
rv = read(fd, msg, sizeof(struct helper_msg));
if (rv == -1 && errno == EINTR)
goto retry;
if (rv != sizeof(struct helper_msg))
return -1;
return 0;
}
static void exec_command(char *cmd_str)
{
char arg[ONE_ARG_LEN];
char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */
int av_count = 0;
int i, arg_len, cmd_len;
for (i = 0; i < MAX_AV_COUNT + 1; i++)
av[i] = NULL;
if (!cmd_str[0])
return;
/* this should already be done, but make sure */
cmd_str[RUN_COMMAND_LEN - 1] = '\0';
memset(&arg, 0, sizeof(arg));
arg_len = 0;
cmd_len = strlen(cmd_str);
for (i = 0; i < cmd_len; i++) {
if (!cmd_str[i])
break;
if (av_count == MAX_AV_COUNT)
break;
if (cmd_str[i] == '\\') {
if (i == (cmd_len - 1))
break;
i++;
if (cmd_str[i] == '\\') {
arg[arg_len++] = cmd_str[i];
continue;
}
if (isspace(cmd_str[i])) {
arg[arg_len++] = cmd_str[i];
continue;
} else {
break;
}
}
if (isalnum(cmd_str[i]) || ispunct(cmd_str[i])) {
arg[arg_len++] = cmd_str[i];
} else if (isspace(cmd_str[i])) {
if (arg_len)
av[av_count++] = strdup(arg);
memset(arg, 0, sizeof(arg));
arg_len = 0;
} else {
break;
}
}
if ((av_count < MAX_AV_COUNT) && arg_len) {
av[av_count++] = strdup(arg);
}
execvp(av[0], av);
}
static int send_result(struct helper_msg *msg, int fd)
{
int rv;
rv = write(fd, msg, sizeof(struct helper_msg));
if (rv == sizeof(struct helper_msg))
return 0;
return -1;
}
#define IDLE_TIMEOUT_MS (30 * 1000)
#define ACTIVE_TIMEOUT_MS 500
__attribute__((noreturn)) void helper_main(int in_fd, int out_fd, int log_stderr)
{
struct pollfd pollfd;
struct helper_msg msg;
struct helper_msg_list *ml;
siginfo_t info;
unsigned int fork_count = 0;
unsigned int done_count = 0;
int timeout = IDLE_TIMEOUT_MS;
int rv, pid;
INIT_LIST_HEAD(&commands);
_log_stderr = log_stderr;
rv = setgroups(0, NULL);
if (rv < 0)
log_helper("error clearing helper groups errno %i", errno);
memset(&pollfd, 0, sizeof(pollfd));
pollfd.fd = in_fd;
pollfd.events = POLLIN;
openlog("lvmlockd-helper", LOG_CONS | LOG_PID, LOG_LOCAL4);
while (1) {
rv = poll(&pollfd, 1, timeout);
if (rv == -1 && errno == EINTR)
continue;
if (rv < 0)
exit(0);
if (pollfd.revents & POLLIN) {
memset(&msg, 0, sizeof(msg));
rv = read_msg(in_fd, &msg);
if (rv)
continue;
if (msg.type == HELPER_COMMAND) {
pid = fork();
if (!pid) {
exec_command(msg.command);
exit(1);
}
msg.pid = pid;
_save_command(&msg);
fork_count++;
}
}
if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL))
exit(0);
/* collect child exits until no more children exist (ECHILD)
or none are ready (WNOHANG) */
while (1) {
memset(&info, 0, sizeof(info));
rv = waitid(P_ALL, 0, &info, WEXITED | WNOHANG);
if ((rv < 0) && (errno == ECHILD)) {
/*
log_helper("helper no children exist fork_count %d done_count %d", fork_count, done_count);
*/
timeout = IDLE_TIMEOUT_MS;
}
else if (!rv && !info.si_pid) {
log_helper("helper no children ready fork_count %d done_count %d", fork_count, done_count);
timeout = ACTIVE_TIMEOUT_MS;
}
else if (!rv && info.si_pid) {
done_count++;
if (!(ml = _get_command(info.si_pid))) {
log_helper("command for pid %d result %d not found",
info.si_pid, info.si_status);
continue;
}
log_helper("command for pid %d result %d done", info.si_pid, info.si_status);
ml->msg.type = HELPER_COMMAND_RESULT;
ml->msg.result = info.si_status;
send_result(&ml->msg, out_fd);
list_del(&ml->list);
free(ml);
continue;
}
else {
log_helper("helper waitid rv %d errno %d fork_count %d done_count %d",
rv, errno, fork_count, done_count);
}
break;
}
}
}

View File

@@ -63,6 +63,10 @@ enum {
LD_OP_QUERY_LOCK,
LD_OP_REFRESH_LV,
LD_OP_VG_STATUS,
LD_OP_FENCE,
LD_OP_FENCE_RESULT,
LD_OP_SETLOCKARGS_BEFORE,
LD_OP_SETLOCKARGS_FINAL,
};
/* resource types */
@@ -119,6 +123,7 @@ struct client {
#define LD_AF_ADOPT_ONLY 0x00200000 /* adopt orphan or fail */
#define LD_AF_NODELAY 0x00400000
#define LD_AF_REPAIR 0x00800000
#define LD_AF_NO_TIMEOUT 0x01000000
/*
* Number of times to repeat a lock request after
@@ -132,6 +137,32 @@ struct pvs {
int num;
};
#define RUN_COMMAND_LEN 1024
#define MAX_AV_COUNT 32
#define ONE_ARG_LEN 256
/* helper_msg types */
#define HELPER_COMMAND 0x1
#define HELPER_COMMAND_RESULT 0x2
struct helper_msg {
uint8_t type;
uint8_t act;
uint16_t unused1;
uint32_t msg_id;
int pid;
int result;
char ls_name[MAX_NAME+1];
uint8_t unused2;
uint16_t unused3;
char command[RUN_COMMAND_LEN];
};
struct helper_msg_list {
struct helper_msg msg;
struct list_head list;
};
#define OWNER_NAME_SIZE 64
#define OWNER_STATE_SIZE 32
@@ -147,8 +178,11 @@ struct action {
struct list_head list;
uint32_t client_id;
uint32_t flags; /* LD_AF_ */
uint32_t msg_id;
uint32_t version;
uint32_t host_id;
uint64_t ourkey;
uint64_t remkey;
uint64_t lv_size_bytes;
int8_t op; /* operation type LD_OP_ */
int8_t rt; /* resource type LD_RT_ */
@@ -166,7 +200,7 @@ struct action {
char lv_uuid[MAX_NAME+1];
char vg_args[MAX_ARGS+1];
char lv_args[MAX_ARGS+1];
char prev_lv_args[MAX_ARGS+1];
char other_args[MAX_ARGS+1];
struct owner owner;
struct pvs pvs; /* PV list for idm */
};
@@ -187,6 +221,7 @@ struct resource {
unsigned int use_vb : 1;
struct list_head locks;
struct list_head actions;
struct list_head fence_wait_actions;
char lv_args[MAX_ARGS+1];
char lm_data[]; /* lock manager specific data */
};
@@ -209,8 +244,10 @@ struct lockspace {
char vg_args[MAX_ARGS+1]; /* lock manager specific args */
int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */
void *lm_data;
uint32_t lock_args_flags;
uint32_t host_id;
uint64_t generation;
uint64_t ourkey;
uint64_t free_lock_offset; /* for sanlock, start search for free lock here */
struct pvs pvs; /* for idm: PV list */
@@ -225,13 +262,14 @@ struct lockspace {
unsigned int thread_done : 1;
unsigned int sanlock_gl_enabled: 1;
unsigned int sanlock_gl_dup: 1;
unsigned int free_vg: 1;
unsigned int kill_vg: 1;
unsigned int drop_vg: 1;
unsigned int fence_pr: 1;
unsigned int no_timeout: 1;
struct list_head actions; /* new client actions */
struct list_head resources; /* resource/lock state for gl/vg/lv */
struct list_head dispose; /* resources to free */
struct list_head fence_history; /* internally created actions for fencing */
};
/* val_blk version */
@@ -390,7 +428,9 @@ void log_level(int level, const char *fmt, ...) __attribute__((format(printf, 2
struct lockspace *alloc_lockspace(void);
int lockspaces_empty(void);
int last_string_from_args(char *args_in, char *last);
int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsigned int *patch);
void helper_main(int in_fd, int out_fd, int log_stderr);
int lockd_lockargs_get_user_flags(const char *str, uint32_t *flags);
int lockd_lockargs_get_version(char *str, unsigned int *major, unsigned int *minor, unsigned int *patch);
static inline const char *mode_str(int x)
{
@@ -559,7 +599,7 @@ static inline int lm_refresh_lv_check_dlm(struct action *act)
#ifdef LOCKDSANLOCK_SUPPORT
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb);
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb, char *other_args);
int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args);
int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r);
int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args);
@@ -584,6 +624,9 @@ int lm_data_size_sanlock(void);
int lm_is_running_sanlock(void);
int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes);
int lm_vg_status_sanlock(struct lockspace *ls, struct action *act);
void lm_set_host_dead_sanlock(struct lockspace *ls, struct owner *owner);
int lm_setlockargs_supported_sanlock(struct lockspace *ls, struct action *act);
int lm_setlockargs_vg_sanlock(char *ls_name, char *vg_name, struct action *act);
static inline int lm_support_sanlock(void)
{
@@ -592,7 +635,7 @@ static inline int lm_support_sanlock(void)
#else
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb)
static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb, char *other_args)
{
return -1;
}
@@ -706,6 +749,20 @@ static inline int lm_support_sanlock(void)
return 0;
}
void lm_set_host_dead_sanlock(struct lockspace *ls, struct owner *owner)
{
}
int lm_setlockargs_supported_sanlock(struct lockspace *ls, struct action *act)
{
return 0;
}
int lm_setlockargs_vg_sanlock(char *ls_name, char *vg_name, struct action *act)
{
return 0;
}
#endif /* sanlock support */
#ifdef LOCKDIDM_SUPPORT

View File

@@ -175,30 +175,32 @@ int lm_data_size_sanlock(void)
}
/*
* lock_args format
* If a new variant of the lock_args string cannot be
* handled by the previous version of lvmlockd, then the
* new variant should contain a larger major number.
*
* vg_lock_args format for sanlock is
* vg_version_string:undefined:lock_lv_name
* VG_LOCK_ARGS_V1 format:
* 1.0.0:lvname
*
* lv_lock_args format for sanlock is
* lv_version_string:undefined:offset
*
* version_string is MAJOR.MINOR.PATCH
* undefined may contain ":"
*
* If a new version of the lock_args string cannot be
* handled by an old version of lvmlockd, then the
* new lock_args string should contain a larger major number.
* VG_LOCK_ARGS_V2 format:
* 2.0.0:lvname:notimeout:persist
* 2.0.0:lvname:notimeout
* 2.0.0:lvname:persist
*/
#define VG_LOCK_ARGS_MAJOR 1
#define VG_LOCK_ARGS_MAJOR 2
#define VG_LOCK_ARGS_MINOR 0
#define VG_LOCK_ARGS_PATCH 0
#define VG_LOCK_ARGS_V1 "1.0.0"
#define VG_LOCK_ARGS_V2 "2.0.0"
#define LV_LOCK_ARGS_MAJOR 1
#define LV_LOCK_ARGS_MINOR 0
#define LV_LOCK_ARGS_PATCH 0
#define LV_LOCK_ARGS_V1 "1.0.0"
/*
* offset 0 is lockspace
* offset align_size * 1 is unused
@@ -241,9 +243,31 @@ static void strcpy_name_len(char *buf, const char *str, size_t len)
memccpy(buf, str, 0, len);
}
static int lock_lv_name_from_args(char *vg_args, char *lock_lv_name)
/*
* copy out lvname from lock_args string:
* 1.0.0:lvname
* 2.0.0:lvname
* 2.0.0:lvname:other
*/
static int lockd_lockargs_get_locklv(char *vg_args, char *lock_lv_name)
{
return last_string_from_args(vg_args, lock_lv_name);
char args[MAX_ARGS+1] = {0};
char *p, *name;
strncpy(args, vg_args, MAX_ARGS);
if (!(p = strchr(args, ':')))
return -1;
name = p+1;
if (!*name)
return -1;
if ((p = strchr(name, ':')))
*p = '\0';
strncpy(lock_lv_name, name, MAX_ARGS);
return 0;
}
static int lock_lv_offset_from_args(char *lv_args, uint64_t *lock_lv_offset)
@@ -269,7 +293,7 @@ static int check_args_version(char *args, unsigned int our_major)
unsigned int major = 0;
int rv;
rv = version_from_args(args, &major, NULL, NULL);
rv = lockd_lockargs_get_version(args, &major, NULL, NULL);
if (rv < 0) {
log_error("check_args_version %s error %d", args, rv);
return rv;
@@ -333,13 +357,13 @@ out:
}
#if LOCKDSANLOCK_SUPPORT >= 410
static int read_info_file(struct lockspace *ls, uint32_t *host_id, uint64_t *generation, int *sector_size, int *align_size)
static int read_info_file(char *vg_name, uint32_t *host_id, uint64_t *generation, int *sector_size, int *align_size, int *no_timeout)
{
char line[MAX_LINE];
char path[PATH_MAX] = { 0 };
FILE *fp;
if (dm_snprintf(path, sizeof(path), "/var/lib/lvm/lvmlockd_info_%s", ls->vg_name) < 0)
if (dm_snprintf(path, sizeof(path), "/var/lib/lvm/lvmlockd_info_%s", vg_name) < 0)
return -1;
if (!(fp = fopen(path, "r"))) {
@@ -362,11 +386,14 @@ static int read_info_file(struct lockspace *ls, uint32_t *host_id, uint64_t *gen
} else if (!strncmp(line, "align_size ", 11)) {
if (sscanf(line, "align_size %d", align_size) != 1)
goto fail;
} else if (!strncmp(line, "no_timeout ", 11)) {
if (sscanf(line, "no_timeout %d", no_timeout) != 1)
goto fail;
}
}
_fclose(fp, path);
log_debug("info file: read %u %llu %d %d", *host_id, (unsigned long long)*generation, *sector_size, *align_size);
log_debug("info file: read %u %llu %d %d %d", *host_id, (unsigned long long)*generation, *sector_size, *align_size, *no_timeout);
return 0;
fail:
@@ -376,14 +403,13 @@ fail:
}
#endif
static int write_info_file(struct lockspace *ls)
static int write_info_file(char *vg_name, uint32_t host_id, uint64_t generation, int sector_size, int align_size, int no_timeout)
{
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
char path[PATH_MAX] = { 0 };
FILE *fp;
time_t t = time(NULL);
if (dm_snprintf(path, sizeof(path), "/var/lib/lvm/lvmlockd_info_%s", ls->vg_name) < 0)
if (dm_snprintf(path, sizeof(path), "/var/lib/lvm/lvmlockd_info_%s", vg_name) < 0)
return -1;
if (!(fp = fopen(path, "w"))) {
@@ -391,17 +417,38 @@ static int write_info_file(struct lockspace *ls)
return -1;
}
fprintf(fp, "# vg %s %s created %s", ls->vg_name, ls->vg_uuid, ctime(&t));
fprintf(fp, "host_id %u\n", ls->host_id);
fprintf(fp, "generation %llu\n", (unsigned long long)ls->generation);
fprintf(fp, "sector_size %d\n", lms->sector_size);
fprintf(fp, "align_size %d\n", lms->align_size);
fprintf(fp, "# vg %s created %s", vg_name, ctime(&t));
fprintf(fp, "host_id %u\n", host_id);
fprintf(fp, "generation %llu\n", (unsigned long long)generation);
fprintf(fp, "sector_size %d\n", sector_size);
fprintf(fp, "align_size %d\n", align_size);
fprintf(fp, "no_timeout %d\n", no_timeout);
if (fflush(fp))
log_warn("Failed to write/flush %s", path);
_fclose(fp, path);
log_debug("info file: wrote %u %llu %d %d", ls->host_id, (unsigned long long)ls->generation, lms->sector_size, lms->align_size);
log_debug("info file: wrote %u %llu %d %d %d", host_id, (unsigned long long)generation, sector_size, align_size, no_timeout);
return 0;
}
static int update_info_file(char *vg_name, int no_timeout_new)
{
uint32_t host_id;
uint64_t generation;
int sector_size;
int align_size;
int no_timeout;
int rv;
rv = read_info_file(vg_name, &host_id, &generation, &sector_size, &align_size, &no_timeout);
if (rv < 0)
return rv;
rv = write_info_file(vg_name, host_id, generation, sector_size, align_size, no_timeout_new);
if (rv < 0)
return rv;
return 0;
}
@@ -591,7 +638,7 @@ static int _lease_corrupt_error(int rv)
sanlock encoded this in the lockspace/resource structs on disk. */
static int read_lockspace_info(char *path, uint32_t host_id, int *sector_size, int *align_size, int *align_mb,
uint32_t *ss_flags, uint32_t *rs_flags, struct sanlk_host *hs)
uint32_t *ss_size_flags, uint32_t *rs_size_flags, int *no_timeout, struct sanlk_host *hs)
{
struct sanlk_lockspace ss;
uint32_t io_timeout = 0;
@@ -623,40 +670,43 @@ static int read_lockspace_info(char *path, uint32_t host_id, int *sector_size, i
*sector_size = 4096;
*align_mb = 8;
*align_size = 8 * ONE_MB;
*ss_flags = SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN8M;
*rs_flags = SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M;
*ss_size_flags = SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN8M;
*rs_size_flags = SANLK_RES_SECTOR4K | SANLK_RES_ALIGN8M;
} else if ((ss.flags & SANLK_LSF_SECTOR4K) && (ss.flags & SANLK_LSF_ALIGN4M)) {
*sector_size = 4096;
*align_mb = 4;
*align_size = 4 * ONE_MB;
*ss_flags = SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN4M;
*rs_flags = SANLK_RES_SECTOR4K | SANLK_RES_ALIGN4M;
*ss_size_flags = SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN4M;
*rs_size_flags = SANLK_RES_SECTOR4K | SANLK_RES_ALIGN4M;
} else if ((ss.flags & SANLK_LSF_SECTOR4K) && (ss.flags & SANLK_LSF_ALIGN2M)) {
*sector_size = 4096;
*align_mb = 2;
*align_size = 2 * ONE_MB;
*ss_flags = SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN2M;
*rs_flags = SANLK_RES_SECTOR4K | SANLK_RES_ALIGN2M;
*ss_size_flags = SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN2M;
*rs_size_flags = SANLK_RES_SECTOR4K | SANLK_RES_ALIGN2M;
} else if ((ss.flags & SANLK_LSF_SECTOR4K) && (ss.flags & SANLK_LSF_ALIGN1M)) {
*sector_size = 4096;
*align_mb = 1;
*align_size = ONE_MB;
*ss_flags = SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN1M;
*rs_flags = SANLK_RES_SECTOR4K | SANLK_RES_ALIGN1M;
*ss_size_flags = SANLK_LSF_SECTOR4K | SANLK_LSF_ALIGN1M;
*rs_size_flags = SANLK_RES_SECTOR4K | SANLK_RES_ALIGN1M;
} else if ((ss.flags & SANLK_LSF_SECTOR512) && (ss.flags & SANLK_LSF_ALIGN1M)) {
*sector_size = 512;
*align_mb = 1;
*align_size = ONE_MB;
*ss_flags = SANLK_LSF_SECTOR512 | SANLK_LSF_ALIGN1M;
*rs_flags = SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M;
*ss_size_flags = SANLK_LSF_SECTOR512 | SANLK_LSF_ALIGN1M;
*rs_size_flags = SANLK_RES_SECTOR512 | SANLK_RES_ALIGN1M;
}
log_debug("read_lockspace_info %s %u found sector_size %d align_size %d",
path, host_id, *sector_size, *align_size);
if (ss.flags & SANLK_LSF_NO_TIMEOUT)
*no_timeout = 1;
log_debug("read_lockspace_info %s %u found sector_size %d align_size %d no_timeout %d",
path, host_id, *sector_size, *align_size, *no_timeout);
return 0;
}
@@ -670,43 +720,45 @@ static int read_lockspace_info(char *path, uint32_t host_id, int *sector_size, i
#define MAX_VERSION 16
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb)
int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb, char *other_args)
{
struct sanlk_lockspace ss;
struct sanlk_resourced rd;
struct sanlk_disk disk;
char lock_lv_name[MAX_ARGS+1];
char lock_args_version[MAX_VERSION+1];
const char *gl_name = NULL;
uint32_t lock_args_flags = 0;
uint32_t rs_flags;
uint32_t daemon_version;
uint32_t daemon_proto;
uint64_t offset;
uint64_t dev_size;
int no_timeout;
int persist;
int sector_size = 0;
int align_size = 0;
int align_mb = 0;
int i, rv;
if (other_args && !lockd_lockargs_get_user_flags(other_args, &lock_args_flags)) {
log_error("S %s init_vg_san unknown other args %s", ls_name, other_args);
return -EARGS;
}
no_timeout = (lock_args_flags & LOCKARGS_NOTIMEOUT) ? 1 :0;
persist = (lock_args_flags & LOCKARGS_PERSIST) ? 1 : 0;
memset(&ss, 0, sizeof(ss));
memset(&rd, 0, sizeof(rd));
memset(&disk, 0, sizeof(disk));
memset(lock_args_version, 0, sizeof(lock_args_version));
if (!vg_args || !vg_args[0] || !strcmp(vg_args, "none")) {
log_error("S %s init_vg_san vg_args missing", ls_name);
return -EARGS;
}
snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
VG_LOCK_ARGS_MAJOR, VG_LOCK_ARGS_MINOR, VG_LOCK_ARGS_PATCH);
/* see comment above about input vg_args being only lock_lv_name */
dm_strncpy(lock_lv_name, vg_args, sizeof(lock_lv_name));
if (strlen(lock_lv_name) + strlen(lock_args_version) + 2 > MAX_ARGS)
return -EARGS;
if ((rv = build_dm_path(disk.path, SANLK_PATH_LEN, vg_name, lock_lv_name)))
return rv;
@@ -715,7 +767,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
if (daemon_test) {
if (!gl_lsname_sanlock[0])
strncpy(gl_lsname_sanlock, ls_name, MAX_NAME);
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", VG_LOCK_ARGS_V1, lock_lv_name);
if (rv >= MAX_ARGS)
log_debug("init_vg_san vg_args may be too long %d %s", rv, vg_args);
return 0;
@@ -787,6 +839,9 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
return -EARGS;
}
if (no_timeout)
ss.flags |= SANLK_LSF_NO_TIMEOUT;
rv = sanlock_write_lockspace(&ss, 0, 0, sanlock_io_timeout);
if (rv < 0) {
log_error("S %s init_vg_san write_lockspace error %d %s",
@@ -841,15 +896,6 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
return rv;
}
if (!strcmp(gl_name, R_NAME_GL))
dm_strncpy(gl_lsname_sanlock, ls_name, sizeof(gl_lsname_sanlock));
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", lock_args_version, lock_lv_name);
if (rv >= MAX_ARGS)
log_debug("init_vg_san vg_args may be too long %d %s", rv, vg_args);
log_debug("S %s init_vg_san done vg_args %s", ls_name, vg_args);
/*
* Go through all lv resource slots and initialize them with the
* correct lockspace name but a special resource name that indicates
@@ -888,6 +934,25 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar
offset += align_size;
}
if (no_timeout && persist)
rv = snprintf(vg_args, MAX_ARGS, "%s:%s:notimeout:persist", VG_LOCK_ARGS_V2, lock_lv_name);
else if (no_timeout)
rv = snprintf(vg_args, MAX_ARGS, "%s:%s:notimeout", VG_LOCK_ARGS_V2, lock_lv_name);
else if (persist)
rv = snprintf(vg_args, MAX_ARGS, "%s:%s:persist", VG_LOCK_ARGS_V2, lock_lv_name);
else
rv = snprintf(vg_args, MAX_ARGS, "%s:%s", VG_LOCK_ARGS_V1, lock_lv_name);
if (rv >= MAX_ARGS) {
log_error("S %s init_vg_san vg_args string too long %d %s", ls_name, rv, vg_args);
return -EINVAL;
}
if (!strcmp(gl_name, R_NAME_GL))
dm_strncpy(gl_lsname_sanlock, ls_name, sizeof(gl_lsname_sanlock));
log_debug("S %s init_vg_san done vg_args %s", ls_name, vg_args);
return 0;
}
@@ -905,12 +970,12 @@ int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char
struct lm_sanlock *lms;
struct sanlk_resourced rd;
char lock_lv_name[MAX_ARGS+1];
char lock_args_version[MAX_VERSION+1];
uint64_t offset;
uint64_t prev_offset = 0;
int sector_size = 0;
int align_size = 0;
int align_mb;
int no_timeout = 0;
uint32_t ss_flags;
uint32_t rs_flags = 0;
uint32_t tries = 1;
@@ -918,24 +983,20 @@ int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char
memset(&rd, 0, sizeof(rd));
memset(lock_lv_name, 0, sizeof(lock_lv_name));
memset(lock_args_version, 0, sizeof(lock_args_version));
memset(disk_path, 0, sizeof(disk_path));
snprintf(lock_args_version, MAX_VERSION, "%u.%u.%u",
LV_LOCK_ARGS_MAJOR, LV_LOCK_ARGS_MINOR, LV_LOCK_ARGS_PATCH);
if (daemon_test) {
align_size = 1024 * 1024;
snprintf(lv_args, MAX_ARGS, "%s:%llu",
lock_args_version,
LV_LOCK_ARGS_V1,
(unsigned long long)((align_size * LV_LOCK_BEGIN) + (align_size * daemon_test_lv_count)));
daemon_test_lv_count++;
return 0;
}
rv = lock_lv_name_from_args(vg_args, lock_lv_name);
rv = lockd_lockargs_get_locklv(vg_args, lock_lv_name);
if (rv < 0) {
log_error("S %s init_lv_san lock_lv_name_from_args error %d %s",
log_error("S %s init_lv_san lockd_lockargs_get_locklv error %d %s",
ls_name, rv, vg_args);
return rv;
}
@@ -957,7 +1018,7 @@ int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char
/* using host_id 1 to get sizes since we don't need host-specific info */
rv = read_lockspace_info(disk_path, 1, &sector_size, &align_size, &align_mb, &ss_flags, &rs_flags, NULL);
rv = read_lockspace_info(disk_path, 1, &sector_size, &align_size, &align_mb, &ss_flags, &rs_flags, &no_timeout, NULL);
if (rv < 0) {
log_error("S %s init_lv_san read_lockspace_info error %d %s",
ls_name, rv, disk_path);
@@ -1025,7 +1086,7 @@ int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char
rv = sanlock_write_resource(&rd.rs, 0, 0, 0);
if (!rv) {
snprintf(lv_args, MAX_ARGS, "%s:%llu",
lock_args_version, (unsigned long long)offset);
LV_LOCK_ARGS_V1, (unsigned long long)offset);
} else {
log_error("S %s init_lv_san write error %d offset %llu",
ls_name, rv, (unsigned long long)rv);
@@ -1065,9 +1126,9 @@ int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_
return -EINVAL;
}
rv = lock_lv_name_from_args(vg_args, lock_lv_name);
rv = lockd_lockargs_get_locklv(vg_args, lock_lv_name);
if (rv < 0) {
log_error("S %s init_lv_san lock_lv_name_from_args error %d %s",
log_error("S %s init_lv_san lockd_lockargs_get_locklv error %d %s",
ls_name, rv, vg_args);
return rv;
}
@@ -1587,6 +1648,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation
int sector_size = 0;
int align_size = 0;
int align_mb = 0;
int no_timeout = 0;
int retries = 0;
int gl_found;
int ret, rv;
@@ -1612,9 +1674,9 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation
goto fail;
}
rv = lock_lv_name_from_args(ls->vg_args, lock_lv_name);
rv = lockd_lockargs_get_locklv(ls->vg_args, lock_lv_name);
if (rv < 0) {
log_error("S %s prepare_lockspace_san lock_lv_name_from_args error %d %s",
log_error("S %s prepare_lockspace_san lockd_lockargs_get_locklv error %d %s",
ls->name, rv, ls->vg_args);
ret = -EARGS;
goto fail;
@@ -1711,15 +1773,16 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation
#endif
sector_size = 0;
align_size = 0;
no_timeout = 0;
rv = read_lockspace_info(disk_path, lms->ss.host_id, &sector_size, &align_size, &align_mb, &ss_flags, &rs_flags, &hs);
rv = read_lockspace_info(disk_path, lms->ss.host_id, &sector_size, &align_size, &align_mb, &ss_flags, &rs_flags, &no_timeout, &hs);
#if LOCKDSANLOCK_SUPPORT >= 410
if ((rv == -ELOCKREPAIR) && repair && !retries) {
uint64_t generation = 0;
uint32_t host_id = 0;
rv = read_info_file(ls, &host_id, &generation, &sector_size, &align_size);
rv = read_info_file(ls->vg_name, &host_id, &generation, &sector_size, &align_size, &no_timeout);
if (rv < 0) {
log_error("S %s prepare_lockspace_san cannot repair lockspace no info file", lsname);
ret = -EINVAL;
@@ -1750,6 +1813,9 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation
ret = -EINVAL;
}
if (no_timeout)
lms->ss.flags |= SANLK_LSF_NO_TIMEOUT;
log_debug("S %s prepare_lockspace_san repair host %u lease", lsname, host_id);
rv = sanlock_init_lockspace_host(&lms->ss, NULL, generation, 0, 0, 0);
@@ -1899,7 +1965,7 @@ int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok,
free(hs);
write_info_file(ls);
write_info_file(ls->vg_name, ls->host_id, ls->generation, lms->sector_size, lms->align_size, ls->no_timeout);
/*
* Don't let the lockspace be cleanly released if orphan locks
@@ -2203,6 +2269,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
rv == SANLK_ACQUIRE_OWNED ||
rv == SANLK_ACQUIRE_OTHER ||
rv == SANLK_ACQUIRE_OWNED_RETRY ||
rv == SANLK_ACQUIRE_OWNED_NO_TIMEOUT ||
rv == -EAGAIN) {
/*
@@ -2231,6 +2298,9 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
if (rv == SANLK_ACQUIRE_OWNED_RETRY)
*retry = 0;
if (rv == SANLK_ACQUIRE_OWNED_NO_TIMEOUT)
*retry = 0;
if (owner && owner_host.host_id) {
const char *host_state;
@@ -2421,6 +2491,7 @@ int lm_convert_sanlock(struct lockspace *ls, struct resource *r,
case SANLK_ACQUIRE_IDLIVE:
case SANLK_ACQUIRE_OWNED:
case SANLK_ACQUIRE_OWNED_RETRY:
case SANLK_ACQUIRE_OWNED_NO_TIMEOUT:
case SANLK_ACQUIRE_OTHER:
case SANLK_AIO_TIMEOUT:
/* expected errors from known/normal cases like lock contention or io timeouts */
@@ -2729,3 +2800,137 @@ int lm_is_running_sanlock(void)
return 1;
}
void lm_set_host_dead_sanlock(struct lockspace *ls, struct owner *owner)
{
struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data;
struct sanlk_host host = { 0 };
int rv;
log_debug("S %s set_host_dead_sanlock host_id %u gen %u", ls->name, owner->host_id, owner->generation);
host.host_id = owner->host_id;
host.generation = owner->generation;
rv = sanlock_set_host(&lms->ss, SANLK_SET_HOST_DEAD_EXT, 0, 0, &host);
if (rv < 0)
log_error("S %s set_host_dead_sanlock host_id %u gen %u error %d", ls->name, owner->host_id, owner->generation, rv);
}
int lm_setlockargs_supported_sanlock(struct lockspace *ls, struct action *act)
{
uint32_t daemon_version;
uint32_t daemon_proto;
uint32_t lock_args_flags = 0;
uint32_t ver_major, ver_minor;
int rv;
if (!lockd_lockargs_get_user_flags(act->other_args, &lock_args_flags)) {
log_error("S %s setlockargs_supported invalid user lock args %s", ls->name, act->other_args);
return 0;
}
if (!(lock_args_flags & LOCKARGS_NOTIMEOUT) && !(lock_args_flags & LOCKARGS_PERSIST))
return 1;
rv = sanlock_version(0, &daemon_version, &daemon_proto);
if (rv < 0) {
log_error("S %s setlockargs failed to connect to sanlock daemon", ls->name);
return 0;
}
log_debug("S %s setlockargs sanlock version 0x%x lock_args_flags 0x%x", ls->name, daemon_version, lock_args_flags);
ver_major = (daemon_version & 0xFF000000) >> 24;
ver_minor = (daemon_version & 0x00FF0000) >> 16;
/* sanlock 4.1.0 added support for LOCKARGS_NOTIMEOUT or LOCKARGS_PERSIST. */
if (ver_major < 4)
return 0;
if ((ver_major == 4) && (ver_minor < 1))
return 0;
return 1;
}
int lm_setlockargs_vg_sanlock(char *ls_name, char *vg_name, struct action *act)
{
struct sanlk_lockspace ss = {0};
char lock_lv_name[MAX_ARGS+1] = {0};
char disk_path[SANLK_PATH_LEN] = {0};
uint32_t ss_size_flags = 0;
uint32_t rs_size_flags = 0;
uint32_t lock_args_flags = 0;
int sector_size = 0;
int align_size = 0;
int align_mb = 0;
int no_timeout;
int persist;
int rv;
if (!lockd_lockargs_get_user_flags(act->other_args, &lock_args_flags)) {
log_error("S %s setlockargs invalid user lock args %s", ls_name, act->other_args);
return 0;
}
rv = lockd_lockargs_get_locklv(act->vg_args, lock_lv_name);
if (rv < 0) {
log_error("S %s setlockargs lockd_lockargs_get_locklv error %d %s",
ls_name, rv, act->vg_args);
return rv;
}
if ((rv = build_dm_path(disk_path, SANLK_PATH_LEN, vg_name, lock_lv_name)))
return rv;
/* get the sector and align flags from host_id 1 in the current lockspace */
rv = read_lockspace_info(disk_path, 1, &sector_size, &align_size, &align_mb, &ss_size_flags, &rs_size_flags, &no_timeout, NULL);
if (rv < 0) {
log_error("S %s setlockargs read_lockspace_info error %d %s", ls_name, rv, disk_path);
return rv;
}
/* initialize lockspace */
no_timeout = (lock_args_flags & LOCKARGS_NOTIMEOUT) ? 1 :0;
persist = (lock_args_flags & LOCKARGS_PERSIST) ? 1 : 0;
strcpy_name_len(ss.name, ls_name, SANLK_NAME_LEN);
memcpy(ss.host_id_disk.path, disk_path, SANLK_PATH_LEN);
ss.host_id_disk.offset = 0;
ss.flags = ss_size_flags;
if (no_timeout)
ss.flags |= SANLK_LSF_NO_TIMEOUT;
log_debug("S %s setlockargs write_lockspace no_timeout %d flags 0x%x", ls_name, no_timeout, ss.flags);
rv = sanlock_write_lockspace(&ss, 0, 0, sanlock_io_timeout);
if (rv < 0) {
log_error("S %s setlockargs write_lockspace error %d %s", ls_name, rv, ss.host_id_disk.path);
return rv;
}
update_info_file(vg_name, no_timeout);
if (no_timeout && persist)
rv = snprintf(act->vg_args, MAX_ARGS, "%s:%s:notimeout:persist", VG_LOCK_ARGS_V2, lock_lv_name);
else if (no_timeout)
rv = snprintf(act->vg_args, MAX_ARGS, "%s:%s:notimeout", VG_LOCK_ARGS_V2, lock_lv_name);
else if (persist)
rv = snprintf(act->vg_args, MAX_ARGS, "%s:%s:persist", VG_LOCK_ARGS_V2, lock_lv_name);
else
rv = snprintf(act->vg_args, MAX_ARGS, "%s:%s", VG_LOCK_ARGS_V1, lock_lv_name);
log_debug("S %s setlockargs new args %s", ls_name, act->vg_args);
if (rv >= MAX_ARGS) {
log_error("S %s setlockargs vg_args string too long %d %s", ls_name, rv, act->vg_args);
return -EINVAL;
}
return 0;
}

View File

@@ -813,7 +813,7 @@ int vg_is_registered(struct cmd_context *cmd, struct volume_group *vg, uint64_t
}
}
int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int may_fail)
int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int may_fail, uint64_t *our_key_ret)
{
struct pv_list *pvl;
struct device *dev;
@@ -826,6 +826,9 @@ int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int may
if (!vg_is_registered(cmd, vg, &our_key_val, &partial))
goto out;
if (our_key_ret)
*our_key_ret = our_key_val;
if (partial) {
log_debug("PR is started: partial");
goto out;
@@ -1166,6 +1169,8 @@ int persist_key_update(struct cmd_context *cmd, struct volume_group *vg, uint32_
return 0;
}
/* TODO: send new key to lvmlockd, e.g. call lockd_vg_is_started() and have that include our key */
log_debug("persist_key_update: updated 0x%llx to %s", (unsigned long long)our_key_val, new_key_buf);
return 1;
}
@@ -1794,6 +1799,117 @@ static int _persist_extend_shared(struct cmd_context *cmd, struct volume_group *
return error ? 0 : 1;
}
int persist_upgrade_stop(struct cmd_context *cmd, struct volume_group *vg, uint64_t our_key_val)
{
DM_LIST_INIT(devs);
char our_key_buf[PR_KEY_BUF_SIZE] = { 0 };
if (!pv_list_to_dev_list(cmd->mem, &vg->pvs, &devs))
return_0;
if (dm_snprintf(our_key_buf, PR_KEY_BUF_SIZE-1, "0x%llx", (unsigned long long)our_key_val) < 0)
return_0;
if (!_run_stop(cmd, vg, &devs, our_key_buf, 0))
return_0;
return 1;
}
/*
* Host currently holds a normal sh access PR on shared VG,
* and wants to switch to an ex access PR on that VG
* (to prevent other hosts from using it while it's making
* changes.)
*/
int persist_upgrade_ex(struct cmd_context *cmd, struct volume_group *vg, uint64_t *our_key_held)
{
DM_LIST_INIT(devs);
struct device_list *devl;
char *local_key = (char *)find_config_tree_str(cmd, local_pr_key_CFG, NULL);
int local_host_id = find_config_tree_int(cmd, local_host_id_CFG, NULL);
char our_key_buf[PR_KEY_BUF_SIZE] = { 0 };
char new_key_buf[PR_KEY_BUF_SIZE] = { 0 };
uint64_t our_key_val = 0;
uint64_t new_key_val = 0;
const char *devname;
const char **argv;
int pv_count;
int args;
int status;
if (!local_key && !local_host_id)
return 1;
if (!get_our_key(cmd, vg, local_key, local_host_id, our_key_buf, &our_key_val))
return_0;
if (!pv_list_to_dev_list(cmd->mem, &vg->pvs, &devs))
return_0;
log_debug("persist_upgrade_ex stop PR %s", our_key_buf);
if (!_run_stop(cmd, vg, &devs, our_key_buf, 0))
return_0;
if (local_key) {
new_key_val = our_key_val;
memcpy(new_key_buf, our_key_buf, PR_KEY_BUF_SIZE);
} else if (local_host_id) {
if (dm_snprintf(new_key_buf, PR_KEY_BUF_SIZE-1, "0x100000000000%04x", local_host_id) != 18) {
log_error("Failed to format key string for host_id %d", local_host_id);
return 0;
}
if (!parse_prkey(new_key_buf, &new_key_val)) {
log_error("Failed to parse generated key %s", new_key_buf);
return 0;
}
}
pv_count = dm_list_size(&devs);
log_debug("persist_upgrade_ex start PR on %d devs with local key %llx", pv_count, (unsigned long long)new_key_val);
args = 9 + pv_count*2;
if (vg->pr & VG_PR_PTPL)
args += 1;
if (!(argv = dm_pool_alloc(cmd->mem, args * sizeof(char *))))
return_0;
args = 0;
argv[0] = LVMPERSIST_PATH;
argv[++args] = "start";
argv[++args] = "--ourkey";
argv[++args] = new_key_buf;
argv[++args] = "--access";
argv[++args] = "ex";
argv[++args] = "--vg";
argv[++args] = vg->name;
if (vg->pr & VG_PR_PTPL)
argv[++args] = "--ptpl";
dm_list_iterate_items(devl, &devs) {
if (!(devname = dm_pool_strdup(cmd->mem, dev_name(devl->dev))))
return_0;
argv[++args] = "--device";
argv[++args] = devname;
}
argv[++args] = NULL;
if (!exec_cmd(cmd, argv, &status, 1)) {
log_error("persistent reservation exclusive start failed: lvmpersist command error.");
log_error("(Use vgchange --persist stop to stop PR on other hosts.");
return 0;
}
*our_key_held = new_key_val;
return 1;
}
/*
* Start PR on devices that are being used for vgcreate.
* This is somewhat awkward because it happens early in
@@ -1817,6 +1933,8 @@ int persist_vgcreate_begin(struct cmd_context *cmd, char *vg_name, char *local_k
int args;
int status;
persist_key_file_remove_name(cmd, vg_name);
if (local_key) {
if (!parse_prkey(local_key, &our_key_val)) {
log_error("Failed to parse local key %s", local_key);
@@ -1883,7 +2001,8 @@ int persist_vgcreate_begin(struct cmd_context *cmd, char *vg_name, char *local_k
* access PR (typically WE), and starts PR with the normal sh access
* PR (typically WEAR), allowing other hosts to also use the new VG.
*/
int persist_vgcreate_update(struct cmd_context *cmd, struct volume_group *vg, uint32_t set_flags)
int persist_vgcreate_update(struct cmd_context *cmd, struct volume_group *vg, uint32_t set_flags,
uint64_t *our_key_ret)
{
DM_LIST_INIT(devs);
struct device_list *devl;
@@ -1987,9 +2106,13 @@ int persist_vgcreate_update(struct cmd_context *cmd, struct volume_group *vg, ui
return 0;
}
/* key file is an optimization, not an error condition */
if (!write_key_file(cmd, vg, our_key_val))
stack;
if (our_key_ret)
*our_key_ret = our_key_val;
return 1;
}

View File

@@ -62,9 +62,13 @@ int persist_start_extend(struct cmd_context *cmd, struct volume_group *vg);
int persist_vgcreate_begin(struct cmd_context *cmd, char *vg_name, char *local_key, int local_host_id,
uint32_t set_flags, struct dm_list *devs);
int persist_vgcreate_update(struct cmd_context *cmd, struct volume_group *vg, uint32_t set_flags);
int persist_vgcreate_update(struct cmd_context *cmd, struct volume_group *vg, uint32_t set_flags,
uint64_t *our_key_ret);
int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int may_fail);
int persist_upgrade_ex(struct cmd_context *cmd, struct volume_group *vg, uint64_t *our_key_held);
int persist_upgrade_stop(struct cmd_context *cmd, struct volume_group *vg, uint64_t our_key_val);
int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int may_fail, uint64_t *our_key);
int persist_key_update(struct cmd_context *cmd, struct volume_group *vg, uint32_t prev_gen);

View File

@@ -117,6 +117,41 @@ void lvmlockd_disconnect(void)
_lvmlockd_connected = 0;
}
#define MAX_LOCKARGS 8
/* parse lock_args string for values that may appear in command line --setlockargs */
int lockd_lockargs_get_user_flags(const char *str, uint32_t *flags)
{
char buf[PATH_MAX];
char *argv[MAX_LOCKARGS];
int argc;
int i;
if (!str)
return 0;
dm_strncpy(buf, str, sizeof(buf));
split_line(buf, &argc, argv, MAX_LOCKARGS, ',');
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "persist"))
*flags |= LOCKARGS_PERSIST;
else if (!strcmp(argv[i], "nopersist"))
*flags |= LOCKARGS_NOPERSIST;
else if (!strcmp(argv[i], "timeout"))
*flags |= LOCKARGS_TIMEOUT;
else if (!strcmp(argv[i], "notimeout"))
*flags |= LOCKARGS_NOTIMEOUT;
else {
log_error("Unknown lockargs option value: %s", argv[i]);
return 0;
}
}
return 1;
}
/* Translate the result strings from lvmlockd to bit flags. */
static void _flags_str_to_lockd_flags(const char *flags_str, uint32_t *lockd_flags)
{
@@ -892,7 +927,7 @@ static int _init_vg_idm(struct cmd_context *cmd, struct volume_group *vg)
return _init_vg(cmd, vg, "idm");
}
static int _init_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg, int lv_lock_count)
static int _init_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg, int lv_lock_count, const char *set_args)
{
daemon_reply reply;
const char *reply_str;
@@ -908,9 +943,9 @@ static int _init_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg, in
int ret;
if (!_use_lvmlockd)
return 0;
return_0;
if (!_lvmlockd_connected)
return 0;
return_0;
/*
* We need the sector size to know what size to create the LV,
@@ -1014,6 +1049,7 @@ static int _init_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg, in
"vg_name = %s", vg->name,
"vg_lock_type = %s", "sanlock",
"vg_lock_args = %s", vg->sanlock_lv->name,
"set_lock_args = %s", set_args ?: "none",
"align_mb = " FMTd64, (int64_t) align_size,
"opts = %s", opts ?: "none",
NULL);
@@ -1301,7 +1337,7 @@ static int _free_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg)
/* vgcreate */
int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg,
const char *lock_type, int lv_lock_count)
const char *lock_type, int lv_lock_count, const char *set_args)
{
switch (get_lock_type_from_string(lock_type)) {
case LOCK_TYPE_NONE:
@@ -1311,7 +1347,7 @@ int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg,
case LOCK_TYPE_DLM:
return _init_vg_dlm(cmd, vg);
case LOCK_TYPE_SANLOCK:
return _init_vg_sanlock(cmd, vg, lv_lock_count);
return _init_vg_sanlock(cmd, vg, lv_lock_count, set_args);
case LOCK_TYPE_IDM:
return _init_vg_idm(cmd, vg);
default:
@@ -1437,7 +1473,7 @@ void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg)
* lock the vg, read/use/write the vg, unlock the vg.
*/
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, int *exists)
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, uint64_t our_key, int *exists)
{
char uuid[64] __attribute__((aligned(8)));
const char *opts = NULL;
@@ -1515,6 +1551,7 @@ int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, int *exists
"vg_uuid = %s", uuid[0] ? uuid : "none",
"version = " FMTd64, (int64_t) vg->seqno,
"host_id = " FMTd64, (int64_t) host_id,
"our_key = " FMTd64, (int64_t) our_key,
"opts = %s", opts ?: "none",
NULL);
_lockd_free_pv_list(&lock_pvs);
@@ -1528,6 +1565,7 @@ int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, int *exists
"vg_uuid = %s", uuid[0] ? uuid : "none",
"version = " FMTd64, (int64_t) vg->seqno,
"host_id = " FMTd64, (int64_t) host_id,
"our_key = " FMTd64, (int64_t) our_key,
"opts = %s", opts ?: "none",
NULL);
}
@@ -4231,7 +4269,7 @@ int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int
* Depending on the problem that caused the rename to
* fail, it may make sense to not restart the VG here.
*/
if (!lockd_start_vg(cmd, vg, NULL))
if (!lockd_start_vg(cmd, vg, 0, NULL))
log_error("Failed to restart VG %s lockspace.", vg->name);
return 1;
}
@@ -4271,7 +4309,7 @@ int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int
}
}
if (!lockd_start_vg(cmd, vg, NULL))
if (!lockd_start_vg(cmd, vg, 0, NULL))
log_error("Failed to start VG %s lockspace.", vg->name);
return 1;
@@ -4487,3 +4525,171 @@ void lockd_lockopt_get_flags(const char *str, uint32_t *flags)
log_warn("Ignoring unknown lockopt value: %s", argv[i]);
}
}
int lockd_setlockargs(struct cmd_context *cmd, struct volume_group *vg, const char *set_args, uint64_t *our_key_held)
{
daemon_reply reply;
const char *reply_str;
const char *vg_lock_args = NULL;
uint32_t lockd_flags = 0;
uint32_t lock_args_flags = 0;
int result;
int ret;
if (!_use_lvmlockd) {
log_error("lvmlockd is not in use.");
return 0;
}
if (!_lvmlockd_connected) {
log_error("lvmlockd is not connected.");
return 0;
}
if (!vg->lock_type || strcmp(vg->lock_type, "sanlock")) {
log_error("setlockargs is only supported for lock type sanlock.");
return 0;
}
if (!set_args)
return_0;
if (!lockd_lockargs_get_user_flags(set_args, &lock_args_flags))
return_0;
if ((lock_args_flags & LOCKARGS_PERSIST) && !(vg->pr & VG_PR_REQUIRE)) {
log_error("lockargs \"persist\" requires persistent reservation setting \"require\".");
return 0;
}
/*
* Check if other PR keys are registered, which would
* cause the persist_upgrade_ex below to fail.
*/
if (vg->pr & (VG_PR_REQUIRE | VG_PR_AUTOSTART)) {
struct pv_list *pvl;
struct device *dev;
int key_count;
dm_list_iterate_items(pvl, &vg->pvs) {
if (!(dev = pvl->pv->dev))
continue;
if (dm_list_empty(&dev->aliases))
continue;
if (!dev_find_key(cmd, dev, 0, 0, NULL, 0, NULL, 1, &key_count, NULL)) {
/* Shouldn't happen if persist_is_started already passed. */
log_error("No PR key found on %s.", dev_name(dev));
return 0;
}
if (key_count != 1) {
log_error("Found %d PR keys on %s, stop PR and lockspace on other hosts.", key_count, dev_name(dev));
log_error("(See vgchange --lockstop --persist stop.)");
return 0;
}
}
}
/*
* setlockargs_before checks that sanlock version supports
* the new set_lock_args, checks that no LV locks are held,
* checks we are the only host in the lockspace, and stops
* the lockspace.
*/
log_debug("lockd setlockargs_vg_before %s", vg->name);
reply = _lockd_send("setlockargs_vg_before",
"pid = " FMTd64, (int64_t) getpid(),
"vg_name = %s", vg->name,
"vg_lock_type = %s", vg->lock_type,
"vg_lock_args = %s", vg->lock_args,
"set_lock_args = %s", set_args,
NULL);
if (!_lockd_result(cmd, "setlockargs_vg_before", reply, &result, &lockd_flags, NULL)) {
ret = 0;
goto out;
}
if (result == -EBUSY) {
log_error("Lockspace for \"%s\" not stopped on other hosts", vg->name);
ret = 0;
goto out;
} else if (result < 0) {
log_error("Lockspace setlockargs error %d for \"%s\"", result, vg->name);
ret = 0;
goto out;
}
daemon_reply_destroy(reply);
/*
* When the VG has the ability to use PR, change the
* current PR to an exclusive mode (WE), using a key
* with our host_id and gen 0. The exclusive PR protects
* the VG from other hosts while the locking parameters
* are being changed (since locking can't be used while
* the locking is being changed.) The lockspace is stopped
* while it's being changed. At the end of the vgchange
* setlockargs command, persist_ugprade_stop() releases
* the exclusive PR. After this, any host can do a normal
* start of PR/locking using the new lockargs.
*/
if (vg->pr & (VG_PR_REQUIRE | VG_PR_AUTOSTART)) {
if (!persist_upgrade_ex(cmd, vg, our_key_held)) {
log_error("Failed to upgrade to exclusive PR.");
log_error("Restart PR and locking to retry setlockargs.");
return 0;
}
}
/*
* setlockargs_final reformats sanlock leases on the lvmlock LV.
* The host generation numbers will all be reset back to 0, and
* the PR keys containing the gen will start over from gen 1.
* lvmlockd returns a new lock_args string that this command
* writes in VG metadata.
*/
retry_final:
log_debug("lockd setlockargs_vg_final %s", vg->name);
reply = _lockd_send("setlockargs_vg_final",
"pid = " FMTd64, (int64_t) getpid(),
"vg_name = %s", vg->name,
"vg_lock_type = %s", vg->lock_type,
"vg_lock_args = %s", vg->lock_args,
"set_lock_args = %s", set_args,
NULL);
if (!_lockd_result(cmd, "setlockargs_vg_final", reply, &result, &lockd_flags, NULL)) {
ret = 0;
goto out;
}
if (result == -EAGAIN) {
daemon_reply_destroy(reply);
sleep(1);
goto retry_final;
}
if (!(reply_str = daemon_reply_str(reply, "vg_lock_args", NULL))) {
log_error("VG %s setlockargs failed: result %d new lock_args not returned", vg->name, result);
ret = 0;
goto out;
}
if (!(vg_lock_args = dm_pool_strdup(cmd->mem, reply_str))) {
ret = 0;
goto out;
}
log_debug("lockd setlockargs_vg %s result %d new lock_args %s", vg->name, result, vg_lock_args);
vg->lock_args = vg_lock_args;
ret = 1;
out:
daemon_reply_destroy(reply);
return ret;
}

View File

@@ -14,6 +14,7 @@
#include "libdaemon/client/config-util.h"
#include "libdaemon/client/daemon-client.h"
#include "lib/metadata/metadata-exported.h" /* is_lockd_type() */
#include "daemons/lvmlockd/lvmlockd-client.h"
#define LOCKD_SANLOCK_LV_NAME "lvmlock"
@@ -66,6 +67,7 @@
#ifdef LVMLOCKD_SUPPORT
void lockd_lockopt_get_flags(const char *str, uint32_t *flags);
int lockd_lockargs_get_user_flags(const char *str, uint32_t *flags);
struct lvresize_params;
struct lvcreate_params;
@@ -82,7 +84,8 @@ void lvmlockd_disconnect(void);
/* vgcreate/vgremove use init/free */
int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type, int lv_lock_count);
int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg,
const char *lock_type, int lv_lock_count, const char *set_args);
int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg, int changing, int yes);
void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg);
@@ -93,7 +96,7 @@ int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int
/* start and stop the lockspace for a vg */
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, int *exists);
int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, uint64_t our_key, int *exists);
int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg);
int lockd_start_wait(struct cmd_context *cmd);
int lockd_vg_is_started(struct cmd_context *cmd, struct volume_group *vg, uint32_t *cur_gen);
@@ -142,12 +145,19 @@ void lockd_lvcreate_done(struct cmd_context *cmd, struct volume_group *vg, struc
int lockd_lvremove_lock(struct cmd_context *cmd, struct logical_volume *lv, struct logical_volume **lv_other, int *other_unlock);
void lockd_lvremove_done(struct cmd_context *cmd, struct logical_volume *lv, struct logical_volume *lv_other, int other_unlock);
int lockd_setlockargs(struct cmd_context *cmd, struct volume_group *vg, const char *set_args, uint64_t *our_key_held);
#else /* LVMLOCKD_SUPPORT */
static inline void lockd_lockopt_get_flags(const char *str, uint32_t *flags)
{
}
static inline int lockd_lockargs_get_user_flags(const char *str, uint32_t *flags)
{
return 0;
}
static inline void lvmlockd_set_socket(const char *sock)
{
}
@@ -173,7 +183,8 @@ static inline int lvmlockd_use(void)
return 0;
}
static inline int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg, const char *lock_type, int lv_lock_count)
static inline int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg,
const char *lock_type, int lv_lock_count, const char *set_args)
{
return 1;
}
@@ -345,6 +356,11 @@ static inline int lockd_vg_is_busy(struct cmd_context *cmd, struct volume_group
return 0;
}
static inline int lockd_setlockargs(struct cmd_context *cmd, struct volume_group *vg, const char *set_args, uint64_t *our_key_held)
{
return 0;
}
#endif /* LVMLOCKD_SUPPORT */
#endif /* _LVMLOCKD_H */

View File

@@ -2230,16 +2230,6 @@ static int _validate_lock_args_chars(const char *lock_args)
return r;
}
static int _validate_vg_lock_args(struct volume_group *vg)
{
if (!vg->lock_args || !_validate_lock_args_chars(vg->lock_args)) {
log_error(INTERNAL_ERROR "VG %s has invalid lock_args chars", vg->name);
return 0;
}
return 1;
}
/*
* For lock_type sanlock, LV lock_args are <version>:<info>
* For lock_type dlm, LV lock_args are not used, and lock_args is
@@ -2606,8 +2596,6 @@ int vg_validate(struct volume_group *vg)
r = 0;
}
if (!_validate_vg_lock_args(vg))
r = 0;
} else {
if (vg->lock_args) {
log_error(INTERNAL_ERROR "VG %s has lock_args %s without lock_type",
@@ -5150,7 +5138,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
}
if ((vg->pr & VG_PR_REQUIRE) && (writing || activating) && !cmd->disable_pr_required) {
if (!persist_is_started(cmd, vg, 0)) {
if (!persist_is_started(cmd, vg, 0, NULL)) {
failure |= FAILED_PR_REQUIRED;
goto_bad;
}

View File

@@ -649,6 +649,20 @@ arg(setpersist_ARG, '\0', "setpersist", string_VAL, 0, 0,
"lvmlocal.conf pr_key or host_id must be configured to use PR.\n"
"For local VGs, enabling system_id is also recommended.\n")
arg(setlockargs_ARG, '\0', "setlockargs", string_VAL, 0, 0,
"Add or remove lock_args settings for a shared VG.\n"
"The lock_args determine lock manager behavior for the VG.\n"
"These settings are only allowed for lock_type sanlock.\n"
"persist: use persistent reservations for lock recovery.\n"
"lvmlockd will preempt-abort the persistent reservation of a failed\n"
"lock owner so that the lock can be acquired.\n"
"notimeout: use locks that do not time out when the owner fails.\n"
"In this case, a lock owned by a failed host can only be acquired\n"
"using the persist feature.\n"
"nopersist: do not use the persist feature.\n"
"timeout: do not use the notimeout feature.\n"
"The default behavior with no settings configured is: nopersist and timeout.\n")
arg(removekey_ARG, '\0', "removekey", string_VAL, 0, 0,
"A persistent reservation key to remove.\n")

View File

@@ -1843,6 +1843,11 @@ OO: --select String, --removekey String, --majoritypvs, --force
ID: vgchange_persist
DESC: Perform persistent reservation commands on devices.
vgchange --setlockargs String VG|Tag|Select
OO: --select String
ID: vgchange_setlockargs
DESC: Set or clear lock_args flags to control lock manager behavior.
vgchange --lockstart
OO: --select String, --persist start
OP: VG|Tag|Select ...
@@ -1856,6 +1861,7 @@ ID: vgchange_lockstop
DESC: Stop the lockspace of a shared VG in lvmlockd.
vgchange --locktype LockType VG
OO: --setlockargs String
ID: vgchange_locktype
DESC: Change the lock type for a shared VG.
@@ -1880,7 +1886,7 @@ OO: --addtag Tag, --alloc Alloc, --autobackup Bool, --clustered Bool, --maxlogic
--metadatasize SizeMB, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
--reportformat ReportFmt, --dataalignment SizeKB, --dataalignmentoffset SizeKB,
--shared, --systemid String, --locktype LockType, --setautoactivation Bool,
--setpersist String, --persist start
--setpersist String, --persist start, --setlockargs String
ID: vgcreate_general
---

View File

@@ -90,6 +90,7 @@ static const struct command_function _command_functions[CMD_COUNT] = {
{ vgchange_systemid_CMD, vgchange_systemid_cmd },
{ vgchange_setpersist_CMD, vgchange_setpersist_cmd },
{ vgchange_persist_CMD, vgchange_persist_cmd },
{ vgchange_setlockargs_CMD, vgchange_setlockargs_cmd },
/* lvdisplay variants */
{ lvdisplay_columns_CMD, lvdisplay_columns_cmd },

View File

@@ -521,7 +521,8 @@ int vgcreate_params_set_defaults(struct cmd_context *cmd,
*/
int vgcreate_params_set_from_args(struct cmd_context *cmd,
struct vgcreate_params *vp_new,
struct vgcreate_params *vp_def)
struct vgcreate_params *vp_def,
struct pvcreate_params *pp)
{
const char *system_id_arg_str;
const char *lock_type = NULL;
@@ -736,6 +737,29 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
vp_new->lock_type = lock_type;
log_debug("Setting lock_type to %s", vp_new->lock_type);
if (arg_is_set(cmd, setlockargs_ARG)) {
const char *set_args;
uint32_t lock_args_flags = 0;
if (!lock_type || strcmp(lock_type, "sanlock")) {
log_error("Using setlockargs requires sanlock lock type for shared VG.");
return 0;
}
if (!(set_args = arg_str_value(cmd, setlockargs_ARG, NULL)))
return_0;
if (!lockd_lockargs_get_user_flags(set_args, &lock_args_flags))
return_0;
if (!pp)
return_0;
if ((lock_args_flags & LOCKARGS_PERSIST) && !(pp->setpersist_flags & (SETPR_Y | SETPR_REQUIRE))) {
log_error("Using --setlockargs persist requires --setpersist y|require.");
return 0;
}
}
return 1;
}

View File

@@ -188,7 +188,8 @@ int vgcreate_params_set_defaults(struct cmd_context *cmd,
struct volume_group *vg);
int vgcreate_params_set_from_args(struct cmd_context *cmd,
struct vgcreate_params *vp_new,
struct vgcreate_params *vp_def);
struct vgcreate_params *vp_def,
struct pvcreate_params *pp);
int lv_change_activate(struct cmd_context *cmd, struct logical_volume *lv,
activation_change_t activate);
int lv_refresh(struct cmd_context *cmd, struct logical_volume *lv);

View File

@@ -175,6 +175,7 @@ int vgchange_lock_start_stop_cmd(struct cmd_context *cmd, int argc, char **argv)
int vgchange_systemid_cmd(struct cmd_context *cmd, int argc, char **argv);
int vgchange_setpersist_cmd(struct cmd_context *cmd, int argc, char **argv);
int vgchange_persist_cmd(struct cmd_context *cmd, int argc, char **argv);
int vgchange_setlockargs_cmd(struct cmd_context *cmd, int argc, char **argv);
const struct opt_name *get_opt_name(int opt);
const struct val_name *get_val_name(int val);

View File

@@ -683,6 +683,7 @@ static int _passes_lock_start_filter(struct cmd_context *cmd,
static int _vgchange_lock_start(struct cmd_context *cmd, struct volume_group *vg,
struct vgchange_params *vp)
{
uint64_t our_key = 0;
int auto_opt = 0;
int exists = 0;
int r;
@@ -713,12 +714,12 @@ do_start:
if (!persist_start_include(cmd, vg, 0, auto_opt, NULL))
return 0;
if ((vg->pr & (VG_PR_REQUIRE|VG_PR_AUTOSTART)) && !persist_is_started(cmd, vg, 0)) {
if ((vg->pr & (VG_PR_REQUIRE|VG_PR_AUTOSTART)) && !persist_is_started(cmd, vg, 0, &our_key)) {
log_error("VG %s PR should be started before locking (vgchange --persist start)", vg->name);
return 0;
}
r = lockd_start_vg(cmd, vg, &exists);
r = lockd_start_vg(cmd, vg, our_key, &exists);
if (r)
vp->lock_start_count++;
@@ -1339,7 +1340,7 @@ static int _vgchange_locktype(struct cmd_context *cmd, struct volume_group *vg,
vg->system_id = NULL;
if (!lockd_init_vg(cmd, vg, lock_type, lv_lock_count)) {
if (!lockd_init_vg(cmd, vg, lock_type, lv_lock_count, arg_str_value(cmd, setlockargs_ARG, NULL))) {
log_error("Failed to initialize lock args for lock type %s", lock_type);
return 0;
}
@@ -1879,7 +1880,7 @@ static int _vgchange_setpersist_single(struct cmd_context *cmd, const char *vg_n
* enabling/starting PR, otherwise enabling/starting PR will
* cause i/o to begin failing on those other hosts.
*/
if (on && vg_is_shared(vg) && !persist_is_started(cmd, vg, 1) &&
if (on && vg_is_shared(vg) && !persist_is_started(cmd, vg, 1, NULL) &&
lockd_vg_is_started(cmd, vg, NULL) && lockd_vg_is_busy(cmd, vg)) {
log_error("VG lockspace should be stopped on all hosts (vgchange --lockstop) before enabling PR.");
return ECMD_FAILED;
@@ -1949,3 +1950,51 @@ int vgchange_setpersist_cmd(struct cmd_context *cmd, int argc, char **argv)
return ret;
}
static int _vgchange_setlockargs_single(struct cmd_context *cmd, const char *vg_name,
struct volume_group *vg,
struct processing_handle *handle)
{
const char *set = arg_str_value(cmd, setlockargs_ARG, NULL);
uint64_t our_key_held = 0;
if (!set)
return_ECMD_FAILED;
/*
* lockd_setlockargs gets exclusive PR (if the VG is using PR),
* stops the lockspace, and sets new vg->lock_args that are
* written below. If lockd_setlockargs got the ex PR, then
* persist_upgrade_stop releases the PR.
*/
if (!lockd_setlockargs(cmd, vg, set, &our_key_held))
return_ECMD_FAILED;
if (!vg_write(vg) || !vg_commit(vg))
return_ECMD_FAILED;
if (our_key_held && !persist_upgrade_stop(cmd, vg, our_key_held))
log_warn("Failed to stop PR.");
persist_key_file_remove(cmd, vg);
log_print_unless_silent("Volume group \"%s\" successfully changed.", vg->name);
return ECMD_PROCESSED;
}
int vgchange_setlockargs_cmd(struct cmd_context *cmd, int argc, char **argv)
{
struct processing_handle *handle;
uint32_t flags = READ_FOR_UPDATE;
int ret;
if (!(handle = init_processing_handle(cmd, NULL))) {
log_error("Failed to initialize processing handle.");
return ECMD_FAILED;
}
ret = process_each_vg(cmd, argc, argv, NULL, NULL, flags, 0, handle, &_vgchange_setlockargs_single);
destroy_processing_handle(cmd, handle);
return ret;
}

View File

@@ -46,13 +46,12 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
pp.pv_names = argv;
pp.vg_name = vg_name;
pp.preserve_existing = 1; /* Don't create a new PV on top of an existing PV like pvcreate does. */
pp.check_consistent_block_size = 1;
if (!vgcreate_params_set_defaults(cmd, &vp_def, NULL))
return EINVALID_CMD_LINE;
vp_def.vg_name = vg_name;
if (!vgcreate_params_set_from_args(cmd, &vp_new, &vp_def))
if (!vgcreate_params_set_from_args(cmd, &vp_new, &vp_def, &pp))
return EINVALID_CMD_LINE;
if (!vgcreate_params_validate(cmd, &vp_new))
@@ -161,7 +160,7 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
* a local VG. lockd_init_vg() then writes the VG a second time with
* both lock_type and lock_args set.
*/
if (!lockd_init_vg(cmd, vg, vp_new.lock_type, 0)) {
if (!lockd_init_vg(cmd, vg, vp_new.lock_type, 0, arg_str_value(cmd, setlockargs_ARG, NULL))) {
log_error("Failed to initialize lock args for lock type %s",
vp_new.lock_type);
vg_remove_pvs(vg);
@@ -182,13 +181,15 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
* read without locks until the lockspace is done starting.)
*/
if (vg_is_shared(vg)) {
uint64_t our_key = 0;
if (pp.setpersist_flags &&
!persist_vgcreate_update(cmd, vg, pp.setpersist_flags)) {
!persist_vgcreate_update(cmd, vg, pp.setpersist_flags, &our_key)) {
log_error("Failed to start PR");
goto out;
}
if (!lockd_start_vg(cmd, vg, NULL)) {
if (!lockd_start_vg(cmd, vg, our_key, NULL)) {
log_error("Failed to start locking");
goto out;
}

View File

@@ -609,7 +609,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
goto_bad;
}
vp_def.vg_name = vg_name_to;
if (!vgcreate_params_set_from_args(cmd, &vp_new, &vp_def)) {
if (!vgcreate_params_set_from_args(cmd, &vp_new, &vp_def, NULL)) {
r = EINVALID_CMD_LINE;
goto_bad;
}