mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-10 21:44:27 +03:00
Compare commits
1 Commits
master
...
dev-dct-vg
Author | SHA1 | Date | |
---|---|---|---|
|
813d333e0c |
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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"))
|
||||
|
@@ -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 {
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
21
tools/args.h
21
tools/args.h
@@ -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"
|
||||
|
@@ -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
|
||||
|
||||
---
|
||||
|
111
tools/toollib.c
111
tools/toollib.c
@@ -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.
|
||||
*/
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user