Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=9714f3ec4f3d4526a3378…
Commit: 9714f3ec4f3d4526a33781baf706c24930b6f26c
Parent: 2359023009db40112f4220899f0983684d897765
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Thu Mar 9 11:25:58 2023 -0600
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Mar 10 12:51:53 2023 -0600
lvmdbustest: Only inject 1 missing key error
Previously we were injecting a missing key in the lv, vg, and pv.
Given the order of processing in lvmdbusd, this prevented us from
exercising all the error paths. Change to returning just 1 instead.
---
test/dbus/lvm_error_inject.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/test/dbus/lvm_error_inject.py b/test/dbus/lvm_error_inject.py
index d87286740..98520845c 100755
--- a/test/dbus/lvm_error_inject.py
+++ b/test/dbus/lvm_error_inject.py
@@ -79,6 +79,7 @@ def write_some(q, stream, remaining=False, binary=False):
def del_random_key(src_dict):
keys = list(src_dict.keys())
pick = random.randint(0, len(keys) - 1)
+ debug("%s will be deleted" % keys[pick])
del src_dict[keys[pick]]
@@ -87,16 +88,19 @@ def inject_key_error(output_json):
for r in output_json['report']:
if 'lv' in r:
for i in r['lv']:
+ debug("deleting a lv key")
del_random_key(i)
- break
+ return
if 'vg' in r:
for i in r["vg"]:
+ debug("deleting a vg key")
del_random_key(i)
- break
+ return
elif 'pv' in r:
for i in r["pv"]:
+ debug("deleting a pv key")
del_random_key(i)
- break
+ return
def inject_exit_error(output_json, val):
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=1949afa24b10991408cff…
Commit: 1949afa24b10991408cff362084cdc881f499535
Parent: 3d854b39bd8c3740eae087c4d46e5f685b368f5e
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Thu Mar 9 11:21:27 2023 -0600
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Fri Mar 10 12:51:53 2023 -0600
lvmdbusd: Handle missing key in get_key
When we sort the LVs, we can stumble on a missing key, protect against
this as well.
Seen in error injection testing:
Traceback (most recent call last):
File "/home/tasleson/projects/lvm2/daemons/lvmdbusd/fetch.py", line 198, in update_thread
num_changes = load(*_load_args(queued_requests))
File "/home/tasleson/projects/lvm2/daemons/lvmdbusd/fetch.py", line 83, in load
rc = MThreadRunner(_main_thread_load, refresh, emit_signal).done()
File "/home/tasleson/projects/lvm2/daemons/lvmdbusd/utils.py", line 726, in done
raise self.exception
File "/home/tasleson/projects/lvm2/daemons/lvmdbusd/utils.py", line 732, in _run
self.rc = self.f(*self.args)
File "/home/tasleson/projects/lvm2/daemons/lvmdbusd/fetch.py", line 40, in _main_thread_load
(lv_changes, remove) = load_lvs(
File "/home/tasleson/projects/lvm2/daemons/lvmdbusd/lv.py", line 148, in load_lvs
return common(
File "/home/tasleson/projects/lvm2/daemons/lvmdbusd/loader.py", line 37, in common
objects = retrieve(search_keys, cache_refresh=False)
File "/home/tasleson/projects/lvm2/daemons/lvmdbusd/lv.py", line 72, in lvs_state_retrieve
lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
File "/home/tasleson/projects/lvm2/daemons/lvmdbusd/lv.py", line 35, in get_key
pool = i['pool_lv']
KeyError: 'pool_lv'
---
daemons/lvmdbusd/lv.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/daemons/lvmdbusd/lv.py b/daemons/lvmdbusd/lv.py
index 6a4161ad8..caee23379 100644
--- a/daemons/lvmdbusd/lv.py
+++ b/daemons/lvmdbusd/lv.py
@@ -65,13 +65,13 @@ def lvs_state_retrieve(selection, cache_refresh=True):
if cache_refresh:
cfg.db.refresh()
- # When building up the model, it's best to process LVs with the least
- # dependencies to those that are dependant upon other LVs. Otherwise, when
- # we are trying to gather information we could be in a position where we
- # don't have information available yet.
- lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
-
try:
+ # When building up the model, it's best to process LVs with the least
+ # dependencies to those that are dependant upon other LVs. Otherwise, when
+ # we are trying to gather information we could be in a position where we
+ # don't have information available yet.
+ lvs = sorted(cfg.db.fetch_lvs(selection), key=get_key)
+
for l in lvs:
if cfg.vdo_support:
rc.append(LvStateVdo(
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=e79c6feb080f30fc4bb4a…
Commit: e79c6feb080f30fc4bb4adbfd69c41ac90b6cde3
Parent: 69ea2e3f94815dc94b5fdd8284d30a667690f5df
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Feb 8 17:17:30 2023 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Mar 8 16:31:28 2023 -0600
tests: update missing-pv
add more checks and expand comments explaining behavior
---
test/shell/missing-pv.sh | 106 ++++++++++++++++++++++++++++++++---------------
1 file changed, 72 insertions(+), 34 deletions(-)
diff --git a/test/shell/missing-pv.sh b/test/shell/missing-pv.sh
index 3662483b0..e1ff65917 100644
--- a/test/shell/missing-pv.sh
+++ b/test/shell/missing-pv.sh
@@ -28,8 +28,12 @@ lvs -a -o+devices
# Fail one leg of each mirror LV.
aux disable_dev "$dev1"
-pvs
-vgs
+pvs -o+missing |tee out
+grep missing out |tee out2
+grep unknown out2
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial "partial"
+check vg_field $vg vg_missing_pv_count 1
lvs -a -o+devices
# Cannot do normal activate of either LV with a failed leg.
@@ -40,8 +44,12 @@ not lvchange -ay $vg/$lv2
lvchange -ay --activationmode partial $vg/$lv1
lvchange -ay --activationmode partial $vg/$lv2
-pvs
-vgs
+pvs -o+missing |tee out
+grep missing out |tee out2
+grep unknown out2
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial "partial"
+check vg_field $vg vg_missing_pv_count 1
lvs -a -o+devices
# Repair lv1 so it no longer uses failed dev.
@@ -54,8 +62,12 @@ pvck --dump metadata "$dev2" > meta
grep MISSING meta
rm meta
-pvs
-vgs
+pvs -o+missing |tee out
+grep missing out |tee out2
+grep unknown out2
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial "partial"
+check vg_field $vg vg_missing_pv_count 1
lvs -a -o+devices
# Verify normal activation is possible of lv1 since it's
@@ -68,8 +80,12 @@ vgchange -an $vg
aux enable_dev "$dev1"
-pvs
-vgs
+pvs -o+missing |tee out
+grep missing out |tee out2
+grep "$dev1" out2
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial "partial"
+check vg_field $vg vg_missing_pv_count 1
lvs -a -o+devices
# TODO: check that lv2 has partial flag, lv1 does not
@@ -82,7 +98,6 @@ pvck --dump metadata "$dev2" > meta
grep MISSING meta
rm meta
-
# The missing pv restrictions still apply even after
# the dev has reappeared since it has the MISSING flag.
not lvchange -ay $vg/$lv2
@@ -98,52 +113,75 @@ not lvcreate -l1 $vg
# explicitly writes/fixes metadata.
vgck --updatemetadata $vg
-pvs
-vgs
+pvs -o+missing |tee out
+grep missing out |tee out2
+grep "$dev1" out2
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial "partial"
+check vg_field $vg vg_missing_pv_count 1
lvs -a -o+devices
-# Check that MISSING flag is still set in ondisk
-# metadata since the previously missing dev is still
-# used by lv2.
+# Check that MISSING flag is still set in ondisk metadata since the
+# previously missing dev is still used by lv2.
pvck --dump metadata "$dev2" > meta
grep MISSING meta
rm meta
-
-# The missing pv restrictions still apply since it
-# has the MISSING flag.
+# The missing pv restrictions still apply since it has the MISSING flag.
not lvchange -ay $vg/$lv2
not lvcreate -l1 $vg
lvchange -ay --activationmode partial $vg/$lv2
-# After repair, no more LVs will be using the previously
-# missing PV.
+# Replace the missing leg of LV2 so no LV will be using the dev that was
+# missing. The MISSING_PV flag will not have been cleared from the
+# metadata yet; that will take another metadata update.
lvconvert --repair --yes $vg/$lv2
-pvs
-vgs
-lvs -a -o+devices
+lvs -a -o+devices | tee out
+not grep "$dev1" out
-vgchange -an $vg
-
-# The next write of the metadata will clear the MISSING
-# flag in ondisk metadata because the previously missing
-# PV is no longer used by any LVs.
+# The MISSING_PV flag hasn't been cleared from the metadata yet, but now
+# that the PV is not used by any more LVs, that flag will be cleared from
+# the metadata in the next update.
+pvck --dump metadata "$dev2" > meta
+grep MISSING meta
+rm meta
-# Run a command to write ondisk metadata, which should clear
-# the MISSING flag, could also use vgck --updatemetadata vg.
+# Reporting commands run vg_read which sees MISSING_PV in the metadata,
+# but vg_read then sees the dev is no longer used by any LV, so vg_read
+# clears the MISSING_PV flag in the vg struct (not in the metadata) before
+# returning the vg struct to the caller. It's cleared in the vg struct so
+# that the limitations of having a missing PV are not applied to the
+# command. The caller sees/uses/reports the VG as having no missing PV,
+# even though the metadata still contains MISSING_PV. The MISSING_PV flag
+# is no longer needed in the metadata, but there has simply not been a
+# metadata update yet to clear it.
+# The message that's printed in this case is:
+# WARNING: VG %s has unused reappeared PV %s %s
+pvs -o+missing |tee out
+not grep missing out
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial ""
+check vg_field $vg vg_missing_pv_count 0
+
+# Run any command that updates the metadata, and the MISSING_PV flag will
+# be cleared. Here just use lvcreate -l1, or we could use
+# vgck --updatemetadata.
lvcreate -l1 $vg
-# Check that the MISSING flag is no longer set
-# in the ondisk metadata.
+# Now the MISSING flag is removed from the ondisk metadata.
pvck --dump metadata "$dev2" > meta
not grep MISSING meta
rm meta
+# and commands continue to report no missing PV
+pvs -o+missing |tee out
+not grep missing out
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial ""
+check vg_field $vg vg_missing_pv_count 0
-pvs
-vgs
-lvs -a -o+devices
+vgchange -an $vg
vgremove -ff $vg
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=69ea2e3f94815dc94b5fd…
Commit: 69ea2e3f94815dc94b5fdd8284d30a667690f5df
Parent: 937f1d320980b78b0d70cd778310bf31356ec6da
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Feb 8 13:34:35 2023 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Mar 8 16:31:28 2023 -0600
vg_read: keep MISSING_PV when device with no mda reappears
Remove old code that became incorrect at some point.
It's probably a fragment of an old condition that was left
behind because it wasn't understood. We don't want to drop
the MISSING_PV flag just because the PV has no mda in use.
The device that was missing may have stale data, so the user
needs to decide if the device should be removed or restored.
---
lib/metadata/metadata.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 91a23f931..10af75665 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -3571,12 +3571,6 @@ static void _set_pv_device(struct format_instance *fid,
if (!pv->dev)
pv->status |= MISSING_PV;
- /* is this correct? */
- if ((pv->status & MISSING_PV) && pv->dev && (pv_mda_used_count(pv) == 0)) {
- pv->status &= ~MISSING_PV;
- log_info("Found a previously MISSING PV %s with no MDAs.", pv_dev_name(pv));
- }
-
/* Fix up pv size if missing or impossibly large */
if ((!pv->size || pv->size > (1ULL << 62)) && pv->dev) {
if (!dev_get_size(pv->dev, &pv->size)) {
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=aa85ed1784b2b8e731ac7…
Commit: aa85ed1784b2b8e731ac7bd05a8988bac30405f0
Parent: da44f2b6fe1e0edbd3ee875c831f3e467f242bc0
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Jul 7 16:06:01 2022 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Mar 8 16:30:54 2023 -0600
vgchange: allow changing system ID with majority of PVs
when used with --majoritypvs. This allows the fail-over
of a VG between systems by changing the VG system ID when
a PV is missing.
---
test/shell/system_id.sh | 69 ++++++++++++++++++++++++++++++++++++++++++++++++-
tools/args.h | 4 +++
tools/command-lines.in | 2 +-
tools/vgchange.c | 21 +++++++++++++++
4 files changed, 94 insertions(+), 2 deletions(-)
diff --git a/test/shell/system_id.sh b/test/shell/system_id.sh
index 756c95add..14d2c6fd4 100644
--- a/test/shell/system_id.sh
+++ b/test/shell/system_id.sh
@@ -22,7 +22,7 @@ print_lvmlocal() {
. lib/inittest
-aux prepare_devs 1
+aux prepare_devs 5
SIDFILE="etc/lvm_test.conf"
LVMLOCAL="etc/lvmlocal.conf"
@@ -541,6 +541,73 @@ echo "$SID1" > "$SIDFILE"
clear_df_systemid
vgremove $vg1
+# vgchange --systemid --majoritypvs
+SID1=sidfoofile1
+SID2=sidfoofile2
+rm -f "$LVMLOCAL"
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1" "$dev2" "$dev3"
+vgcreate $vg2 "$dev4" "$dev5"
+# normal vgs sees the vg
+# change the local system_id, making the vg foreign
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+# normal vgs doesn't see the vg
+vgs >err
+not grep $vg1 err
+not grep $vg2 err
+# using --foreign we can see the vg
+vgs --foreign >err
+grep $vg1 err
+grep $vg2 err
+# cannot clear the system_id of the foreign vg
+not vgchange --yes --systemid "" $vg1
+not vgchange --yes --systemid "" $vg2
+# cannot set the system_id of the foreign vg
+not vgchange --yes --systemid foo $vg1
+not vgchange --yes --systemid foo $vg2
+# we are local node SID2, foreign node is SID1
+# use extra_system_ids to take over the foreign vg, making it local
+vgchange --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg1
+vgs $vg1
+# make it foreign again
+vgchange --yes --systemid sidfoofile1 $vg1
+not vgs $vg1
+# both vgs are foreign, drop dev1/dev4 so both vgs are missing a device
+aux hide_dev "$dev1"
+aux hide_dev "$dev4"
+not pvs "$dev1"
+not pvs "$dev4"
+# neither VG can be changed because both are missing a dev
+not vgchange --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg1
+not vgchange --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg2
+# using majoritypvs, vg1 can be changed because 2 of 3 PVs exist
+vgchange --majoritypvs --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg1
+vgs $vg1
+# using majoritypvs, vg2 cannot be changed because 1 of 2 PVs exist
+not vgchange --majoritypvs --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg2
+not vgs $vg2
+vgs --foreign $vg2
+# dev1/dev4 return so we can take over vg2 now
+# vg1 will complain about stale metadata on dev1
+aux unhide_dev "$dev1"
+aux unhide_dev "$dev4"
+vgs
+pvs
+vgchange --majoritypvs --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg2
+vgs $vg2
+# update metadata on dev1
+vgck --updatemetadata $vg1
+vgs $vg1
+clear_df_systemid
+vgremove $vg1
+vgremove $vg2
+
+
# vgcfgbackup backs up foreign vg with --foreign
SID1=sidfoofile1
SID2=sidfoofile2
diff --git a/tools/args.h b/tools/args.h
index 5819bb84e..24dc8b339 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -416,6 +416,10 @@ arg(logonly_ARG, '\0', "logonly", 0, 0, 0,
arg(longhelp_ARG, '\0', "longhelp", 0, 0, 0,
"Display long help text.\n")
+arg(majoritypvs_ARG, '\0', "majoritypvs", 0, 0, 0,
+ "Change the VG system ID if the majority of PVs in the VG\n"
+ "are present (one more than half).\n")
+
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", sizekb_VAL, 0, 0,
"Sets the maximum recovery rate for a RAID LV. The rate value\n"
"is an amount of data per second for each device in the array.\n"
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 4bbafd05d..1cf6bba23 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -1767,7 +1767,7 @@ ID: vgchange_refresh
DESC: Reactivate LVs using the latest metadata.
vgchange --systemid String VG|Tag|Select
-OO: --select String
+OO: --select String, --majoritypvs
ID: vgchange_systemid
DESC: Change the system ID of a VG.
diff --git a/tools/vgchange.c b/tools/vgchange.c
index 09ade96a6..f07b245bd 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -1383,6 +1383,24 @@ static int _vgchange_systemid_single(struct cmd_context *cmd, const char *vg_nam
struct volume_group *vg,
struct processing_handle *handle)
{
+ if (arg_is_set(cmd, majoritypvs_ARG)) {
+ struct pv_list *pvl;
+ int missing_pvs = 0;
+ int found_pvs = 0;
+
+ dm_list_iterate_items(pvl, &vg->pvs) {
+ if (!pvl->pv->dev)
+ missing_pvs++;
+ else
+ found_pvs++;
+ }
+ if (found_pvs <= missing_pvs) {
+ log_error("Cannot change system ID without the majority of PVs (found %d of %d)",
+ found_pvs, found_pvs+missing_pvs);
+ return ECMD_FAILED;
+ }
+ }
+
if (!_vgchange_system_id(cmd, vg))
return_ECMD_FAILED;
@@ -1415,6 +1433,9 @@ int vgchange_systemid_cmd(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
+ if (arg_is_set(cmd, majoritypvs_ARG))
+ cmd->handles_missing_pvs = 1;
+
ret = process_each_vg(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, 0, handle, &_vgchange_systemid_single);
destroy_processing_handle(cmd, handle);