1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-10 21:44:27 +03:00

Compare commits

..

1 Commits

Author SHA1 Message Date
David Teigland
813d333e0c vgcreate: support --setpersist
Previously, setpersist was only supported from vgchange
on an existing VG.  The PR is acquired exclusively before
the devices are modified, and in the case of a shared
VG the PR is subsequently changed to a shared mode.
2025-09-10 13:36:40 -05:00
15 changed files with 505 additions and 64 deletions

View File

@@ -48,7 +48,57 @@ static int get_our_key(struct cmd_context *cmd, struct volume_group *vg,
char *local_key, int local_host_id,
char *ret_key_buf, uint64_t *ret_key_val);
static int dev_allow_pr(struct cmd_context *cmd, struct device *dev)
int setpersist_arg_flags(const char *str, uint32_t *flags)
{
char buf[PATH_MAX];
char *argv[MAX_SETPR_ARGS];
int argc;
int i;
*flags = 0;
if (!str)
return 0;
dm_strncpy(buf, str, sizeof(buf));
split_line(buf, &argc, argv, MAX_SETPR_ARGS, ',');
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "y"))
*flags |= SETPR_Y;
else if (!strcmp(argv[i], "n"))
*flags |= SETPR_N;
else if (!strcmp(argv[i], "require"))
*flags |= SETPR_REQUIRE;
else if (!strcmp(argv[i], "norequire"))
*flags |= SETPR_NOREQUIRE;
else if (!strcmp(argv[i], "autostart"))
*flags |= SETPR_AUTOSTART;
else if (!strcmp(argv[i], "noautostart"))
*flags |= SETPR_NOAUTOSTART;
else if (!strcmp(argv[i], "ptpl"))
*flags |= SETPR_PTPL;
else if (!strcmp(argv[i], "noptpl"))
*flags |= SETPR_NOPTPL;
else {
log_error("Unknown setpersist option value: %s", argv[i]);
return 0;
}
}
if (((*flags & SETPR_Y) && (*flags & SETPR_N)) ||
((*flags & SETPR_REQUIRE) && (*flags & SETPR_NOREQUIRE)) ||
((*flags & SETPR_AUTOSTART) && (*flags & SETPR_NOAUTOSTART)) ||
((*flags & SETPR_PTPL) && (*flags & SETPR_NOPTPL))) {
log_error("Invalid setpersist option combination: %s", str);
return 0;
}
return 1;
}
int dev_allow_pr(struct cmd_context *cmd, struct device *dev)
{
if (dm_list_empty(&dev->aliases))
return 0;
@@ -124,11 +174,11 @@ static int parse_prkey(const char *ptr, uint64_t *prkey)
return 1;
}
void persist_key_file_remove(struct cmd_context *cmd, struct volume_group *vg)
void persist_key_file_remove(struct cmd_context *cmd, const char *vg_name)
{
char path[PATH_MAX] = { 0 };
if (dm_snprintf(path, PATH_MAX-1, "/var/lib/lvm/persist_key_%s", vg->name) < 0)
if (dm_snprintf(path, PATH_MAX-1, "/var/lib/lvm/persist_key_%s", vg_name) < 0)
return;
if (unlink(path))
@@ -240,12 +290,12 @@ static int read_key_file(struct cmd_context *cmd, struct volume_group *vg,
return 1;
}
static int write_key_file(struct cmd_context *cmd, struct volume_group *vg, uint64_t key)
static int write_key_file(struct cmd_context *cmd, const char *vg_name, uint64_t key)
{
char path[PATH_MAX] = { 0 };
FILE *fp;
if (dm_snprintf(path, PATH_MAX-1, "/var/lib/lvm/persist_key_%s", vg->name) < 0)
if (dm_snprintf(path, PATH_MAX-1, "/var/lib/lvm/persist_key_%s", vg_name) < 0)
return 0;
if (!(fp = fopen(path, "w"))) {
@@ -806,7 +856,7 @@ static int get_our_key(struct cmd_context *cmd, struct volume_group *vg,
if (last_host_id != local_host_id) {
log_debug("last key from file: wrong host_id %d vs local %d", last_host_id, local_host_id);
persist_key_file_remove(cmd, vg);
persist_key_file_remove(cmd, vg->name);
goto read_keys;
}
@@ -913,7 +963,7 @@ static int get_our_key_sanlock_start(struct cmd_context *cmd, struct volume_grou
if (last_host_id != local_host_id) {
log_debug("last key from file: wrong host_id %d vs local %d", last_host_id, local_host_id);
persist_key_file_remove(cmd, vg);
persist_key_file_remove(cmd, vg->name);
goto read_keys;
}
@@ -1009,6 +1059,10 @@ int persist_key_update(struct cmd_context *cmd, struct volume_group *vg, uint32_
if (local_key)
return 1;
/* persist_vgcreate_done updates the key */
if (!strcmp(cmd->name, "vgcreate"))
return 1;
/*
* Check if we are using PR on this VG. We don't
* want to update our PR key if we are not already
@@ -1031,15 +1085,6 @@ int persist_key_update(struct cmd_context *cmd, struct volume_group *vg, uint32_
return 1;
}
/*
* In case a previous VG with the same name left
* a key file behind.
*/
if (!strcmp(cmd->name, "vgcreate")) {
persist_key_file_remove(cmd, vg);
return 1;
}
dm_list_iterate_items(pvl, &vg->pvs) {
if (!(dev = pvl->pv->dev))
continue;
@@ -1435,7 +1480,7 @@ int persist_check(struct cmd_context *cmd, struct volume_group *vg,
if (!read_key_file(cmd, vg, NULL, &file_key, NULL, NULL) || (file_key != our_key_val)) {
log_print_unless_silent("updating incorrect key file value 0x%llx to 0x%llx",
(unsigned long long)file_key, (unsigned long long)our_key_val);
if (!write_key_file(cmd, vg, our_key_val))
if (!write_key_file(cmd, vg->name, our_key_val))
log_warn("WARNING: Failed to update key file.");
}
@@ -1674,6 +1719,208 @@ static int _persist_extend_shared(struct cmd_context *cmd, struct volume_group *
return error ? 0 : 1;
}
/*
* Start PR on devices that are being used for vgcreate.
* This is somewhat awkward because it happens early in
* the vgcreate command, before PVs are initialized, and
* before a 'vg' struct exists.
*
* For shared VGs, we use an ex access PR (like local VGs),
* then at the end of vgcreate, in persist_vgcreate_update,
* change the PR sh access (standard for shared VGs.)
*/
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)
{
struct device_list *devl;
uint64_t our_key_val = 0;
char our_key_buf[PR_KEY_BUF_SIZE] = { 0 };
const char *devname;
const char **argv;
int pv_count;
int args;
int status;
persist_key_file_remove(cmd, vg_name);
if (local_key) {
if (!parse_prkey(local_key, &our_key_val)) {
log_error("Failed to parse local key %s", local_key);
return 0;
}
if (dm_snprintf(our_key_buf, PR_KEY_BUF_SIZE-1, "0x%llx", (unsigned long long)our_key_val) < 0)
return_0;
} else if (local_host_id) {
if (dm_snprintf(our_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(our_key_buf, &our_key_val)) {
log_error("Failed to parse generated key %s", our_key_buf);
return 0;
}
}
pv_count = dm_list_size(devs);
log_debug("start PR on %d devs with local key %llx", pv_count, (unsigned long long)our_key_val);
args = 9 + pv_count*2;
if (set_flags & SETPR_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] = our_key_buf;
argv[++args] = "--access";
argv[++args] = "ex";
argv[++args] = "--vg";
argv[++args] = vg_name; /* vg doesn't exist yet, just used for log messages */
if (set_flags & SETPR_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 start failed: lvmpersist command error.");
return 0;
}
return 1;
}
/*
* At the start of creating a shared VG, before writing anything,
* persist_vgcreate_begin() takes an ex access PR on the devices.
* At the end of creating the shared VG (after initializing PVs and
* writing VG metadata), persist_vgcreate_update() removes the ex
* 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)
{
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 our_key_buf_stop[PR_KEY_BUF_SIZE] = { 0 };
uint64_t our_key_val = 0;
const char *access = vg_is_shared(vg) ? "sh" : "ex";
const char *devname;
const char **argv;
int args = 0;
int pv_count;
int status;
int setpersist_on;
setpersist_on = (set_flags & (SETPR_Y | SETPR_REQUIRE | SETPR_AUTOSTART)) ? 1 : 0;
if (!setpersist_on)
return 1;
if (!local_key && local_host_id && vg->lock_type && !strcmp(vg->lock_type, "sanlock")) {
if (dm_snprintf(our_key_buf, PR_KEY_BUF_SIZE-1, "0x100000%06x%04x", 1, local_host_id) != 18) {
log_error("Failed to format key string for host_id %d", local_host_id);
return 0;
}
if (!parse_prkey(our_key_buf, &our_key_val)) {
log_error("Failed to parse generated key %s", our_key_buf);
return 0;
}
} else if (local_key) {
if (!parse_prkey(local_key, &our_key_val)) {
log_error("Failed to parse local key %s", local_key);
return 0;
}
if (dm_snprintf(our_key_buf, PR_KEY_BUF_SIZE-1, "0x%llx", (unsigned long long)our_key_val) < 0)
return_0;
} else if (local_host_id) {
if (dm_snprintf(our_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(our_key_buf, &our_key_val)) {
log_error("Failed to parse generated key %s", our_key_buf);
return 0;
}
}
if (local_key)
memcpy(our_key_buf_stop, our_key_buf, sizeof(our_key_buf));
else if (local_host_id) {
/* The key used in persist_vgcreate_begin did not include gen 1. */
if (dm_snprintf(our_key_buf_stop, 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 (!pv_list_to_dev_list(cmd->mem, &vg->pvs, &devs))
return_0;
pv_count = dm_list_size(&devs);
log_debug("stop PR on %d devs with local key %s", pv_count, our_key_buf_stop);
if (!_run_stop(cmd, vg, &devs, our_key_buf_stop, 0))
log_warn("WARNING: failed to stop PR");
log_debug("start PR on %d devs with local key %llx", pv_count, (unsigned long long)our_key_val);
args = 9 + pv_count*2;
if (set_flags & SETPR_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] = our_key_buf;
argv[++args] = "--access";
argv[++args] = access;
argv[++args] = "--vg";
argv[++args] = vg->name;
if (set_flags & SETPR_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 start failed: lvmpersist command error.");
return 0;
}
/* key file is an optimization, not an error condition */
if (!write_key_file(cmd, vg->name, our_key_val))
stack;
return 1;
}
/*
* Return 1:
* if PR is not in use on existing PVs (so nothing to do here),
@@ -2055,7 +2302,7 @@ int persist_start(struct cmd_context *cmd, struct volume_group *vg,
}
/* key file is an optimization, not an error condition */
if (!write_key_file(cmd, vg, our_key_val))
if (!write_key_file(cmd, vg->name, our_key_val))
stack;
return 1;

View File

@@ -29,6 +29,16 @@
#define PR_TYPE_WEAR 5
#define PR_TYPE_EAAR 6
#define SETPR_Y 0x00000001
#define SETPR_N 0x00000002
#define SETPR_REQUIRE 0x00000004
#define SETPR_NOREQUIRE 0x00000008
#define SETPR_AUTOSTART 0x00000010
#define SETPR_NOAUTOSTART 0x00000020
#define SETPR_PTPL 0x00000040
#define SETPR_NOPTPL 0x00000080
#define MAX_SETPR_ARGS 8
int persist_check(struct cmd_context *cmd, struct volume_group *vg,
char *local_key, int local_host_id);
@@ -49,11 +59,15 @@ int persist_clear(struct cmd_context *cmd, struct volume_group *vg,
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_is_started(struct cmd_context *cmd, struct volume_group *vg, int may_fail);
int persist_key_update(struct cmd_context *cmd, struct volume_group *vg, uint32_t prev_gen);
void persist_key_file_remove(struct cmd_context *cmd, struct volume_group *vg);
void persist_key_file_remove(struct cmd_context *cmd, const char *vg_name);
void persist_key_file_rename(const char *old_name, const char *new_name);
int dev_read_reservation_nvme(struct cmd_context *cmd, struct device *dev, uint64_t *holder_ret, int *prtype_ret);
@@ -70,4 +84,8 @@ int dev_find_key_nvme(struct cmd_context *cmd, struct device *dev, int may_fail,
int vg_is_registered(struct cmd_context *cmd, struct volume_group *vg, uint64_t *our_key_ret, int *partial_ret);
int setpersist_arg_flags(const char *str, uint32_t *flags);
int dev_allow_pr(struct cmd_context *cmd, struct device *dev);
#endif

View File

@@ -1410,7 +1410,7 @@ void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg)
case LOCK_TYPE_CLVM:
break;
case LOCK_TYPE_SANLOCK:
persist_key_file_remove(cmd, vg);
persist_key_file_remove(cmd, vg->name);
break;
case LOCK_TYPE_DLM:
_free_vg_dlm(cmd, vg);
@@ -4428,24 +4428,6 @@ int lockd_lv_refresh(struct cmd_context *cmd, struct lvresize_params *lp)
return 1;
}
static void _split_line(char *buf, int *argc, char **argv, int max_args, char sep)
{
char *p = buf;
int i;
argv[0] = p;
for (i = 1; i < max_args; i++) {
p = strchr(p, sep);
if (!p)
break;
*p++ = '\0';
argv[i] = p;
}
*argc = i;
}
#define MAX_LOCKOPT 16
void lockd_lockopt_get_flags(const char *str, uint32_t *flags)
@@ -4460,7 +4442,7 @@ void lockd_lockopt_get_flags(const char *str, uint32_t *flags)
dm_strncpy(buf, str, sizeof(buf));
_split_line(buf, &argc, argv, MAX_LOCKOPT, ',');
split_line(buf, &argc, argv, MAX_LOCKOPT, ',');
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "force"))

View File

@@ -628,6 +628,8 @@ struct pvcreate_params {
int zero;
force_t force;
unsigned yes;
uint32_t setpersist_flags;
char *vg_name;
/*
* From recovery-specific command line args.
@@ -656,6 +658,7 @@ struct pvcreate_params {
unsigned preserve_existing : 1;
unsigned check_failed : 1;
unsigned check_consistent_block_size : 1;
unsigned start_pr : 1;
};
struct lvresize_params {

View File

@@ -19,6 +19,7 @@
#include "lib/activate/activate.h"
#include "lib/commands/toolcontext.h"
#include "lib/format_text/archiver.h"
#include "lib/device/persist.h"
#include "base/data-struct/radix-tree.h"
struct volume_group *alloc_vg(const char *pool_name, struct cmd_context *cmd,
@@ -650,6 +651,27 @@ int vg_set_lock_type(struct volume_group *vg, const char *lock_type)
return 1;
}
int vg_set_persist(struct volume_group *vg, uint32_t set_flags)
{
if (set_flags & SETPR_Y)
vg->pr = VG_PR_AUTOSTART | VG_PR_REQUIRE;
else if (set_flags & SETPR_N)
vg->pr = 0;
else if (set_flags & SETPR_REQUIRE)
vg->pr |= VG_PR_REQUIRE;
else if (set_flags & SETPR_NOREQUIRE)
vg->pr &= ~VG_PR_REQUIRE;
else if (set_flags & SETPR_AUTOSTART)
vg->pr |= VG_PR_AUTOSTART;
else if (set_flags & SETPR_NOAUTOSTART)
vg->pr &= ~VG_PR_AUTOSTART;
else if (set_flags & SETPR_PTPL)
vg->pr |= VG_PR_PTPL;
else if (set_flags & SETPR_NOPTPL)
vg->pr &= ~VG_PR_PTPL;
return 1;
}
char *vg_attr_dup(struct dm_pool *mem, const struct volume_group *vg)
{
char *repstr;

View File

@@ -183,6 +183,7 @@ uint32_t vg_mda_count(const struct volume_group *vg);
uint32_t vg_mda_used_count(const struct volume_group *vg);
uint32_t vg_mda_copies(const struct volume_group *vg);
int vg_set_mda_copies(struct volume_group *vg, uint32_t mda_copies);
int vg_set_persist(struct volume_group *vg, uint32_t set_flags);
char *vg_profile_dup(const struct volume_group *vg);
void vg_backup_if_needed(struct volume_group *vg);

View File

@@ -323,3 +323,22 @@ int drop_lvname_suffix(char *new_name, const char *name, const char *suffix)
return 1;
}
void split_line(char *buf, int *argc, char **argv, int max_args, char sep)
{
char *p = buf;
int i;
argv[0] = p;
for (i = 1; i < max_args; i++) {
p = strchr(p, sep);
if (!p)
break;
*p++ = '\0';
argv[i] = p;
}
*argc = i;
}

View File

@@ -59,4 +59,6 @@ int is_reserved_lvname(const char *name);
char *first_substring(const char *str, ...);
int drop_lvname_suffix(char *new_name, const char *name, const char *suffix);
void split_line(char *buf, int *argc, char **argv, int max_args, char sep);
#endif

View File

@@ -393,6 +393,26 @@ generation number, in which case the lockstart command will update the key
with the correct value (the generation number is officially determined
during lockstart.)
.P
.SS vgcreate
.P
PR features can be enabled when creating a new VG:
.P
.B vgcreate --setpersist y
.I VG ""
.I PVs
.P
For local VGs,
.B --persist start
can be included to also start PR on the new VG.
.P
Creating new shared VGs with --setpersist works differently.
PR is always started for a new shared VG, even without --persist start.
First, an exclusive PR (typically WE mode) is acquired for the new VG
devices. The devices are then initialized, and the new VG metadata is
written. The exclusive PR is then removed, and a shared PR (typically
WEAR mode) is acquired for normal sharing of the VG. Finally, the VG
lockspace is started.
.P
.SS vgextend
.P
For local VGs, vgextend starts PR on the new devices before adding them to

View File

@@ -624,13 +624,26 @@ arg(persist_ARG, '\0', "persist", string_VAL, 0, 0,
"Use --setpersist to automate and/or require PR.\n")
arg(setpersist_ARG, '\0', "setpersist", string_VAL, 0, 0,
"#vgcreate\n"
"Set flags to control persistent reservation behavior.\n"
"y: set require and autostart flags.\n"
"require: PR will be required to write or activate VG.\n"
"autostart: PR will be automatically started.\n"
"ptpl: use persist through power loss on devices.\n"
"When autostart is enabled, autoactivation and auto-lockstart\n"
"commands will first start PR.\n"
"lvmlocal.conf pr_key or host_id must be configured to use PR.\n"
"For local VGs, enabling system_id is also recommended.\n"
"#vgchange\n"
"Set or clear flags to control persistent reservation behavior.\n"
"autostart: set flag, PR will be automatically started.\n"
"noautostart: clear autostart flag.\n"
"y: set require and autostart flags.\n"
"n: clear require and autostart flags.\n"
"require: set flag, PR will be required to write or activate VG.\n"
"norequire: clear require flag.\n"
"y: set autostart and require flags.\n"
"n: clear autostart and require flags.\n"
"autostart: set flag, PR will be automatically started.\n"
"noautostart: clear autostart flag.\n"
"ptpl: set flag, use persist through power loss on devices.\n"
"noptpl: clear ptpl flag.\n"
"When autostart is enabled, autoactivation and auto-lockstart\n"
"commands will first start PR.\n"
"lvmlocal.conf pr_key or host_id must be configured to use PR.\n"

View File

@@ -1879,7 +1879,8 @@ OO: --addtag Tag, --alloc Alloc, --autobackup Bool, --clustered Bool, --maxlogic
--physicalextentsize SizeMB, --force, --zero Bool, --labelsector Number,
--metadatasize SizeMB, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
--reportformat ReportFmt, --dataalignment SizeKB, --dataalignmentoffset SizeKB,
--shared, --systemid String, --locktype LockType, --setautoactivation Bool
--shared, --systemid String, --locktype LockType, --setautoactivation Bool,
--setpersist String, --persist start
ID: vgcreate_general
---

View File

@@ -5044,6 +5044,35 @@ int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *p
pp->pva.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, pp->pva.ba_size);
if (!strcmp(cmd->name, "vgcreate")) {
int shared_vg = arg_is_set(cmd, shared_ARG);
int setpersist_on;
if (arg_is_set(cmd, setpersist_ARG) &&
!setpersist_arg_flags(arg_str_value(cmd, setpersist_ARG, NULL), &pp->setpersist_flags))
return_0;
setpersist_on = (pp->setpersist_flags & (SETPR_Y | SETPR_REQUIRE | SETPR_AUTOSTART)) ? 1 : 0;
pp->start_pr = arg_is_set(cmd, persist_ARG); /* --persist start is the only permitted option */
if (!shared_vg && arg_is_set(cmd, locktype_ARG)) {
int lock_type_num = get_lock_type_from_string(arg_str_value(cmd, locktype_ARG, NULL));
if (lock_type_num == LOCK_TYPE_SANLOCK || lock_type_num == LOCK_TYPE_DLM)
shared_vg = 1;
}
if (!setpersist_on && shared_vg && pp->start_pr) {
log_error("A shared VG should include --setpersist y|require to use PR.");
return 0;
}
/* Automatic PR start for shared VGs because lockstart is automatic in vgcreate,
and PR start happens before lockstart. */
if (setpersist_on && shared_vg)
pp->start_pr = 1;
}
return 1;
}
@@ -5599,6 +5628,7 @@ int pvcreate_each_device(struct cmd_context *cmd,
unsigned int prev_pbs = 0, prev_lbs = 0;
int must_use_all = (cmd->cname->flags & MUST_USE_ALL_ARGS);
int unlocked_for_prompts = 0;
int setpersist_on;
int found;
unsigned i;
@@ -5974,6 +6004,87 @@ do_command:
else
dm_list_splice(&pp->arg_create, &pp->arg_process);
/*
* It would be nice to not do PR stuff in this function, but
* - it's not nice to do it before this function, because the
* needed list of devs is not available until this function.
* - it's not nice to do it after this function, because if
* PR is unsupported, it's better to fail the command before
* writing the new PVs here. Also, if we're going to use PR,
* it's nicer to get the reservation before writing anything.
*
* Usually, setpersist (writing PR settings in VG metadata)
* is separate from persist start (starting PR on devices).
* Both steps can be optionally combined in one command with:
* --setpersist y --persist start. So,
*
* . vgcreate --setpersist y does not start PR
* . vgcreate --persist start does start PR
* . vgcreate --setpersist y --persist start does start PR
*
* A special case which does not follow this pattern is creating
* a shared VG, where PR is started even without --persist start
* when setpersist is enabled:
*
* . vgcreate --shared --setpersist y does start PR
*
* This case is different because creating a shared VG includes
* automatically starting the VG lockspace. The proper sequence
* of using a shared VG is first starting PR, then starting the
* lockspace. So, to maintain this proper sequence, the vgcreate
* needs to include an automatic PR start prior to the automatic
* lock start.
*
* Creating a shared VG without setpersist, but PR start is
* currently disallowed, because it's not clear if this
* combination would ever be useful.
*
* . vgcreate --shared --persist start disallowed
*/
setpersist_on = (pp->setpersist_flags & (SETPR_Y | SETPR_REQUIRE | SETPR_AUTOSTART)) ? 1 : 0;
if (pp->start_pr || setpersist_on) {
DM_LIST_INIT(devs);
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);
int key_count;
if (!local_key && !local_host_id) {
log_error("A local pr_key or host_id is required to use PR (see lvmlocal.conf).");
return 0;
}
dm_list_iterate_items(pd, &pp->arg_create) {
if (!dev_allow_pr(cmd, pd->dev)) {
log_error("persistent reservation not supported for device type %s", dev_name(pd->dev));
return 0;
}
}
dm_list_iterate_items(pd, &pp->arg_create) {
/* find_key is just being used here to test if the dev supports PR commands. */
if (!dev_find_key(cmd, pd->dev, 1, 0, NULL, 0, NULL, 1, &key_count, NULL)) {
log_error("Failed to access persistent reservation on %s.", dev_name(pd->dev));
return 0;
}
}
if (pp->start_pr) {
dm_list_iterate_items(pd, &pp->arg_create) {
if (!(devl = dm_pool_alloc(cmd->mem, sizeof(*devl))))
return_0;
devl->dev = pd->dev;
dm_list_add(&devs, &devl->list);
}
if (!persist_vgcreate_begin(cmd, pp->vg_name, local_key, local_host_id, pp->setpersist_flags, &devs)) {
log_error("Failed to start persistent reservation.");
return 0;
}
}
}
/*
* Wipe signatures on devices being created.
*/

View File

@@ -1774,21 +1774,21 @@ static int _vgchange_setpersist_single(struct cmd_context *cmd, const char *vg_n
struct volume_group *vg,
struct processing_handle *handle)
{
const char *set = arg_str_value(cmd, setpersist_ARG, NULL);
const char *op = arg_str_value(cmd, persist_ARG, NULL);
char *root_dm_uuid = NULL;
char *local_key;
struct pv_list *pvl;
struct device *dev;
uint32_t set_flags;
int key_count;
int local_host_id;
int start_done = 0;
int on;
if (!set)
if (!setpersist_arg_flags(arg_str_value(cmd, setpersist_ARG, NULL), &set_flags))
return_ECMD_FAILED;
on = !strcmp(set, "y") || !strcmp(set, "require") || !strcmp(set, "autostart");
on = (set_flags & (SETPR_Y | SETPR_REQUIRE | SETPR_AUTOSTART)) ? 1 : 0;
if (on) {
local_key = (char *)find_config_tree_str(cmd, local_pr_key_CFG, NULL);
@@ -1842,26 +1842,22 @@ static int _vgchange_setpersist_single(struct cmd_context *cmd, const char *vg_n
start_done = 1;
}
if (!strcmp(set, "y"))
if (set_flags & SETPR_Y)
vg->pr = VG_PR_AUTOSTART | VG_PR_REQUIRE;
else if (!strcmp(set, "n"))
else if (set_flags & SETPR_N)
vg->pr = 0;
else if (!strcmp(set, "require"))
else if (set_flags & SETPR_REQUIRE)
vg->pr |= VG_PR_REQUIRE;
else if (!strcmp(set, "norequire"))
else if (set_flags & SETPR_NOREQUIRE)
vg->pr &= ~VG_PR_REQUIRE;
else if (!strcmp(set, "autostart"))
else if (set_flags & SETPR_AUTOSTART)
vg->pr |= VG_PR_AUTOSTART;
else if (!strcmp(set, "noautostart"))
else if (set_flags & SETPR_NOAUTOSTART)
vg->pr &= ~VG_PR_AUTOSTART;
else if (!strcmp(set, "ptpl"))
else if (set_flags & SETPR_PTPL)
vg->pr |= VG_PR_PTPL;
else if (!strcmp(set, "noptpl"))
else if (set_flags & SETPR_NOPTPL)
vg->pr &= ~VG_PR_PTPL;
else {
log_error("Invalid setpersist value.");
return_ECMD_FAILED;
}
if (!vg_write(vg) || !vg_commit(vg)) {
if (start_done) {

View File

@@ -14,6 +14,7 @@
*/
#include "tools.h"
#include "lib/device/persist.h"
int vgcreate(struct cmd_context *cmd, int argc, char **argv)
{
@@ -43,10 +44,8 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
pp.pv_count = argc;
pp.pv_names = argv;
/* Don't create a new PV on top of an existing PV like pvcreate does. */
pp.preserve_existing = 1;
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))
@@ -118,6 +117,7 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
!vg_set_max_pv(vg, vp_new.max_pv) ||
!vg_set_alloc_policy(vg, vp_new.alloc) ||
!vg_set_system_id(vg, vp_new.system_id) ||
!vg_set_persist(vg, pp.setpersist_flags) ||
!vg_set_mda_copies(vg, vp_new.vgmetadatacopies))
goto_bad;
@@ -181,6 +181,12 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
* read without locks until the lockspace is done starting.)
*/
if (vg_is_shared(vg)) {
if (pp.setpersist_flags &&
!persist_vgcreate_update(cmd, vg, pp.setpersist_flags)) {
log_error("Failed to start PR");
goto out;
}
if (!lockd_start_vg(cmd, vg, NULL)) {
log_error("Failed to start locking");
goto out;

View File

@@ -95,7 +95,7 @@ static int _vgremove_single(struct cmd_context *cmd, const char *vg_name,
if (pr_stop) {
if (!persist_stop_run(cmd, vg, &pr_devs, pr_key))
log_warn("WARNING: persistent reservation not removed from devices.");
persist_key_file_remove(cmd, vg);
persist_key_file_remove(cmd, vg->name);
}
return ECMD_PROCESSED;