256 lines
4.6 KiB
Plaintext
256 lines
4.6 KiB
Plaintext
|
#! /bin/bash
|
||
|
|
||
|
# Usage: block-dmmd [add args | remove args]
|
||
|
#
|
||
|
# the xm config file should have something like:
|
||
|
# dmmd:md;/dev/md0;md;/dev/md1;lvm;/dev/vg1/lv1
|
||
|
# or
|
||
|
# dmmd:lvm;/dev/vg1/lv1;lvm;/dev/vg1/lv2;md;/dev/md0
|
||
|
# note the last device will be used for VM
|
||
|
|
||
|
# History:
|
||
|
# 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
|
||
|
echo ""
|
||
|
date
|
||
|
set -x
|
||
|
echo shell-flags: $-
|
||
|
command=$1
|
||
|
|
||
|
# We check for errors ourselves:
|
||
|
set +e
|
||
|
|
||
|
function run_mdadm()
|
||
|
{
|
||
|
local mdadm_cmd=$1
|
||
|
local msg
|
||
|
local rc
|
||
|
|
||
|
msg="`/sbin/mdadm $mdadm_cmd 2>&1`"
|
||
|
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
|
||
|
}
|
||
|
|
||
|
function activate_md()
|
||
|
{
|
||
|
local par=$1
|
||
|
local already_active=0 cfg dev rc t
|
||
|
|
||
|
if [ ${par} = ${par%%(*} ]; then
|
||
|
# No configuration file specified:
|
||
|
dev=$par
|
||
|
cfd=
|
||
|
else
|
||
|
dev=${par%%(*}
|
||
|
t=${par#*(}
|
||
|
cfg="-c ${t%%)*}"
|
||
|
fi
|
||
|
if /sbin/mdadm -Q -D $dev; then
|
||
|
already_active=1
|
||
|
fi
|
||
|
run_mdadm "-A $dev $cfg"
|
||
|
rc=$?
|
||
|
if [ $already_active -eq 1 ] && [ $rc -eq 2 ]; then
|
||
|
return 0
|
||
|
fi
|
||
|
return $rc
|
||
|
}
|
||
|
|
||
|
function deactivate_md ()
|
||
|
{
|
||
|
local par=$1 # Make it explicitly local
|
||
|
|
||
|
## We need the device name only while deactivating
|
||
|
/sbin/mdadm -S ${par%%(*}
|
||
|
return $?
|
||
|
}
|
||
|
|
||
|
function activate_lvm ()
|
||
|
{
|
||
|
# First scan for PVs and VGs; we may then have to activate the VG
|
||
|
# first, but can ignore errors:
|
||
|
/sbin/pvscan || :
|
||
|
/sbin/vgscan --mknodes || :
|
||
|
/sbin/vgchange -ay ${1%/*} || :
|
||
|
/sbin/lvchange -ay $1
|
||
|
return $?
|
||
|
}
|
||
|
|
||
|
function deactivate_lvm ()
|
||
|
{
|
||
|
/sbin/lvchange -an $1
|
||
|
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
|
||
|
}
|
||
|
|
||
|
BP=100
|
||
|
SP=$BP
|
||
|
VBD=
|
||
|
|
||
|
declare -a stack
|
||
|
function push ()
|
||
|
{
|
||
|
if [ -z "$1" ]; then
|
||
|
return
|
||
|
fi
|
||
|
let "SP -= 1"
|
||
|
stack[$SP]="${1}"
|
||
|
return
|
||
|
}
|
||
|
function pop ()
|
||
|
{
|
||
|
VBD=
|
||
|
|
||
|
if [ "$SP" -eq "$BP" ]; then
|
||
|
return
|
||
|
fi
|
||
|
|
||
|
VBD=${stack[$SP]}
|
||
|
let "SP += 1"
|
||
|
return
|
||
|
}
|
||
|
function activate_dmmd ()
|
||
|
{
|
||
|
# echo $1 $2
|
||
|
case $1 in
|
||
|
md)
|
||
|
activate_md $2
|
||
|
return
|
||
|
;;
|
||
|
lvm)
|
||
|
activate_lvm $2
|
||
|
return
|
||
|
;;
|
||
|
esac
|
||
|
}
|
||
|
function deactivate_dmmd()
|
||
|
{
|
||
|
case "$1" in
|
||
|
md)
|
||
|
deactivate_md $2
|
||
|
return
|
||
|
;;
|
||
|
lvm)
|
||
|
deactivate_lvm $2
|
||
|
return
|
||
|
;;
|
||
|
esac
|
||
|
}
|
||
|
function cleanup_stack ()
|
||
|
{
|
||
|
while [ 1 ]; do
|
||
|
pop
|
||
|
if [ -z "$VBD" ]; then
|
||
|
break
|
||
|
fi
|
||
|
deactivate_dmmd $VBD
|
||
|
done
|
||
|
return
|
||
|
}
|
||
|
|
||
|
function parse_par ()
|
||
|
{
|
||
|
local ac par rc s t # Make these explicitly local vars
|
||
|
|
||
|
ac=$1
|
||
|
par="$2"
|
||
|
|
||
|
echo "parse_paring $1, $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#*;}
|
||
|
|
||
|
echo "type is $t, dev is $s"
|
||
|
if [ "$ac" = "activate" ]; then
|
||
|
activate_dmmd $t $s
|
||
|
rc=$?
|
||
|
if [ $rc -ne 0 ]; then
|
||
|
return 1
|
||
|
fi
|
||
|
fi
|
||
|
echo "push $t $s"
|
||
|
push "$t $s"
|
||
|
|
||
|
done
|
||
|
}
|
||
|
|
||
|
echo $command
|
||
|
|
||
|
case "$command" in
|
||
|
add)
|
||
|
p=`xenstore-read $XENBUS_PATH/params` || true
|
||
|
claim_lock "dmmd"
|
||
|
dmmd=$p
|
||
|
echo "before parse_par $dmmd"
|
||
|
parse_par activate "$dmmd"
|
||
|
rc=$?
|
||
|
echo "reach here with rc: $rc"
|
||
|
if [ $rc -ne 0 ]; then
|
||
|
cleanup_stack
|
||
|
release_lock "dmmd"
|
||
|
exit 1
|
||
|
fi
|
||
|
claim_lock "block"
|
||
|
xenstore-write $XENBUS_PATH/node ${dmmd##*;}
|
||
|
write_dev ${dmmd##*;}
|
||
|
release_lock "block"
|
||
|
release_lock "dmmd"
|
||
|
exit 0
|
||
|
;;
|
||
|
|
||
|
remove)
|
||
|
p=`xenstore-read $XENBUS_PATH/params` || true
|
||
|
claim_lock "dmmd"
|
||
|
dmmd=$p
|
||
|
parse_par noactivate "$dmmd"
|
||
|
cleanup_stack
|
||
|
release_lock "dmmd"
|
||
|
exit 0
|
||
|
;;
|
||
|
esac
|