#!/bin/sh count_zvols() { if [ -z "$zvols" ]; then echo 0 else echo "$zvols" | wc -l fi } filter_out_zvols_with_links() { echo "$zvols" | tr ' ' '+' | while read -r zvol; do if ! [ -L "/dev/zvol/$zvol" ]; then echo "$zvol" fi done | tr '+' ' ' } filter_out_deleted_zvols() { OIFS="$IFS" IFS=" " # shellcheck disable=SC2086 zfs list -H -o name $zvols 2>/dev/null IFS="$OIFS" } list_zvols() { read -r default_volmode < /sys/module/zfs/parameters/zvol_volmode zfs list -t volume -H -o \ name,volmode,receive_resume_token,redact_snaps,keystatus | while IFS=" " read -r name volmode token redacted keystatus; do # IFS=\t here! # /dev links are not created for zvols with volmode = "none", # redacted zvols, or encrypted zvols for which the key has not # been loaded. [ "$volmode" = "none" ] && continue [ "$volmode" = "default" ] && [ "$default_volmode" = "3" ] && continue [ "$redacted" = "-" ] || continue [ "$keystatus" = "unavailable" ] && continue # We also ignore partially received zvols if it is # not an incremental receive, as those won't even have a block # device minor node created yet. if [ "$token" != "-" ]; then # Incremental receives create an invisible clone that # is not automatically displayed by zfs list. if ! zfs list "$name/%recv" >/dev/null 2>&1; then continue fi fi echo "$name" done } zvols=$(list_zvols) zvols_count=$(count_zvols) if [ "$zvols_count" -eq 0 ]; then echo "No zvols found, nothing to do." exit 0 fi echo "Testing $zvols_count zvol links" outer_loop=0 while [ "$outer_loop" -lt 20 ]; do outer_loop=$((outer_loop + 1)) old_zvols_count=$(count_zvols) inner_loop=0 while [ "$inner_loop" -lt 30 ]; do inner_loop=$((inner_loop + 1)) zvols="$(filter_out_zvols_with_links)" zvols_count=$(count_zvols) if [ "$zvols_count" -eq 0 ]; then echo "All zvol links are now present." exit 0 fi sleep 1 done echo "Still waiting on $zvols_count zvol links ..." # # Although zvols should normally not be deleted at boot time, # if that is the case then their links will be missing and # we would stall. # if [ "$old_zvols_count" -eq "$zvols_count" ]; then echo "No progress since last loop." echo "Checking if any zvols were deleted." zvols=$(filter_out_deleted_zvols) zvols_count=$(count_zvols) if [ "$old_zvols_count" -ne "$zvols_count" ]; then echo "$((old_zvols_count - zvols_count)) zvol(s) deleted." fi if [ "$zvols_count" -ne 0 ]; then echo "Remaining zvols:" echo "$zvols" else echo "All zvol links are now present." exit 0 fi fi done echo "Timed out waiting on zvol links" exit 1