1
0
mirror of git://sourceware.org/git/lvm2.git synced 2026-02-10 08:32:46 +03:00

Compare commits

..

15 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
David Teigland
687b1a780f persist: support --setpersist in vgcreate
Previously, setpersist was only supported in 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-17 15:46:54 -05:00
David Teigland
57bf48c058 persist: use vgid in the key file name
adding a new helper function to create key file path.

Including vgid protects against cases of reading a
stale key file that was left over from a previous VG
with the same name.
2025-09-17 12:28:30 -05:00
David Teigland
ab1405034d persist: vgremove should check for other keys
vgremove should check for keys registered by other hosts
before removing the VG to avoid leaving dangling PR keys
on devices.  This involves refactoring the related commit
ca6fe99162 "lvmpersist: fix vgremove when another key is registered"
that separated persist_stop into before and after parts.
2025-09-17 11:38:08 -05:00
Peter Rajnoha
1f18ee1388 scripts: lvresize-fs-helper.sh: logmsg and not fail if unable to get XFS mount options for remount 2025-09-17 14:36:48 +02:00
Peter Rajnoha
f5852f2c9e WHATS_NEW: update 2025-09-17 12:16:26 +02:00
Peter Rajnoha
b6df5bf9d6 tests: lvresize-xfs: test quota mount options are preserved 2025-09-17 11:57:12 +02:00
Peter Rajnoha
55fda3afa5 scripts: lvresize-fs-helper.sh: detect and use proper quota mount options for XFS
When an XFS file system was previously mounted with quota mount options
(combination of -o uquota,gquota,pgquota) and then we are mounting the
file system as part of the lvresize/lvextend operation (through the fs
resize helper script), we need to preserve the quota mount options.

Otherwise, the XFS would need to recheck quotas - in that case the kernel
log contains:

  XFS (<device>): Quotacheck needed: Please wait.

This may take a long time, depending on the file system size.

Related issue: https://github.com/lvmteam/lvm2/issues/182
2025-09-17 11:57:02 +02:00
Arnout Engelen
6013977043 man: simplify vmautoactivation(7)
Previously this was hard-coded to: "Autoactivation commands use a number
of temp files in /run/lvm (with the expectation that /run is cleared
between boots.)"

Since c1bfc8737f it was made more generic,
but on some systems this logic leads to "Autoactivation commands use a
number of temp files in /run/lvm (with the expectation that /var/run
is cleared between boots)." which I'd say adds more confusion than it
solves.
2025-09-16 15:31:26 +00:00
David Teigland
b4a49811cd persist: fix start/stop with vgchange ay/an
vgchange -ay --persist start
	wasn't working, and should exclude shared VGs.
vgchange -an --persist stop
	code was missing for this case.
2025-09-12 15:20:42 -05:00
Zdenek Kabelac
09ceb425b7 make: generate 2025-09-12 14:23:35 +02:00
Zdenek Kabelac
fb708004fe man: print better arg for persist
As man pages now tend to print options as man macro reference,
we may still need some local 'specialization'.

ATM --persist option is known expection where command may accept only
certain argument to be recognized/allowed - so generic String printed
in Italic can be replaced with just specific argument printed in Bold.

TODO: recognize only cases where the 'generic' String is NOT used and
for rest of them use the common O_persist macro reference.
2025-09-12 14:23:14 +02:00
Zdenek Kabelac
b9e6337f04 codespell: typos 2025-09-11 16:18:19 +02:00
Marian Csontos
edd8b52967 doc: Few fixes and additions in pages
(cherry picked from commit 4561756bda8a0b5417c7cf5df269bb37af6eaec5)
2025-09-11 16:12:39 +02:00
David Teigland
58c534ba57 lvmpersist: fix remove exit code if an invalid local key is specified
Exit with an error if the wrong local key is specified.
2025-09-10 15:56:45 -05:00
22 changed files with 301 additions and 89 deletions

View File

@@ -1,5 +1,6 @@
Version 2.03.36 -
==================
Detect and use existing XFS quota mount options for lvresize --fs resize.
Version 2.03.35 - 09th September 2025
=====================================

View File

@@ -39,7 +39,7 @@ local {
# system_id = ""
# Configuration option local/pr_key.
# The local persistent reservation key in hexidecimal.
# The local persistent reservation key in hexadecimal.
# The value must be unique among all hosts using the same VG.
# The max length is 16 hex characters (8 bytes), plus an optional
# 0x prefix. If pr_key is not set, host_id will be used to create a key.

View File

@@ -182,10 +182,10 @@ static int listen_fd;
static int restart_pi;
static int restart_fds[2];
static int helper_send_fd; /* main loop sends requests to helper */
static int helper_recv_fd; /* main loop receives results from helper */
static int helper_pid;
static int helper_pi;
static int helper_send_fd = -1; /* main loop sends requests to helper */
static int helper_recv_fd = -1; /* main loop receives results from helper */
static int helper_pid = -1;
static int helper_pi = -1;
static uint32_t helper_msg_id = 1;
/*
@@ -3013,11 +3013,6 @@ static void *lockspace_thread_main(void *arg_in)
/* return success, allow the change */
/* list_del act and add_client_result done after rem_lockspace */
/*
list_del(&act->list);
act->result = 0;
add_client_result(act);
*/
/* the lockspace needs to be stopped for setlockargs_final */
ls->thread_work = 0;
@@ -4265,9 +4260,14 @@ static void work_fence(struct action *act, int *retry)
if (!found_done && !found_busy) {
rv = send_helper_request(act, ls_name, new_msg_id);
if (rv < 0) {
/* TODO: change act to FENCE_RESULT with error and move it to ls->actions */
/* change act to FENCE_RESULT error and move it to ls->actions */
log_error("work_fence %s failed to send helper request %u", vg_name, new_msg_id);
free_action(act);
pthread_mutex_lock(&ls->mutex);
list_del(&act->list);
act->op = LD_OP_FENCE_RESULT;
act->result = -ENOTCONN;
list_add_tail(&act->list, &ls->actions);
pthread_mutex_unlock(&ls->mutex);
}
}
pthread_mutex_unlock(&lockspaces_mutex);

View File

@@ -72,6 +72,7 @@ incorrectly!
Make one by running `pvcreate /dev/sdX`.
See [pvcreate(8)](https://man7.org/linux/man-pages/man8/pvcreate.8.html). This step is optional.
* Volume Group (VG) consisting of one or more PVs is used as a pool from which LVs are allocated.
List VGs using [vgs(8)](https://man7.org/linux/man-pages/man8/vgs.8.html) or
[vgdisplay(8)](https://man7.org/linux/man-pages/man8/vgdisplay.8.html).
@@ -80,27 +81,34 @@ incorrectly!
To use LVM at least one Volume Group must be present on the system.
See [vgcreate(8)](https://man7.org/linux/man-pages/man8/vgcreate.8.html), and
[vgextend(8)](https://man7.org/linux/man-pages/man8/vgextend.8.html).
* Logical Volume (LV) is the block device usually visible to user to be used for file system.
List PVs using [lvs(8)](https://man7.org/linux/man-pages/man8/lvs.8.html) or
List LVs using [lvs(8)](https://man7.org/linux/man-pages/man8/lvs.8.html) or
[lvdisplay(8)](https://man7.org/linux/man-pages/man8/lvdisplay.8.html).
Make one by running `lvcreate [-n LVNAME] -L SIZE VGNAME`, and you are done!
See [vgcreate(8)](https://man7.org/linux/man-pages/man8/vgcreate.8.html).
See [lvcreate(8)](https://man7.org/linux/man-pages/man8/lvcreate.8.html).
To change size of LV it is recommended to use [lvresize(8)](https://man7.org/linux/man-pages/man8/lvresize.8.html) with `--resizefs` option.
To change properties of LV (e.g. to acivate/deactivate a volume, or change it to read only) use [lvchange(8)](https://man7.org/linux/man-pages/man8/lvchange.8.html).
To change the type of LV (e.g. change a linear volume to a RAID) use [lvconvert(8)](https://man7.org/linux/man-pages/man8/lvconvert.8.html).
## Avoiding Problems
Good start is to avoid using `{--force|-f}` and `{--yes|-y}` options which are
Good start is to **avoid using `{--force|-f}` and `{--yes|-y}` options** which are
often seen on internet discussions.
there is a possibility of data loss, LVM tools usually ask, so read the prompts
carefully! Using `--yes` removes these safety.
Also in some cases where it is too dangerous to proceed, e.g. device is used,
LVM refuses to do so, which can be overridden by `--force`.
Second, when resizing and especially when shrinking LVs it is always a good
idea to use `--resizefs` option which ensures the devices are resized in
Second, when **resizing** and especially when shrinking LVs it is always a good
idea to **use `--resizefs` option** which ensures the devices are resized in
correct order.
Third, if you still make a mess, never ever run fsck on damaged LV/FS, this is
Third, if you still make a mess, **never ever run fsck on damaged LV/FS**, this is
usually the final blow to your data. It is always better to ask first!

View File

@@ -2280,7 +2280,7 @@ cfg(local_system_id_CFG, "system_id", local_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_D
"#\n")
cfg(local_pr_key_CFG, "pr_key", local_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, 0, vsn(2, 3, 32), NULL, 0, NULL,
"The local persistent reservation key in hexidecimal.\n"
"The local persistent reservation key in hexadecimal.\n"
"The value must be unique among all hosts using the same VG.\n"
"The max length is 16 hex characters (8 bytes), plus an optional\n"
"0x prefix. If pr_key is not set, host_id will be used to create a key.\n")

View File

@@ -1056,7 +1056,7 @@ static int get_our_key_sanlock_start(struct cmd_context *cmd, struct volume_grou
/*
* Called after sanlock lockstart to check if a registered PR key contains the
* latest generation number (from sanlock) for the host, and if not to update
* the PR key. The sanlock lockstart atually returns the previous generation
* the PR key. The sanlock lockstart actually returns the previous generation
* number that was used for this host_id in the lockspace, and we expect that
* the next generation number just will be +1.
*
@@ -1572,23 +1572,78 @@ static int _run_stop(struct cmd_context *cmd, struct volume_group *vg, struct dm
}
/*
* Separate persist_stop_prepare() and persist_stop_run() is needed
* for vgremove, where prepare is needed before the normal vgremove,
* and run should happen after the normal vgremove.
* - prepare cannot happen after normal vgremove, because the list
* For vgremove, separate persist_stop into before and after parts:
* - before cannot happen after normal vgremove, because the list
* of PVs is no longer available.
* - run cannot happen before normal vgremove, because removing the
* - after cannot happen before normal vgremove, because removing the
* reservation will prevent writing metadata for normal vgremove if
* another host has a PR key registered (which may not happen in the
* normal usage pattern, but is still possible.)
*/
int persist_stop_prepare(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char **key)
int persist_vgremove_before(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char **key)
{
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 };
uint64_t our_key_val = 0;
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;
/*
* When removing a shared VG, verify that other hosts
* have stopped PR to avoid leaving dangling reservations.
*/
if (vg_is_shared(vg)) {
struct pv_list *pvl;
struct device *dev;
int found_key_count;
dm_list_iterate_items(pvl, &vg->pvs) {
if (!(dev = pvl->pv->dev))
continue;
found_key_count = 0;
if (!dev_find_key(cmd, dev, 0, 0, NULL, 0, NULL, 1, &found_key_count, NULL)) {
/* shouldn't happen */
log_error("Failed to get PR keys from %s", dev_name(dev));
return 0;
}
if (found_key_count > 1) {
log_error("Found %d PR keys on %s", found_key_count, dev_name(dev));
log_error("Stop PR for VG %s on other hosts (vgchange --persist stop)", vg->name);
return 0;
}
}
}
if (!pv_list_to_dev_list(cmd->mem, &vg->pvs, devs))
return_0;
if (!(*key = dm_pool_strdup(cmd->mem, our_key_buf)))
return_0;
return 1;
}
void persist_vgremove_after(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char *key)
{
_run_stop(cmd, vg, devs, key, 0);
persist_key_file_remove(cmd, vg);
}
int persist_stop(struct cmd_context *cmd, struct volume_group *vg)
{
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);
char our_key_buf[PR_KEY_BUF_SIZE] = { 0 };
uint64_t our_key_val = 0;
uint32_t cur_gen = 0;
if (!local_key && !local_host_id)
@@ -1602,34 +1657,15 @@ int persist_stop_prepare(struct cmd_context *cmd, struct volume_group *vg, struc
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))
if (!pv_list_to_dev_list(cmd->mem, &vg->pvs, &devs))
return_0;
if (!(*key = dm_pool_strdup(cmd->mem, our_key_buf)))
if (!_run_stop(cmd, vg, &devs, our_key_buf, 0))
return_0;
return 1;
}
int persist_stop_run(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char *key)
{
if (!_run_stop(cmd, vg, devs, key, 0))
return_0;
return 1;
}
int persist_stop(struct cmd_context *cmd, struct volume_group *vg)
{
DM_LIST_INIT(devs);
char *key = NULL;
if (!persist_stop_prepare(cmd, vg, &devs, &key))
return_0;
if (!persist_stop_run(cmd, vg, &devs, key))
return_0;
return 1;
}
static int _persist_extend_shared(struct cmd_context *cmd, struct volume_group *vg,
uint64_t our_key_val, struct device *check_dev)
{
@@ -1965,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;
@@ -2032,7 +2069,7 @@ int persist_vgcreate_update(struct cmd_context *cmd, struct volume_group *vg, ui
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_warn("WARNING: failed to stop PR with key %s", our_key_buf_stop);
log_debug("start PR on %d devs with local key %llx", pv_count, (unsigned long long)our_key_val);
@@ -2073,6 +2110,9 @@ int persist_vgcreate_update(struct cmd_context *cmd, struct volume_group *vg, ui
if (!write_key_file(cmd, vg, our_key_val))
stack;
if (our_key_ret)
*our_key_ret = our_key_val;
return 1;
}

View File

@@ -48,8 +48,9 @@ int persist_start(struct cmd_context *cmd, struct volume_group *vg,
char *local_key, int local_host_id, const char *remkey);
int persist_stop(struct cmd_context *cmd, struct volume_group *vg);
int persist_stop_prepare(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char **key);
int persist_stop_run(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char *key);
int persist_vgremove_before(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char **key);
void persist_vgremove_after(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char *key);
int persist_remove(struct cmd_context *cmd, struct volume_group *vg,
char *local_key, int local_host_id, const char *remkey);
@@ -61,7 +62,8 @@ 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_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);

View File

@@ -1446,7 +1446,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->name);
persist_key_file_remove(cmd, vg);
break;
case LOCK_TYPE_DLM:
_free_vg_dlm(cmd, vg);

View File

@@ -341,4 +341,3 @@ void split_line(char *buf, int *argc, char **argv, int max_args, char sep)
}
*argc = i;
}

View File

@@ -175,9 +175,7 @@ is reserved for udev output.)
.
Autoactivation commands use a number of temp files in
.I #DEFAULT_RUN_DIR#
(with the expectation that
.I #DEFAULT_PID_DIR#
is cleared between boots).
(with the expectation that it is cleared between boots).
.
.TP
.B pvs_online

View File

@@ -258,7 +258,7 @@ Display the settings.
.P
.SS VG PR commands
.P
vgchange --persist is used to perfom PR operations on the VG's devices.
vgchange --persist is used to perform PR operations on the VG's devices.
.P
.B vgchange --persist start
.I VG

View File

@@ -609,7 +609,7 @@ Activate or deactivate LVs.
]
.br
[
.O_persist
\fB--persist\fP \fBstart\fP
]
.br
[
@@ -698,7 +698,7 @@ Change the system ID of a VG.
]
.br
[
.O_persist
\fB--persist\fP \fIString\fP
]
.br
[
@@ -723,7 +723,7 @@ Set or clear flags to control persistent reservation behavior.
]
.br
[
.O_persist
\fB--persist\fP \fBstart\fP
]
.br
[ COMMON_OPTIONS ]
@@ -772,7 +772,7 @@ Start the lockspace of a shared VG in lvmlockd.
]
.br
[
.O_persist
\fB--persist\fP \fBstart\fP
]
.br
[ COMMON_OPTIONS ]
@@ -794,7 +794,7 @@ Stop the lockspace of a shared VG in lvmlockd.
]
.br
[
.O_persist
\fB--persist\fP \fBstop\fP
]
.br
[ COMMON_OPTIONS ]

View File

@@ -162,7 +162,7 @@ Export specified VGs.
]
.br
[
.O_persist
\fB--persist\fP \fBstop\fP
]
.br
[ COMMON_OPTIONS ]

View File

@@ -152,7 +152,7 @@ Import specified VGs.
]
.br
[
.O_persist
\fB--persist\fP \fBstart\fP
]
.br
[ COMMON_OPTIONS ]

View File

@@ -866,6 +866,7 @@ do_remove() {
for dev in "${DEVICES[@]}"; do
if ! key_is_on_device "$dev" "$OURKEY" ; then
logmsg "cannot remove $REMKEY from $dev without ourkey $OURKEY being registered"
err=1
continue
fi

View File

@@ -19,6 +19,11 @@ errorexit() {
exit 1
}
logerror() {
echo "$1" >&2
logger "${SCRIPTNAME}: $1"
}
logmsg() {
echo "$1"
logger "${SCRIPTNAME}: $1"
@@ -68,6 +73,72 @@ TMP_MOUNT_DONE=0
# Set to 1 if the fs resize command fails
RESIZEFS_FAILED=0
# Function to detect XFS mount options
detect_xfs_mount_options() {
local device=$1
local qflags_output qflags_hex
MOUNT_OPTIONS=""
# Get quota flags using xfs_db.
if ! qflags_output=$(xfs_db -r "$device" -c 'sb 0' -c 'p qflags'); then
logerror "xfs_db failed"
return 1
fi
# Extract the hex value from output that is in format "qflags = 0x<hex_number>".
qflags_hex="${qflags_output#qflags = }"
# No flags set, no extra mount options needed.
if [[ "$qflags_hex" == "0" ]]; then
return 0
fi
if [[ ! "$qflags_hex" =~ ^0x[0-9a-fA-F]+$ ]]; then
logerror "xfs_db unexpected output"
return 1
fi
# Check XFS quota flags and set MOUNT_OPTIONS appropriately
# The quota flags as defined in Linux kernel source: fs/xfs/libxfs/xfs_log_format.h:
# XFS_UQUOTA_ACCT = 0x0001
# XFS_UQUOTA_ENFD = 0x0002
# XFS_GQUOTA_ACCT = 0x0040
# XFS_GQUOTA_ENFD = 0x0080
# XFS_PQUOTA_ACCT = 0x0008
# XFS_PQUOTA_ENFD = 0x0200
if [ $(($qflags_hex & 0x0001)) -ne 0 ]; then
if [ $(($qflags_hex & 0x0002)) -ne 0 ]; then
MOUNT_OPTIONS="${MOUNT_OPTIONS}uquota,"
else
MOUNT_OPTIONS="${MOUNT_OPTIONS}uqnoenforce,"
fi
fi
if [ $(($qflags_hex & 0x0040)) -ne 0 ]; then
if [ $(($qflags_hex & 0x0080)) -ne 0 ]; then
MOUNT_OPTIONS="${MOUNT_OPTIONS}gquota,"
else
MOUNT_OPTIONS="${MOUNT_OPTIONS}gqnoenforce,"
fi
fi
if [ $(($qflags_hex & 0x0008)) -ne 0 ]; then
if [ $(($qflags_hex & 0x0200)) -ne 0 ]; then
MOUNT_OPTIONS="${MOUNT_OPTIONS}pquota,"
else
MOUNT_OPTIONS="${MOUNT_OPTIONS}pqnoenforce,"
fi
fi
# Trim trailing comma
MOUNT_OPTIONS="${MOUNT_OPTIONS%,}"
if [[ -n "$MOUNT_OPTIONS" ]]; then
logmsg "mount options for xfs: ${MOUNT_OPTIONS}"
fi
}
fsextend() {
if [ "$DO_UNMOUNT" -eq 1 ]; then
logmsg "unmount ${MOUNTDIR}"
@@ -98,7 +169,7 @@ fsextend() {
fi
fi
fi
if [ "$DO_CRYPTRESIZE" -eq 1 ]; then
logmsg "cryptsetup resize ${DEVPATH}"
if cryptsetup resize "$DEVPATH"; then
@@ -110,8 +181,12 @@ fsextend() {
fi
if [ "$DO_MOUNT" -eq 1 ]; then
if [[ "$FSTYPE" == "xfs" ]]; then
detect_xfs_mount_options "$DEVPATH" || logmsg "not using XFS mount options"
fi
logmsg "mount ${DEVPATH} ${TMPDIR}"
if mount -t "$FSTYPE" "$DEVPATH" "$TMPDIR"; then
if mount -t "$FSTYPE" ${MOUNT_OPTIONS:+-o "$MOUNT_OPTIONS"} "$DEVPATH" "$TMPDIR"; then
logmsg "mount done"
TMP_MOUNT_DONE=1
else
@@ -170,8 +245,12 @@ fsextend() {
# If the fs was temporarily unmounted, now remount it.
# Not considered a command failure if this fails.
if [[ $DO_UNMOUNT -eq 1 && $REMOUNT -eq 1 ]]; then
if [[ "$FSTYPE" == "xfs" ]]; then
detect_xfs_mount_options "$DEVPATH" || logmsg "not using XFS mount options"
fi
logmsg "remount ${DEVPATH} ${MOUNTDIR}"
if mount -t "$FSTYPE" "$DEVPATH" "$MOUNTDIR"; then
if mount -t "$FSTYPE" ${MOUNT_OPTIONS:+-o "$MOUNT_OPTIONS"} "$DEVPATH" "$MOUNTDIR"; then
logmsg "remount done"
else
logmsg "remount failed"
@@ -384,6 +463,9 @@ DO_FSCK=0
# mounted and the script unmounted it.
REMOUNT=0
# Initialize MOUNT_OPTIONS to ensure clean state
MOUNT_OPTIONS=""
if [ "$UID" != 0 ] && [ "$EUID" != 0 ]; then
errorexit "${SCRIPTNAME} must be run as root."
fi

View File

@@ -89,12 +89,24 @@ check lv_field $vg/$lv lv_size "380.00m"
df --output=size "$mount_dir" |tee df2
not diff df1 df2
# lvextend, xfs, active, not mounted, quotas defined, --fs resize
umount "$mount_dir"
mount -o uquota,gquota,pquota "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
umount "$mount_dir"
lvextend -y --fs resize -L+10M $vg/$lv | tee out
grep "mount options for xfs: uquota,gquota,pquota" out # must preserve the mount options!
# lvextend, xfs, active, not mounted, quotas not defined, --fs resize
mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
umount "$mount_dir"
lvextend -y --fs resize -L+10M $vg/$lv | tee out
not grep "mount options for xfs" out # mount options not needed
lvchange -an $vg/$lv
# lvextend, xfs, inactive, --fs ignore
lvextend --fs ignore -L+20M $vg/$lv
check lv_field $vg/$lv lv_size "400.00m"
check lv_field $vg/$lv lv_size "420.00m"
lvremove -f $vg/$lv

View File

@@ -1815,7 +1815,7 @@ DESC: Start or stop processing LV conversions.
vgchange --activate Active
OO: --activationmode ActivationMode, --ignoreactivationskip, --partial, --sysinit,
--readonly, --ignorelockingfailure, --monitor Bool, --poll Bool,
--autoactivation String, --persist start, OO_VGCHANGE
--autoactivation String, --persist String, OO_VGCHANGE
OP: VG|Tag|Select ...
IO: --ignoreskippedcluster
ID: vgchange_activate

View File

@@ -691,7 +691,22 @@ static void _print_man_usage(char *lvmname, struct command *cmd)
if (_is_lvm_all_opt(opt_enum))
continue;
_print_bracket_ds_opt_name(opt_enum);
switch (opt_enum) {
case persist_ARG:
/* --persist may require specific argument (printed in bold) */
printf("[\n");
_print_man_option(cmd->name, opt_enum);
if (cmd->optional_opt_args[oo].def.val_bits) {
printf(" ");
_print_def_man(cname, opt_enum, &cmd->optional_opt_args[oo].def, 1, NULL);
}
printf("\n]\n");
break;
default:
_print_bracket_ds_opt_name(opt_enum);
}
printf(".br\n");
}

View File

@@ -205,6 +205,7 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
const struct lv_list *lvl;
struct pv_list *pvl;
int do_activate = is_change_activating(activate);
const char *pr_op = NULL;
/*
* We can get here in the odd case where an LV is already active in
@@ -233,8 +234,23 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
}
}
if (do_activate && !persist_start_include(cmd, vg, (activate == CHANGE_AAY), 0, NULL))
return 0;
if (arg_is_set(cmd, persist_ARG))
pr_op = arg_str_value(cmd, persist_ARG, NULL);
/*
* vgchange -ay --persist start
* This command bypasses the persist_is_started check in vg_read (disable_pr_required.)
* It is not permitted for shared VGs, where PR start happens before lockstart.
* For non-shared VGs, require a successful persist_start() here before activating.
*/
if (do_activate && pr_op && !strcmp(pr_op, "start") && cmd->disable_pr_required) {
if (vg_is_shared(vg)) {
log_error("Activation with persist start not permitted for shared VG %s.", vg->name);
return 0;;
}
if (!persist_start_include(cmd, vg, (activate == CHANGE_AAY), 0, NULL))
return_0;
}
/*
* Safe, since we never write out new metadata here. Required for
@@ -284,6 +300,18 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
r = 0;
}
if (!do_activate && pr_op && !strcmp(pr_op, "stop")) {
/* For a shared VG, PR stop happens after lockstop. */
if (vg_is_shared(vg))
log_warn("WARNING: skipping persist stop for shared VG.");
else if (lvs_in_vg_activated(vg))
log_warn("WARNING: skipping persist stop for incomplete deactivation.");
else if (!persist_stop(cmd, vg)) {
log_error("Failed to stop persistent reservation.");
r = 0;
}
}
/*
* Possibly trigger auto-generation of system.devices:
* - if root_dm_uuid contains vg->id, and
@@ -1100,10 +1128,37 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
if (noupdate)
cmd->ignore_device_name_mismatch = 1;
/* Allow LVs to be deactivated without PR started. */
if (arg_is_set(cmd, activate_ARG) &&
!is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
cmd->disable_pr_required = 1;
/*
* PR usage with activation/deactivation.
*/
if (arg_is_set(cmd, activate_ARG)) {
int is_activating = is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY));
/* Always allow deactivation without PR being started. */
if (!is_activating)
cmd->disable_pr_required = 1;
/* Either "-ay --persist start", or "-an --persist stop". */
if (arg_is_set(cmd, persist_ARG)) {
const char *pr_op = arg_str_value(cmd, persist_ARG, NULL);
if (strcmp(pr_op, "start") && strcmp(pr_op, "stop")) {
log_error("Invalid --persist usage.");
return ECMD_FAILED;
}
if ((!strcmp(pr_op, "start") && !is_activating) ||
(!strcmp(pr_op, "stop") && is_activating)) {
log_error("Invalid --persist usage.");
return ECMD_FAILED;
}
/*
* Setting disable_pr_required to bypass the
* persist_is_started check in vg_read requires
* persist_start in vgchange_activate.
*/
if (!strcmp(pr_op, "start") && is_activating)
cmd->disable_pr_required = 1;
}
}
/*
* If the devices file includes PVs stacked on LVs, then

View File

@@ -117,8 +117,8 @@ 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))
!vg_set_mda_copies(vg, vp_new.vgmetadatacopies) ||
!vg_set_persist(vg, pp.setpersist_flags))
goto_bad;
if (arg_is_set(cmd, setautoactivation_ARG) && !arg_int_value(cmd, setautoactivation_ARG, 1))
@@ -181,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, 0, NULL)) {
if (!lockd_start_vg(cmd, vg, our_key, NULL)) {
log_error("Failed to start locking");
goto out;
}

View File

@@ -74,6 +74,9 @@ static int _vgremove_single(struct cmd_context *cmd, const char *vg_name,
!lvremove_single(cmd, vg->pool_metadata_spare_lv, &void_handle))
return_ECMD_FAILED;
if (pr_stop && !persist_vgremove_before(cmd, vg, &pr_devs, &pr_key))
return_ECMD_FAILED;
if (!lockd_free_vg_before(cmd, vg, 0, arg_count(cmd, yes_ARG)))
return_ECMD_FAILED;
@@ -82,9 +85,6 @@ static int _vgremove_single(struct cmd_context *cmd, const char *vg_name,
online_vgremove(vg);
if (pr_stop && !persist_stop_prepare(cmd, vg, &pr_devs, &pr_key))
return_ECMD_FAILED;
vg_remove_pvs(vg);
if (!vg_remove(vg))
@@ -92,11 +92,8 @@ static int _vgremove_single(struct cmd_context *cmd, const char *vg_name,
lockd_free_vg_final(cmd, vg);
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->name);
}
if (pr_stop)
persist_vgremove_after(cmd, vg, &pr_devs, pr_key);
return ECMD_PROCESSED;
}