2010-01-16 01:12:54 +01:00
|
|
|
#! /bin/bash
|
|
|
|
|
|
|
|
# Usage: block-dmmd [add args | remove args]
|
|
|
|
#
|
2013-10-03 00:41:46 +02:00
|
|
|
# the dmmd device syntax (in xm commands/configs) is something like:
|
2010-01-16 01:12:54 +01:00
|
|
|
# dmmd:md;/dev/md0;md;/dev/md1;lvm;/dev/vg1/lv1
|
|
|
|
# or
|
|
|
|
# dmmd:lvm;/dev/vg1/lv1;lvm;/dev/vg1/lv2;md;/dev/md0
|
2013-10-03 00:41:46 +02:00
|
|
|
# device pairs (type;dev) are processed in order, with the last device
|
|
|
|
# assigned to the VM
|
|
|
|
#
|
|
|
|
# md devices can optionally:
|
|
|
|
# specify a config file through:
|
|
|
|
# md;/dev/md100(/var/xen/config/mdadm.conf)
|
|
|
|
# use an array name (mdadm -N option):
|
|
|
|
# dmmd:md;My-MD-name;lvm;/dev/vg1/lv1
|
|
|
|
#
|
2010-01-16 01:12:54 +01:00
|
|
|
# History:
|
2013-10-03 00:41:46 +02:00
|
|
|
# 2013-07-03, loic.devulder@mpsa.com:
|
|
|
|
# Partial rewrite of the script for supporting MD activation by name
|
2010-01-16 01:12:54 +01:00
|
|
|
# 2009-06-09, mh@novell.com:
|
|
|
|
# Emit debugging messages into a temporary file; if no longer needed,
|
|
|
|
# just comment the exec I/O redirection below
|
|
|
|
# Make variables used in functions local to avoid global overridings
|
|
|
|
# Use vgscan and vgchange where required
|
|
|
|
# Use the C locale to avoid dealing with localized messages
|
|
|
|
# Assign output from assembling an MD device to a variable to aid debugging
|
|
|
|
|
|
|
|
# We do not want to deal with localized messages:
|
|
|
|
LANG=C
|
|
|
|
LC_MESSAGES=C
|
|
|
|
export LANG LC_MESSAGES
|
|
|
|
|
|
|
|
dir=$(dirname "$0")
|
|
|
|
. "$dir/block-common.sh"
|
|
|
|
|
|
|
|
#exec >> /tmp/block-dmmd-`date +%F_%T.%N`.log 2>&1
|
2012-11-19 14:58:33 +01:00
|
|
|
#echo shell-flags: $-
|
|
|
|
|
2010-01-16 01:12:54 +01:00
|
|
|
command=$1
|
|
|
|
|
|
|
|
# We check for errors ourselves:
|
|
|
|
set +e
|
|
|
|
|
|
|
|
function run_mdadm()
|
|
|
|
{
|
2012-11-19 14:58:33 +01:00
|
|
|
local mdadm_cmd=$1
|
|
|
|
local msg
|
|
|
|
local rc
|
2010-01-16 01:12:54 +01:00
|
|
|
|
2013-10-03 00:41:46 +02:00
|
|
|
msg="$(/sbin/mdadm $mdadm_cmd 2>&1)"
|
2012-11-19 14:58:33 +01:00
|
|
|
rc=$?
|
|
|
|
case "$msg" in
|
|
|
|
*"has been started"* | *"already active"* )
|
|
|
|
return 0
|
|
|
|
;;
|
|
|
|
*"is already in use"* )
|
|
|
|
# hmm, might be used by another device in this domU
|
|
|
|
# leave it to upper layers to detect a real error
|
|
|
|
return 2
|
|
|
|
;;
|
|
|
|
* )
|
|
|
|
return $rc
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
return 1
|
2010-01-16 01:12:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function activate_md()
|
|
|
|
{
|
2013-10-03 00:41:46 +02:00
|
|
|
# Make it explicitly local
|
2012-11-19 14:58:33 +01:00
|
|
|
local par=$1
|
2013-10-03 00:41:46 +02:00
|
|
|
local cfg dev dev_path rc t mdadm_opts
|
2012-11-19 14:58:33 +01:00
|
|
|
|
|
|
|
if [ ${par} = ${par%%(*} ]; then
|
2013-10-03 00:41:46 +02:00
|
|
|
# No configuration file specified
|
2012-11-19 14:58:33 +01:00
|
|
|
dev=$par
|
|
|
|
cfg=
|
|
|
|
else
|
|
|
|
dev=${par%%(*}
|
|
|
|
t=${par#*(}
|
|
|
|
cfg="-c ${t%%)*}"
|
|
|
|
fi
|
2013-10-03 00:41:46 +02:00
|
|
|
|
|
|
|
# Looking for device name or aliase
|
|
|
|
if [ ${dev:0:1} = / ]; then
|
|
|
|
dev_path=${dev%/*}
|
|
|
|
mdadm_opts=
|
|
|
|
else
|
|
|
|
dev_path=/dev/md
|
|
|
|
mdadm_opts="-s -N"
|
2012-11-19 14:58:33 +01:00
|
|
|
fi
|
2013-10-03 00:41:46 +02:00
|
|
|
|
|
|
|
# Is md device already active?
|
|
|
|
# We need to use full path name, aliase is not possible...
|
|
|
|
/sbin/mdadm -Q -D $dev_path/${dev##*/} > /dev/null 2>&1 \
|
|
|
|
&& return 0
|
|
|
|
|
|
|
|
run_mdadm "-A $mdadm_opts $dev $cfg"
|
2012-11-19 14:58:33 +01:00
|
|
|
rc=$?
|
2013-10-03 00:41:46 +02:00
|
|
|
[ $rc -eq 2 ] && return 0
|
|
|
|
|
2012-11-19 14:58:33 +01:00
|
|
|
return $rc
|
2010-01-16 01:12:54 +01:00
|
|
|
}
|
|
|
|
|
2012-11-19 14:58:33 +01:00
|
|
|
function deactivate_md()
|
2010-01-16 01:12:54 +01:00
|
|
|
{
|
2013-10-03 00:41:46 +02:00
|
|
|
local par=$1
|
|
|
|
local dev
|
|
|
|
|
|
|
|
if [ ${par} = ${par%%(*} ]; then
|
|
|
|
# No configuration file specified
|
|
|
|
dev=${par}
|
|
|
|
else
|
|
|
|
dev=${par%%(*}
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Looking for device name or aliase
|
|
|
|
if [ ${dev:0:1} = / ]; then
|
|
|
|
dev_path=${dev%/*}
|
|
|
|
else
|
|
|
|
dev_path=/dev/md
|
|
|
|
fi
|
|
|
|
|
|
|
|
# We need the device name only while deactivating
|
|
|
|
/sbin/mdadm -S ${dev_path}/${dev##*/} > /dev/null 2>&1
|
2010-01-16 01:12:54 +01:00
|
|
|
|
2012-11-19 14:58:33 +01:00
|
|
|
return $?
|
2010-01-16 01:12:54 +01:00
|
|
|
}
|
|
|
|
|
2012-11-19 14:58:33 +01:00
|
|
|
function activate_lvm()
|
2010-01-16 01:12:54 +01:00
|
|
|
{
|
2013-06-01 23:11:56 +02:00
|
|
|
local run_timeout=90
|
|
|
|
local parsed_timeout
|
|
|
|
local end_time
|
|
|
|
|
|
|
|
# Parse device-create-timeout from /etc/xen/xend-config.sxp
|
|
|
|
# If not set, use default timeout of 90s
|
2013-10-03 00:41:46 +02:00
|
|
|
parsed_timeout=$(grep -v "^[ \t]*#.*" /etc/xen/xend-config.sxp \
|
|
|
|
| sed -n 's/(device-create-timeout \+\([0-9]\+\))/\1/p')
|
|
|
|
[ ! -z $parsed_timeout ] \
|
|
|
|
&& run_timeout=$((${parsed_timeout}*9/10))
|
|
|
|
|
|
|
|
# First scan for PVs and VGs
|
|
|
|
# We need this for using md device as PV
|
|
|
|
/sbin/pvscan > /dev/null 2>&1
|
|
|
|
# /sbin/vgscan --mknodes > /dev/null 2>&1
|
2013-06-01 23:11:56 +02:00
|
|
|
|
|
|
|
end_time=$(($(date +%s)+${run_timeout}))
|
|
|
|
while true; do
|
2013-10-03 00:41:46 +02:00
|
|
|
/sbin/lvchange -aey $1 > /dev/null 2>&1
|
|
|
|
|
2013-06-01 23:11:56 +02:00
|
|
|
if [ $? -eq 0 -a -e $1 ]; then
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
|
|
|
|
sleep 0.1
|
|
|
|
if [ $(date +%s) -ge ${end_time} ]; then
|
|
|
|
log err "Failed to activate $1 within ${run_timeout} seconds"
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
done
|
2012-11-19 14:58:33 +01:00
|
|
|
return 1
|
2010-01-16 01:12:54 +01:00
|
|
|
}
|
|
|
|
|
2012-11-19 14:58:33 +01:00
|
|
|
function deactivate_lvm()
|
2010-01-16 01:12:54 +01:00
|
|
|
{
|
2013-10-03 00:41:46 +02:00
|
|
|
/sbin/lvchange -aen $1 > /dev/null 2>&1
|
|
|
|
|
2012-11-19 14:58:33 +01:00
|
|
|
if [ $? -eq 0 ]; then
|
|
|
|
# We may have to deactivate the VG now, but can ignore errors:
|
|
|
|
# /sbin/vgchange -an ${1%/*} || :
|
|
|
|
# Maybe we need to cleanup the LVM cache:
|
|
|
|
# /sbin/vgscan --mknodes || :
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
return 1
|
2010-01-16 01:12:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
BP=100
|
|
|
|
SP=$BP
|
|
|
|
VBD=
|
|
|
|
|
|
|
|
declare -a stack
|
2012-11-19 14:58:33 +01:00
|
|
|
function push()
|
2010-01-16 01:12:54 +01:00
|
|
|
{
|
|
|
|
if [ -z "$1" ]; then
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
let "SP -= 1"
|
|
|
|
stack[$SP]="${1}"
|
|
|
|
}
|
2012-11-19 14:58:33 +01:00
|
|
|
|
|
|
|
function pop()
|
2010-01-16 01:12:54 +01:00
|
|
|
{
|
|
|
|
VBD=
|
|
|
|
|
|
|
|
if [ "$SP" -eq "$BP" ]; then
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
VBD=${stack[$SP]}
|
|
|
|
let "SP += 1"
|
|
|
|
}
|
2012-11-19 14:58:33 +01:00
|
|
|
|
|
|
|
function activate_dmmd()
|
2010-01-16 01:12:54 +01:00
|
|
|
{
|
|
|
|
case $1 in
|
|
|
|
md)
|
|
|
|
activate_md $2
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
lvm)
|
|
|
|
activate_lvm $2
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
2012-11-19 14:58:33 +01:00
|
|
|
|
2010-01-16 01:12:54 +01:00
|
|
|
function deactivate_dmmd()
|
|
|
|
{
|
|
|
|
case "$1" in
|
|
|
|
md)
|
|
|
|
deactivate_md $2
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
lvm)
|
|
|
|
deactivate_lvm $2
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
2012-11-19 14:58:33 +01:00
|
|
|
|
|
|
|
function cleanup_stack()
|
2010-01-16 01:12:54 +01:00
|
|
|
{
|
|
|
|
while [ 1 ]; do
|
|
|
|
pop
|
|
|
|
if [ -z "$VBD" ]; then
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
deactivate_dmmd $VBD
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2012-11-19 14:58:33 +01:00
|
|
|
function parse_par()
|
2010-01-16 01:12:54 +01:00
|
|
|
{
|
|
|
|
local ac par rc s t # Make these explicitly local vars
|
|
|
|
|
|
|
|
ac=$1
|
|
|
|
par="$2"
|
|
|
|
|
|
|
|
par="$par;"
|
|
|
|
while [ 1 ]; do
|
|
|
|
t=${par%%;*}
|
|
|
|
if [ -z "$t" ]; then
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
par=${par#*;}
|
|
|
|
|
|
|
|
s=${par%%;*}
|
|
|
|
if [ -z "$s" ]; then
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
par=${par#*;}
|
|
|
|
|
|
|
|
if [ "$ac" = "activate" ]; then
|
|
|
|
activate_dmmd $t $s
|
|
|
|
rc=$?
|
|
|
|
if [ $rc -ne 0 ]; then
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
push "$t $s"
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case "$command" in
|
2012-11-19 14:58:33 +01:00
|
|
|
add)
|
|
|
|
p=`xenstore-read $XENBUS_PATH/params` || true
|
|
|
|
claim_lock "dmmd"
|
|
|
|
dmmd=$p
|
|
|
|
parse_par activate "$dmmd"
|
|
|
|
rc=$?
|
|
|
|
if [ $rc -ne 0 ]; then
|
|
|
|
cleanup_stack
|
|
|
|
release_lock "dmmd"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
lastparam=${dmmd##*;}
|
|
|
|
usedevice=${lastparam%(*}
|
2013-10-03 00:41:46 +02:00
|
|
|
xenstore-write $XENBUS_PATH/node "$usedevice"
|
|
|
|
write_dev "$usedevice"
|
|
|
|
release_lock "dmmd"
|
|
|
|
exit 0
|
|
|
|
;;
|
2012-11-19 14:58:33 +01:00
|
|
|
|
|
|
|
remove)
|
|
|
|
p=`xenstore-read $XENBUS_PATH/params` || true
|
|
|
|
claim_lock "dmmd"
|
|
|
|
dmmd=$p
|
|
|
|
parse_par noactivate "$dmmd"
|
|
|
|
cleanup_stack
|
|
|
|
release_lock "dmmd"
|
|
|
|
exit 0
|
|
|
|
;;
|
2010-01-16 01:12:54 +01:00
|
|
|
esac
|