mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
backendtype=phy using the blktap kernel module needs to use write_dev,
but tapback can't support that. tapback should perform better, but make
the script compatible with the old kernel module again.
Fixes: 76a484193d ("hotplug: Update block-tap")
Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
Acked-by: Anthony PERARD <anthony.perard@vates.tech>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
278 lines
6.8 KiB
Bash
Executable File
278 lines
6.8 KiB
Bash
Executable File
#!/bin/bash -e
|
|
#
|
|
# tapdisk Xen block device hotplug script
|
|
#
|
|
# Author George Dunlap <george.dunlap@eu.citrix.com>
|
|
#
|
|
# Based on block-iscsi by Roger Pau Monné <roger.pau@citrix.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU Lesser General Public License as published
|
|
# by the Free Software Foundation; version 2.1 only. with the special
|
|
# exception on linking described in file LICENSE.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Lesser General Public License for more details.
|
|
#
|
|
# Usage:
|
|
#
|
|
# Disks should be specified using the following syntax:
|
|
#
|
|
# For use with tapback (vbd3) (preferred):
|
|
# vdev=xvda,backendtype=tap,format=vhd,target=/srv/target.vhd
|
|
#
|
|
# For use with blkback and the blktap2 kernel module:
|
|
# script=block-tap,vdev=xvda,target=<type>:<file>
|
|
#
|
|
# format/<type> is either "aio" (for raw files), or "vhd"
|
|
|
|
dir=$(dirname "$0")
|
|
. "$dir/block-common.sh"
|
|
|
|
remove_label()
|
|
{
|
|
echo $1 | sed "s/^\("$2"\)//"
|
|
}
|
|
|
|
check_tools()
|
|
{
|
|
if ! command -v tap-ctl > /dev/null 2>&1; then
|
|
fatal "Unable to find tap-ctl tool"
|
|
fi
|
|
}
|
|
|
|
# Sets the following global variables based on the params field passed in as
|
|
# a parameter: type file
|
|
parse_target()
|
|
{
|
|
params=($(echo "$1" | tr ":" "\n"))
|
|
|
|
type=${params[0]}
|
|
file=${params[1]}
|
|
if [ -z "$type" ] || [ -z "$file" ]; then
|
|
fatal "Cannot parse required parameters"
|
|
fi
|
|
}
|
|
|
|
# Sets $pid and $minor to point to the device associated with the target
|
|
find_device()
|
|
{
|
|
local info
|
|
local param
|
|
|
|
if [ -z "$type" ] || [ -z "$file" ]; then
|
|
fatal "required parameters not set"
|
|
fi
|
|
|
|
info=$(tap-ctl list -t $type -f $file)
|
|
|
|
for param in $(echo "$info" | tr "," "\n")
|
|
do
|
|
case $param in
|
|
pid=*)
|
|
pid=$(remove_label $param "pid=")
|
|
;;
|
|
minor=*)
|
|
minor=$(remove_label $param "minor=")
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$pid" ] || [ -z "$minor" ]; then
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
count_using()
|
|
{
|
|
local file="$1"
|
|
local dom
|
|
local dev
|
|
local f
|
|
|
|
local i=0
|
|
local base_path="$XENBUS_BASE_PATH/$XENBUS_TYPE"
|
|
for dom in $(xenstore-list "$base_path")
|
|
do
|
|
for dev in $(xenstore-list "$base_path/$dom")
|
|
do
|
|
f=$(xenstore_read_default "$base_path/$dom/$dev/params" "")
|
|
f=$(echo "$f" | cut -d ":" -f 2)
|
|
|
|
if [ -n "$f" ] && [ "$file" = $f ] ; then
|
|
i=$(( i + 1 ))
|
|
fi
|
|
done
|
|
done
|
|
|
|
echo "$i"
|
|
}
|
|
|
|
# tap_shared is used to determine if a shared tap can be closed
|
|
# Since a stubdom and a guest both use the same tap, it can only
|
|
# be freed when there is a single one left.
|
|
tap_shared() {
|
|
[ $( count_using "$file" ) -gt 1 ]
|
|
}
|
|
|
|
check_tap_sharing()
|
|
{
|
|
local file="$1"
|
|
local mode="$2"
|
|
local dom
|
|
local dev
|
|
|
|
local base_path="$XENBUS_BASE_PATH/$XENBUS_TYPE"
|
|
for dom in $(xenstore-list "$base_path") ; do
|
|
for dev in $(xenstore-list "$base_path/$dom") ; do
|
|
local f=$(xenstore_read_default "$base_path/$dom/$dev/params" "")
|
|
f=$(echo "$f" | cut -d ":" -f 2)
|
|
|
|
if [ -n "$f" ] && [ "$file" = "$f" ] ; then
|
|
if [ "$mode" = 'w' ] ; then
|
|
if ! same_vm $dom ; then
|
|
echo "guest $f"
|
|
return
|
|
fi
|
|
else
|
|
local m=$(xenstore_read_default "$base_path/$dom/$dev/mode"
|
|
"")
|
|
m=$(canonicalise_mode "$m")
|
|
|
|
if [ "$m" = 'w' ] ; then
|
|
if ! same_vm $dom ; then
|
|
echo "guest $f"
|
|
return
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
done
|
|
|
|
echo 'ok'
|
|
}
|
|
|
|
tap_create()
|
|
{
|
|
if ! minor=$( tap-ctl allocate ) ; then
|
|
fatal "Could not allocate minor"
|
|
fi
|
|
|
|
# Handle with or without kernel blktap
|
|
minor=${minor#/run/blktap-control/tapdisk/tapdisk-}
|
|
minor=${minor#/dev/xen/blktap-2/tapdev}
|
|
|
|
# tap-ctl is spawning tapdisk which would hold the _lockfd open.
|
|
# Ensure it is closed before running tap-ctl spawn, which needs to be
|
|
# done in a subshell to continue holding the lock in the parent.
|
|
if ! pid=$( ( eval "exec $_lockfd>&-" ; tap-ctl spawn ) ) ; then
|
|
tap-ctl free -m "$minor"
|
|
fatal "Could not spawn tapdisk for $minor"
|
|
fi
|
|
|
|
if ! tap-ctl attach -p "$pid" -m "$minor" ; then
|
|
tap-ctl free -m "$minor"
|
|
fatal "Could not attach $pid and $minor"
|
|
fi
|
|
|
|
if ! tap-ctl open -p "$pid" -m "$minor" -a "$target" ; then
|
|
tap-ctl detach -p "$pid" -m "$minor"
|
|
tap-ctl free -m "$minor"
|
|
fatal "Could not open \"$target\""
|
|
fi
|
|
}
|
|
|
|
# Attaches the device and writes xenstore backend entries to connect
|
|
# the device
|
|
add()
|
|
{
|
|
local result
|
|
|
|
claim_lock "block"
|
|
|
|
if find_device; then
|
|
result=$( check_tap_sharing "$file" "$mode" )
|
|
if [ "$result" != "ok" ] ; then
|
|
do_ebusy "tap $type file $file in use " "$mode" "${result%% *}"
|
|
fi
|
|
else
|
|
tap_create
|
|
fi
|
|
|
|
# Create nbd unix path. find_device/tap_create set pid & minor
|
|
dev=$( printf "/run/blktap-control/nbd%ld.%d" "$pid" "$minor" )
|
|
|
|
xenstore_write "$XENBUS_PATH/pid" "$pid"
|
|
xenstore_write "$XENBUS_PATH/minor" "$minor"
|
|
|
|
if [ "$XENBUS_TYPE" = "vbd3" ] ; then
|
|
# $dev, as a unix socket, has major:minor 0:0. If write_dev writes
|
|
# physical-device, tapback would use that incorrect minor 0. So don't
|
|
# write physical-device.
|
|
xenstore_write "$XENBUS_PATH/physical-device-path" "$dev"
|
|
|
|
success
|
|
else
|
|
write_dev "$dev"
|
|
fi
|
|
|
|
release_lock "block"
|
|
}
|
|
|
|
# Disconnects the device
|
|
remove()
|
|
{
|
|
local minor
|
|
local pid
|
|
|
|
claim_lock "block"
|
|
|
|
if tap_shared ; then
|
|
return
|
|
fi
|
|
|
|
minor=$( xenstore_read "$XENBUS_PATH/minor" )
|
|
pid=$( xenstore_read "$XENBUS_PATH/pid" )
|
|
|
|
[ -n "$minor" ] || fatal "minor missing"
|
|
[ -n "$pid" ] || fatal "pid missing"
|
|
do_or_die tap-ctl destroy -p "$pid" -m "$minor" > /dev/null
|
|
|
|
release_lock "block"
|
|
}
|
|
|
|
command=$1
|
|
target=$(xenstore-read $XENBUS_PATH/params || true)
|
|
if [ -z "$target" ]; then
|
|
fatal "No information about the target"
|
|
fi
|
|
|
|
parse_target "$target"
|
|
|
|
check_tools || exit 1
|
|
|
|
mode=$( xenstore_read $XENBUS_PATH/mode )
|
|
mode=$( canonicalise_mode $mode )
|
|
|
|
# needed for same_vm
|
|
FRONTEND_ID=$(xenstore_read "$XENBUS_PATH/frontend-id")
|
|
FRONTEND_UUID=$(xenstore_read_default \
|
|
"/local/domain/$FRONTEND_ID/vm" 'unknown')
|
|
|
|
case $command in
|
|
add)
|
|
add
|
|
;;
|
|
remove)
|
|
remove
|
|
;;
|
|
*)
|
|
exit 1
|
|
;;
|
|
esac
|