With this patch, it's possible to shut down guests in parallel. Parallel startup was possible before, but this functionality was not documented properly. To enable parallel startup set the START_DELAY to 0. Parallel shutdown has a configurable parameter PARALLEL_SHUTDOWN that defines the number of machines being shut down in parallel. Enabling this feature changes the semantics of SHUTDOWN_TIMEOUT parameter that is applied as a cumulative timeout to shutdown all guests on a URI. --- Diff to v1: -changed "domains" to "guests" -used efficient code to avoid subshells -remove unused helper functions -added error message when loosing track of guest in case of error -added docs that setting of SHUTDOWN_TIMEOUT is needed with shutdown action -added initialisation of PARALLEL_SHUTDOWN -fixed output redirections -fixed typo in sysconfig file tools/libvirt-guests.init.sh | 116 +++++++++++++++++++++++++++++++++++++++--- tools/libvirt-guests.sysconf | 12 ++++- 2 files changed, 119 insertions(+), 9 deletions(-) diff --git a/tools/libvirt-guests.init.sh b/tools/libvirt-guests.init.sh index c867ece..141d7fa 100644 --- a/tools/libvirt-guests.init.sh +++ b/tools/libvirt-guests.init.sh @@ -42,6 +42,7 @@ URIS=default ON_BOOT=start ON_SHUTDOWN=suspend SHUTDOWN_TIMEOUT=0 +PARALLEL_SHUTDOWN=0 START_DELAY=0 BYPASS_CACHE=0 @@ -273,6 +274,102 @@ shutdown_guest() fi } +# shutdown_guest_async URI GUEST +# Start a ACPI shutdown of GUEST on URI. This function returns after the command +# was issued to libvirt to allow parallel shutdown. +shutdown_guest_async() +{ + uri=$1 + guest=$2 + + name=$(guest_name "$uri" "$guest") + eval_gettext "Starting shutdown on guest: \$name" + echo + retval run_virsh "$uri" shutdown "$guest" > /dev/null +} + +# guest_count GUEST_LIST +# Returns number of guests in GUEST_LIST +guest_count() +{ + set -- $1 + echo $# +} + +# check_guests_shutdown URI GUESTS +# check if shutdown is complete on guests in "GUESTS" and returns only +# guests that are still shutting down +check_guests_shutdown() +{ + uri=$1 + guests=$2 + + guests_up= + for guest in $guests; do + if ! guest_is_on "$uri" "$guest" >/dev/null 2>&1; then + eval_gettext "Failed to determine state of guest: \$guest. Not tracking it anymore." + echo + continue + fi + if "$guest_running"; then + guests_up="$guests_up $guest" + fi + done + echo "$guests_up" +} + +# print_guests_shutdown URI BEFORE AFTER +# Checks for differences in the lists BEFORE and AFTER and prints +# a shutdown complete notice for guests that have finished +print_guests_shutdown() +{ + uri=$1 + before=$2 + after=$3 + + for guest in $before; do + case " $after " in + *" $guest "*) continue;; + esac + + name=$(guest_name "$uri" "$guest") + eval_gettext "Shutdown of guest \$name complete." + echo + done +} + +# shutdown_guests_parallel URI GUESTS +# Shutdown guests GUESTS on machine URI in parallel +shutdown_guests_parallel() +{ + uri=$1 + guests=$2 + + on_shutdown= + timeout=$SHUTDOWN_TIMEOUT + while [ -n "$on_shutdown" ] || [ -n "$guests" ]; do + while [ -n "$guests" ] && + [ $(guest_count "$on_shutdown") -lt "$PARALLEL_SHUTDOWN" ]; do + set -- $guests + guest=$1 + shift + guests=$* + shutdown_guest_async "$uri" "$guest" + on_shutdown="$on_shutdown $guest" + done + sleep 1 + timeout=$(($timeout - 1)) + if [ $timeout -le 0 ]; then + eval_gettext "Timeout expired while shutting down domains"; echo + RETVAL=1 + return + fi + on_shutdown_prev=$on_shutdown + on_shutdown=$(check_guests_shutdown "$uri" "$on_shutdown") + print_guests_shutdown "$uri" "$on_shutdown_prev" "$on_shutdown" + done +} + # stop # Shutdown or save guests on the configured uris stop() { @@ -359,13 +456,18 @@ stop() { eval_gettext "Shutting down guests on \$uri URI..."; echo fi - for guest in $list; do - if "$suspending"; then - suspend_guest "$uri" "$guest" - else - shutdown_guest "$uri" "$guest" - fi - done + if [ "$PARALLEL_SHUTDOWN" -gt 1 ] && + ! "$suspending"; then + shutdown_guests_parallel "$uri" "$list" + else + for guest in $list; do + if "$suspending"; then + suspend_guest "$uri" "$guest" + else + shutdown_guest "$uri" "$guest" + fi + done + fi done <"$LISTFILE" rm -f "$VAR_SUBSYS_LIBVIRT_GUESTS" diff --git a/tools/libvirt-guests.sysconf b/tools/libvirt-guests.sysconf index 9b8b64f..3e0db46 100644 --- a/tools/libvirt-guests.sysconf +++ b/tools/libvirt-guests.sysconf @@ -10,7 +10,8 @@ # libvirtd #ON_BOOT=start -# number of seconds to wait between each guest start +# Number of seconds to wait between each guest start. Set to 0 to allow +# parallel startup. #START_DELAY=0 # action taken on host shutdown @@ -23,7 +24,14 @@ # value suitable for your guests. #ON_SHUTDOWN=suspend -# number of seconds we're willing to wait for a guest to shut down +# If set to non-zero, shutdown will suspend guests concurrently. Number of +# guests on shutdown at any time will not exceed number set in this variable. +#PARALLEL_SHUTDOWN=0 + +# Number of seconds we're willing to wait for a guest to shut down. If parallel +# shutdown is enabled, this timeout applies as a timeout for shutting down all +# guests on a single URI defined in the variable URIS. This must be set to +# a nonzero positive value if the shutdown action is requested. #SHUTDOWN_TIMEOUT=0 # If non-zero, try to bypass the file system cache when saving and -- 1.7.3.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list