1#!/bin/sh 2 3count_zvols() { 4 if [ -z "$zvols" ]; then 5 echo 0 6 else 7 echo "$zvols" | wc -l 8 fi 9} 10 11filter_out_zvols_with_links() { 12 echo "$zvols" | tr ' ' '+' | while read -r zvol; do 13 if ! [ -L "/dev/zvol/$zvol" ]; then 14 echo "$zvol" 15 fi 16 done | tr '+' ' ' 17} 18 19filter_out_deleted_zvols() { 20 OIFS="$IFS" 21 IFS=" 22" 23 # shellcheck disable=SC2086 24 zfs list -H -o name $zvols 2>/dev/null 25 IFS="$OIFS" 26} 27 28list_zvols() { 29 read -r default_volmode < /sys/module/zfs/parameters/zvol_volmode 30 zfs list -t volume -H -o \ 31 name,volmode,receive_resume_token,redact_snaps,keystatus | 32 while IFS=" " read -r name volmode token redacted keystatus; do # IFS=\t here! 33 34 # /dev links are not created for zvols with volmode = "none", 35 # redacted zvols, or encrypted zvols for which the key has not 36 # been loaded. 37 [ "$volmode" = "none" ] && continue 38 [ "$volmode" = "default" ] && [ "$default_volmode" = "3" ] && 39 continue 40 [ "$redacted" = "-" ] || continue 41 [ "$keystatus" = "unavailable" ] && continue 42 43 # We also ignore partially received zvols if it is 44 # not an incremental receive, as those won't even have a block 45 # device minor node created yet. 46 if [ "$token" != "-" ]; then 47 48 # Incremental receives create an invisible clone that 49 # is not automatically displayed by zfs list. 50 if ! zfs list "$name/%recv" >/dev/null 2>&1; then 51 continue 52 fi 53 fi 54 echo "$name" 55 done 56} 57 58zvols=$(list_zvols) 59zvols_count=$(count_zvols) 60if [ "$zvols_count" -eq 0 ]; then 61 echo "No zvols found, nothing to do." 62 exit 0 63fi 64 65echo "Testing $zvols_count zvol links" 66 67outer_loop=0 68while [ "$outer_loop" -lt 20 ]; do 69 outer_loop=$((outer_loop + 1)) 70 71 old_zvols_count=$(count_zvols) 72 73 inner_loop=0 74 while [ "$inner_loop" -lt 30 ]; do 75 inner_loop=$((inner_loop + 1)) 76 77 zvols="$(filter_out_zvols_with_links)" 78 79 zvols_count=$(count_zvols) 80 if [ "$zvols_count" -eq 0 ]; then 81 echo "All zvol links are now present." 82 exit 0 83 fi 84 sleep 1 85 done 86 87 echo "Still waiting on $zvols_count zvol links ..." 88 # 89 # Although zvols should normally not be deleted at boot time, 90 # if that is the case then their links will be missing and 91 # we would stall. 92 # 93 if [ "$old_zvols_count" -eq "$zvols_count" ]; then 94 echo "No progress since last loop." 95 echo "Checking if any zvols were deleted." 96 97 zvols=$(filter_out_deleted_zvols) 98 zvols_count=$(count_zvols) 99 100 if [ "$old_zvols_count" -ne "$zvols_count" ]; then 101 echo "$((old_zvols_count - zvols_count)) zvol(s) deleted." 102 fi 103 104 if [ "$zvols_count" -ne 0 ]; then 105 echo "Remaining zvols:" 106 echo "$zvols" 107 else 108 echo "All zvol links are now present." 109 exit 0 110 fi 111 fi 112 113 # 114 # zvol_count made some progress - let's stay in this loop. 115 # 116 if [ "$old_zvols_count" -gt "$zvols_count" ]; then 117 outer_loop=$((outer_loop - 1)) 118 fi 119done 120 121echo "Timed out waiting on zvol links" 122exit 1 123