#!/usr/bin/env bash

# Copyright (C) 2008-2013,2018 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

RUNDIR="/run"
test -d "$RUNDIR" || RUNDIR="/var/run"
PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"

_clear_online_files() {
        # wait till udev is finished
        aux udev_wait
        rm -f "$PVS_ONLINE_DIR"/*
        rm -f "$VGS_ONLINE_DIR"/*
}

. lib/inittest

aux prepare_devs 3
get_devs

dd if=/dev/zero of="$dev1" || true
dd if=/dev/zero of="$dev2" || true
dd if=/dev/zero of="$dev3" || true

vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"

pvs

dd if="$dev1" of=meta1 bs=4k count=2

sed 's/flags =/flagx =/' meta1 > meta1.bad

dd if=meta1.bad of="$dev1"

pvs 2>&1 | tee out
grep "bad metadata text" out

pvs "$dev1"
pvs "$dev2"
pvs "$dev3"

# bad metadata in one mda doesn't prevent using
# the VG since other mdas are fine and usable
lvcreate -l1 $vg


vgck --updatemetadata $vg

pvs 2>&1 | tee out
not grep "bad metadata text" out

pvs "$dev1"
pvs "$dev2"
pvs "$dev3"

vgchange -an $vg
vgremove -ff $vg


#
# Same test as above, but corrupt metadata text
# on two of the three PVs, leaving one good
# copy of the metadata.
#

dd if=/dev/zero of="$dev1" || true
dd if=/dev/zero of="$dev2" || true
dd if=/dev/zero of="$dev3" || true

vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"

pvs

dd if="$dev1" of=meta1 bs=4k count=2
dd if="$dev2" of=meta2 bs=4k count=2

sed 's/READ/RRRR/' meta1 > meta1.bad
sed 's/seqno =/sss =/' meta2 > meta2.bad

dd if=meta1.bad of="$dev1"
dd if=meta2.bad of="$dev2"

pvs 2>&1 | tee out
grep "bad metadata text" out > out2
grep "$dev1" out2
grep "$dev2" out2

pvs "$dev1"
pvs "$dev2"
pvs "$dev3"

# bad metadata in one mda doesn't prevent using
# the VG since other mdas are fine
lvcreate -l1 $vg


vgck --updatemetadata $vg

pvs 2>&1 | tee out
not grep "bad metadata text" out

pvs "$dev1"
pvs "$dev2"
pvs "$dev3"

vgchange -an $vg
vgremove -ff $vg

#
# Three PVs where two have one mda, and the third
# has two mdas.  The first mda is corrupted on all
# thee PVs, but the second mda on the third PV
# makes the VG usable.
#

dd if=/dev/zero of="$dev1" || true
dd if=/dev/zero of="$dev2" || true
dd if=/dev/zero of="$dev3" || true

pvcreate "$dev1"
pvcreate "$dev2"
pvcreate --pvmetadatacopies 2 "$dev3"

vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"

pvs

dd if="$dev1" of=meta1 bs=4k count=2
dd if="$dev2" of=meta2 bs=4k count=2
dd if="$dev3" of=meta3 bs=4k count=2

sed 's/READ/RRRR/' meta1 > meta1.bad
sed 's/seqno =/sss =/' meta2 > meta2.bad
sed 's/id =/id/' meta3 > meta3.bad

dd if=meta1.bad of="$dev1"
dd if=meta2.bad of="$dev2"
dd if=meta3.bad of="$dev3"

pvs 2>&1 | tee out
grep "bad metadata text" out > out2
grep "$dev1" out2
grep "$dev2" out2
grep "$dev3" out2

pvs "$dev1"
pvs "$dev2"
pvs "$dev3"

# bad metadata in some mdas doesn't prevent using
# the VG if there's a good mda found
lvcreate -l1 $vg


vgck --updatemetadata $vg

pvs 2>&1 | tee out
not grep "bad metadata text" out

pvs "$dev1"
pvs "$dev2"
pvs "$dev3"

vgchange -an $vg
vgremove -ff $vg

#
# Test that vgck --updatemetadata will update old metadata
# and repair bad metadata text at the same time from different
# devices.
#

dd if=/dev/zero of="$dev1" || true
dd if=/dev/zero of="$dev2" || true
dd if=/dev/zero of="$dev3" || true

pvcreate "$dev1"
pvcreate "$dev2"
pvcreate --pvmetadatacopies 2 "$dev3"

vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"

# Put bad metadata onto dev1
dd if="$dev1" of=meta1 bs=4k count=2
sed 's/READ/RRRR/' meta1 > meta1.bad
dd if=meta1.bad of="$dev1"

pvs 2>&1 | tee out
grep "bad metadata text" out > out2
grep "$dev1" out2

# We can still use the VG with other available
# mdas, skipping the bad mda.

lvcreate -n $lv1 -l1 -an $vg "$dev1"
lvcreate -n $lv2 -l1 -an $vg "$dev1"

# Put old metadata onto dev2 by updating
# the VG while dev2 is disabled.
aux disable_dev "$dev2"

pvs
pvs "$dev1"
not pvs "$dev2"
pvs "$dev3"
lvs $vg/$lv1
lvs $vg/$lv2

lvremove $vg/$lv2

aux enable_dev "$dev2"

# Both old and bad metadata are reported.
pvs 2>&1 | tee out
grep "ignoring metadata seqno" out
grep "bad metadata text" out
pvs "$dev1"
pvs "$dev2"
pvs "$dev3"

lvs $vg/$lv1
not lvs $vg/$lv2

# fixes the bad metadata on dev1, and
# fixes the old metadata on dev2.
vgck --updatemetadata $vg

pvs 2>&1 | tee out
not grep "ignoring metadata seqno" out
not grep "bad metadata text" out
pvs "$dev1"
pvs "$dev2"
pvs "$dev3"

lvs $vg/$lv1

vgchange -an $vg
vgremove -ff $vg

#
# Test pvscan activation with bad PVs
#

# autoactivation not done on shared VGs
if test -n "$LVM_TEST_LVMLOCKD"; then
exit 0
fi

dd if=/dev/zero of="$dev1" || true
dd if=/dev/zero of="$dev2" || true
dd if=/dev/zero of="$dev3" || true

vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"

PVID1=`pvs $dev1 --noheading -o uuid | tr -d - | awk '{print $1}'`
echo $PVID1
PVID2=`pvs $dev2 --noheading -o uuid | tr -d - | awk '{print $1}'`
echo $PVID2
PVID3=`pvs $dev3 --noheading -o uuid | tr -d - | awk '{print $1}'`
echo $PVID3

pvs

dd if="$dev1" of=meta1 bs=4k count=2
dd if="$dev2" of=meta2 bs=4k count=2

sed 's/READ/RRRR/' meta1 > meta1.bad
sed 's/seqno =/sss =/' meta2 > meta2.bad

dd if=meta1.bad of="$dev1"
dd if=meta2.bad of="$dev2"

pvs 2>&1 | tee out
grep "bad metadata text" out > out2
grep "$dev1" out2
grep "$dev2" out2

pvs "$dev1"
pvs "$dev2"
pvs "$dev3"

# bad metadata in one mda doesn't prevent using
# the VG since other mdas are fine
lvcreate -l1 -n $lv1 $vg

vgchange -an $vg

_clear_online_files

# pvscan of one dev with bad metadata will result
# in the pvid online file being created but the 
# VG will not be known.
pvscan --cache -aay "$dev1"
ls "$RUNDIR/lvm/pvs_online/$PVID1"
not ls "$RUNDIR/lvm/pvs_online/$PVID2"
not ls "$RUNDIR/lvm/pvs_online/$PVID3"
not ls "$RUNDIR/lvm/vgs_online/$vg"

_clear_online_files

# scan the one pv with good metadata, does not scan any others
pvscan --cache -aay "$dev3"
not ls "$RUNDIR/lvm/pvs_online/$PVID1"
not ls "$RUNDIR/lvm/pvs_online/$PVID2"
ls "$RUNDIR/lvm/pvs_online/$PVID3"
not ls "$RUNDIR/lvm/vgs_online/$vg"

vgck --updatemetadata $vg

pvs 2>&1 | tee out
not grep "bad metadata text" out

pvs "$dev1"
pvs "$dev2"
pvs "$dev3"

vgchange -an $vg
vgremove -ff $vg

