2013-06-10 13:28:47 +04:00
#!/usr/bin/env bash
2013-09-16 13:18:31 +04:00
# Copyright (C) 2010-2013 Red Hat, Inc. All rights reserved.
2010-07-28 16:20:38 +04:00
#
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2010-05-12 14:08:35 +04:00
# check.sh: assert various things about volumes
2012-03-16 16:59:43 +04:00
# USAGE:
2010-05-12 14:08:35 +04:00
# check linear VG LV
# check lv_on VG LV PV
# check mirror VG LV [LOGDEV|core]
# check mirror_nonredundant VG LV
# check mirror_legs VG LV N
# check mirror_images_on VG LV DEV [DEV...]
# ...
2012-03-16 16:59:43 +04:00
test -z " $BASH " || set -e -o pipefail
2011-01-05 03:16:18 +03:00
2012-03-16 16:59:43 +04:00
die( ) {
2013-09-16 13:05:03 +04:00
rm -f debug.log
echo -e " $@ " >& 2
2012-03-16 16:59:43 +04:00
return 1
2011-01-05 03:16:18 +03:00
}
2010-05-12 09:55:08 +04:00
lvl( ) {
lvs -a --noheadings " $@ "
}
2010-04-12 23:02:59 +04:00
lvdevices( ) {
2012-03-16 16:59:43 +04:00
get lv_devices " $@ "
2010-04-12 23:02:59 +04:00
}
2012-03-16 16:59:43 +04:00
mirror_images_redundant( ) {
local vg = $1
local lv = $vg /$2
lvs -a $vg -o+devices
for i in $( lvdevices $lv ) ; do
echo " # $i : "
lvdevices $vg /$i | sort | uniq
done > check.tmp.all
2010-04-12 23:02:59 +04:00
2012-03-16 16:59:43 +04:00
( grep -v ^# check.tmp.all || true ) | sort | uniq -d > check.tmp
2010-04-12 23:02:59 +04:00
2012-03-16 16:59:43 +04:00
test $( cat check.tmp | wc -l) -eq 0 || \
die " mirror images of $lv expected redundant, but are not: " \
$( cat check.tmp.all)
}
2010-04-12 23:02:59 +04:00
2013-09-16 13:18:31 +04:00
lv_err_list_( ) {
( echo " $2 " | not grep -m 1 -q " $1 " ) || \
echo " $3 on [ $( echo " $2 " | grep " $1 " | cut -b3- | tr '\n' ' ' ) ] "
}
lv_on_diff_( ) {
2014-03-09 02:07:50 +04:00
declare -a xdevs = ( " ${ !1 } " ) # pass in shell array
2013-09-16 13:18:31 +04:00
local expect = ( " ${ @ : 4 } " ) # make an array starting from 4th args...
local diff_e
# Find diff between 2 shell arrays, print them as stdin files
2013-12-04 22:50:53 +04:00
printf "%s\n" " ${ expect [@] } " | sort | uniq >_lv_on_diff1
2014-03-09 02:07:50 +04:00
printf "%s\n" " ${ xdevs [@] } " >_lv_on_diff2
2013-12-04 22:50:53 +04:00
diff_e = $( diff _lv_on_diff1 _lv_on_diff2) ||
2013-09-16 13:18:31 +04:00
die " LV $2 / $3 $( lv_err_list_ "^>" " ${ diff_e } " found) $( lv_err_list_ "^<" " ${ diff_e } " "not found" ) . "
}
# list devices for given LV
2012-03-16 16:59:43 +04:00
lv_on( ) {
2013-09-16 13:18:31 +04:00
local devs
devs = ( $( lvdevices " $1 / $2 " | sort | uniq ) )
lv_on_diff_ devs[ @] " ${ @ } "
}
# list devices for given LV and all its subdevices
lv_tree_on( ) {
local devs
# Get sorted list of devices
devs = ( $( get lv_tree_devices " $1 " " $2 " ) )
lv_on_diff_ devs[ @] " ${ @ } "
2010-04-12 23:02:59 +04:00
}
2010-04-12 23:33:58 +04:00
mirror_images_on( ) {
2012-03-16 16:59:43 +04:00
local vg = $1
local lv = $2
2010-05-12 14:08:35 +04:00
shift 2
2012-03-16 16:59:43 +04:00
for i in $( lvdevices $lv ) ; do
2010-05-12 14:08:35 +04:00
lv_on $vg $lv $1
2010-04-12 23:33:58 +04:00
shift
done
}
2012-03-16 16:59:43 +04:00
mirror_log_on( ) {
local vg = $1
local lv = $2
local where = $3
2010-05-12 14:08:35 +04:00
if test " $where " = "core" ; then
2012-03-16 16:59:43 +04:00
get lv_field $vg /$lv mirror_log | not grep mlog
2010-05-12 14:08:35 +04:00
else
2012-03-16 16:59:43 +04:00
lv_on $vg ${ lv } _mlog " $where "
2010-05-12 14:08:35 +04:00
fi
2010-04-12 23:02:59 +04:00
}
2012-03-16 16:59:43 +04:00
lv_is_contiguous( ) {
local lv = $1 /$2
test $( lvl --segments $lv | wc -l) -eq 1 || \
die " LV $lv expected to be contiguous, but is not: " \
$( lvl --segments $lv )
2010-04-12 23:02:59 +04:00
}
2012-03-16 16:59:43 +04:00
lv_is_clung( ) {
local lv = $1 /$2
test $( lvdevices $lv | sort | uniq | wc -l) -eq 1 || \
die " LV $lv expected to be clung, but is not: " \
$( lvdevices $lv | sort | uniq)
2010-04-12 23:02:59 +04:00
}
2012-03-16 16:59:43 +04:00
mirror_images_contiguous( ) {
for i in $( lvdevices $1 /$2 ) ; do
lv_is_contiguous $1 $i
2010-04-12 23:02:59 +04:00
done
}
2012-03-16 16:59:43 +04:00
mirror_images_clung( ) {
for i in $( lvdevices $1 /$2 ) ; do
lv_is_clung $1 $i
2010-04-12 23:02:59 +04:00
done
}
mirror( ) {
2010-05-12 14:08:35 +04:00
mirror_nonredundant " $@ "
2012-03-16 16:59:43 +04:00
mirror_images_redundant $1 $2
2010-05-12 14:08:35 +04:00
}
mirror_nonredundant( ) {
2012-03-16 16:59:43 +04:00
local lv = $1 /$2
local attr = $( get lv_field $lv attr)
2013-07-12 15:07:40 +04:00
( echo " $attr " | grep " ^......m... $" >/dev/null) || {
if ( echo " $attr " | grep " ^o......... $" >/dev/null) &&
2011-01-28 19:08:39 +03:00
lvs -a | fgrep " [ ${ 2 } _mimage " >/dev/null; then
2011-01-07 16:03:46 +03:00
echo " TEST WARNING: $lv is a snapshot origin and looks like a mirror, "
echo "assuming it is actually a mirror"
else
2012-03-16 16:59:43 +04:00
die " $lv expected a mirror, but is not: " \
$( lvs $lv )
2011-01-07 16:03:46 +03:00
fi
2010-04-12 23:02:59 +04:00
}
2012-03-16 16:59:43 +04:00
test -z " $3 " || mirror_log_on $1 $2 " $3 "
2010-04-12 23:02:59 +04:00
}
2010-05-06 23:01:26 +04:00
mirror_legs( ) {
2012-03-16 16:59:43 +04:00
local expect = $3
test " $expect " -eq $( lvdevices $1 /$2 | wc -w)
2010-05-06 23:01:26 +04:00
}
2012-03-16 16:59:43 +04:00
mirror_no_temporaries( ) {
local vg = $1
local lv = $2
( lvl -o name $vg | grep $lv | not grep "tmp" ) || \
die " $lv has temporary mirror images unexpectedly: " \
$( lvl $vg | grep $lv )
2010-05-12 14:08:35 +04:00
}
2010-04-12 23:02:59 +04:00
linear( ) {
2012-03-16 16:59:43 +04:00
local lv = $1 /$2
test $( get lv_field $lv stripes -a) -eq 1 || \
die " $lv expected linear, but is not: " \
$( lvl $lv -o+devices)
2010-05-12 09:55:08 +04:00
}
2012-07-24 23:17:54 +04:00
# in_sync <VG> <LV>
# Works for "mirror" and "raid*"
in_sync( ) {
local a
local b
local idx
local type
2013-06-20 20:48:15 +04:00
local snap = ""
2012-07-24 23:17:54 +04:00
local lvm_name = " $1 / $2 "
local dm_name = $( echo $lvm_name | sed s:-:--: | sed s:/:-:)
if ! a = ( ` dmsetup status $dm_name ` ) ; then
die " Unable to get sync status of $1 "
elif [ ${ a [2] } = "snapshot-origin" ] ; then
if ! a = ( ` dmsetup status ${ dm_name } -real` ) ; then
die " Unable to get sync status of $1 "
fi
2013-06-20 20:48:15 +04:00
snap = ": under snapshot"
2012-07-24 23:17:54 +04:00
fi
if [ ${ a [2] } = "raid" ] ; then
2013-03-06 21:12:09 +04:00
# 6th argument is the sync ratio for RAID
idx = 6
2012-07-24 23:17:54 +04:00
type = ${ a [3] }
2015-05-27 12:59:10 +03:00
if [ ${ a [ $(( $idx + 1 )) ] } != "idle" ] ; then
echo " $lvm_name ( $type $snap ) is not in-sync "
return 1
fi
2012-07-24 23:17:54 +04:00
elif [ ${ a [2] } = "mirror" ] ; then
# 4th Arg tells us how far to the sync ratio
idx = $(( ${ a [3] } + 4 ))
type = ${ a [2] }
else
die " Unable to get sync ratio for target type ' ${ a [2] } ' "
fi
b = ( $( echo ${ a [ $idx ] } | sed s:/:' ' :) )
2015-05-27 12:59:10 +03:00
if [ ${ b [0] } -eq 0 -o ${ b [0] } != ${ b [1] } ] ; then
2013-06-20 20:48:15 +04:00
echo " $lvm_name ( $type $snap ) is not in-sync "
2012-07-24 23:17:54 +04:00
return 1
fi
if [ [ ${ a [ $(( $idx - 1 )) ] } = ~ a ] ] ; then
2013-06-20 20:48:15 +04:00
die " $lvm_name ( $type $snap ) in-sync, but 'a' characters in health status "
2012-07-24 23:17:54 +04:00
fi
2013-06-20 20:48:15 +04:00
echo " $lvm_name ( $type $snap ) is in-sync "
2012-07-24 23:17:54 +04:00
}
2010-05-12 09:55:08 +04:00
active( ) {
2012-03-16 16:59:43 +04:00
local lv = $1 /$2
2013-07-12 15:07:40 +04:00
( get lv_field $lv attr | grep " ^....a..... $" >/dev/null) || \
2012-03-16 16:59:43 +04:00
die " $lv expected active, but lvs says it's not: " \
$( lvl $lv -o+devices)
2012-03-28 15:10:08 +04:00
dmsetup info $1 -$2 >/dev/null ||
die " $lv expected active, lvs thinks it is but there are no mappings! "
2010-05-12 09:55:08 +04:00
}
inactive( ) {
2012-03-16 16:59:43 +04:00
local lv = $1 /$2
2013-07-12 15:07:40 +04:00
( get lv_field $lv attr | grep " ^....[-isd]..... $" >/dev/null) || \
2012-03-16 16:59:43 +04:00
die " $lv expected inactive, but lvs says it's not: " \
$( lvl $lv -o+devices)
2012-03-28 15:10:08 +04:00
not dmsetup info $1 -$2 2>/dev/null || \
2014-01-31 16:31:40 +04:00
die " $lv expected inactive, lvs thinks it is but there are mappings! "
2010-04-12 23:02:59 +04:00
}
2012-03-16 16:59:43 +04:00
# Check for list of LVs from given VG
2011-04-12 16:39:24 +04:00
lv_exists( ) {
2012-03-16 16:59:43 +04:00
local vg = $1
local lv =
while [ $# -gt 1 ] ; do
shift
lv = " $lv $vg / $1 "
done
2014-01-31 16:31:40 +04:00
test -n " $lv " || lv = $vg
2012-03-16 16:59:43 +04:00
lvl $lv & >/dev/null || \
die " $lv expected to exist but does not "
2011-04-12 16:39:24 +04:00
}
2014-01-31 16:31:40 +04:00
lv_not_exists( ) {
local vg = $1
if test $# -le 1 ; then
2014-09-15 15:45:43 +04:00
if lvl $vg & >/dev/null ; then
die " $vg expected to not exist but it does! "
fi
2014-01-31 16:31:40 +04:00
else
while [ $# -gt 1 ] ; do
shift
lvl $vg /$1 & >/dev/null || continue
die " $vg / $1 expected to not exist but it does! "
done
fi
2014-09-15 15:45:43 +04:00
rm -f debug.log
2014-01-31 16:31:40 +04:00
}
2012-03-16 16:59:43 +04:00
pv_field( ) {
local actual = $( get pv_field " $1 " " $2 " " ${ @ : 4 } " )
test " $actual " = " $3 " || \
die " pv_field: PV=\" $1 \", field=\" $2 \", actual=\" $actual \", expected=\" $3 \" "
2011-01-05 03:16:18 +03:00
}
2012-03-16 16:59:43 +04:00
vg_field( ) {
2013-09-16 13:12:37 +04:00
local actual = $( get vg_field " $1 " " $2 " " ${ @ : 4 } " )
2012-03-16 16:59:43 +04:00
test " $actual " = " $3 " || \
die " vg_field: vg= $1 , field=\" $2 \", actual=\" $actual \", expected=\" $3 \" "
2011-01-05 03:16:18 +03:00
}
2014-05-22 13:59:11 +04:00
vg_attr_bit( ) {
local actual = $( get vg_field " $2 " vg_attr " ${ @ : 4 } " )
local offset = $1
case " $offset " in
perm*) offset = 0 ; ;
resiz*) offset = 1 ; ;
export*) offset = 2 ; ;
partial) offset = 3 ; ;
alloc*) offset = 4 ; ;
cluster*) offset = 5 ; ;
esac
test " ${ actual : $offset : 1 } " = " $3 " || \
die " vg_attr_bit: vg= $2 , ${ offset } bit of \" $actual \" is \" ${ actual : $offset : 1 } \", but expected \" $3 \" "
}
2012-03-16 16:59:43 +04:00
lv_field( ) {
2013-09-16 13:12:37 +04:00
local actual = $( get lv_field " $1 " " $2 " " ${ @ : 4 } " )
2012-03-16 16:59:43 +04:00
test " $actual " = " $3 " || \
2014-04-11 00:07:45 +04:00
die " lv_field: lv= $1 , field=\" $2 \", actual=\" $actual \", expected=\" $3 \" "
}
lv_attr_bit( ) {
local actual = $( get lv_field " $2 " lv_attr " ${ @ : 4 } " )
local offset = $1
case " $offset " in
type ) offset = 0 ; ;
perm*) offset = 1 ; ;
alloc*) offset = 2 ; ;
fixed*) offset = 3 ; ;
state) offset = 4 ; ;
open) offset = 5 ; ;
target) offset = 6 ; ;
zero) offset = 7 ; ;
health) offset = 8 ; ;
skip) offset = 9 ; ;
esac
test " ${ actual : $offset : 1 } " = " $3 " || \
die " lv_attr_bit: lv= $2 , ${ offset } bit of \" $actual \" is \" ${ actual : $offset : 1 } \", but expected \" $3 \" "
2011-01-05 03:16:18 +03:00
}
2012-03-16 16:59:43 +04:00
compare_fields( ) {
local cmd1 = $1
local obj1 = $2
local field1 = $3
local cmd2 = $4
local obj2 = $5
local field2 = $6
local val1 = $( $cmd1 --noheadings -o " $field1 " " $obj1 " )
local val2 = $( $cmd2 --noheadings -o " $field2 " " $obj2 " )
test " $val1 " = " $val2 " || \
die " compare_fields $obj1 ( $field1 ): $val1 $obj2 ( $field2 ): $val2 "
2011-01-05 03:16:18 +03:00
}
2012-03-16 16:59:43 +04:00
compare_vg_field( ) {
local vg1 = $1
local vg2 = $2
local field = $3
local val1 = $( vgs --noheadings -o " $field " $vg1 )
local val2 = $( vgs --noheadings -o " $field " $vg2 )
test " $val1 " = " $val2 " || \
die " compare_vg_field: $vg1 : $val1 , $vg2 : $val2 "
2011-01-05 03:16:18 +03:00
}
2012-03-16 16:59:43 +04:00
pvlv_counts( ) {
2011-01-05 03:16:18 +03:00
local local_vg = $1
local num_pvs = $2
local num_lvs = $3
local num_snaps = $4
2012-03-16 16:59:43 +04:00
lvs -o+devices $local_vg
2011-01-05 03:16:18 +03:00
vg_field $local_vg pv_count $num_pvs
vg_field $local_vg lv_count $num_lvs
vg_field $local_vg snap_count $num_snaps
}
2013-09-16 13:02:58 +04:00
# Compare md5 check generated from get dev_md5sum
dev_md5sum( ) {
md5sum -c " md5. $1 - $2 " || \
( get lv_field $1 /$2 "name,size,seg_pe_ranges"
die " LV $1 / $2 has different MD5 check sum! " )
}
2015-04-24 21:31:22 +03:00
sysfs( ) {
2015-04-03 11:27:00 +03:00
# read maj min and also convert hex to decimal
local maj = $(( $( stat -L --printf= 0x%t " $1 " ) ))
local min = $(( $( stat -L --printf= 0x%T " $1 " ) ))
2015-04-24 21:31:22 +03:00
local P = " /sys/dev/block/ $maj : $min / $2 "
2015-04-03 11:27:00 +03:00
local val = $( < " $P " ) || return 0 # no sysfs ?
test " $val " -eq " $3 " || \
die " $1 : $P = $val differs from expected value $3 ! "
2015-04-02 13:21:55 +03:00
}
2013-09-16 13:02:58 +04:00
#set -x
2012-03-16 16:59:43 +04:00
unset LVM_VALGRIND
2010-04-12 23:02:59 +04:00
" $@ "