xref: /freebsd/sys/contrib/openzfs/cmd/zvol_wait (revision dbd5678dca91abcefe8d046aa2f9b66497a95ffb)
1716fd348SMartin Matuska#!/bin/sh
216038816SMartin Matuska
3716fd348SMartin Matuskacount_zvols() {
4716fd348SMartin Matuska	if [ -z "$zvols" ]; then
5716fd348SMartin Matuska		echo 0
6716fd348SMartin Matuska	else
7716fd348SMartin Matuska		echo "$zvols" | wc -l
8716fd348SMartin Matuska	fi
9716fd348SMartin Matuska}
10e92ffd9bSMartin Matuska
11716fd348SMartin Matuskafilter_out_zvols_with_links() {
12716fd348SMartin Matuska	echo "$zvols" | tr ' ' '+' | while read -r zvol; do
13716fd348SMartin Matuska		if ! [ -L "/dev/zvol/$zvol" ]; then
14716fd348SMartin Matuska			echo "$zvol"
15716fd348SMartin Matuska		fi
16716fd348SMartin Matuska	done | tr '+' ' '
17716fd348SMartin Matuska}
18716fd348SMartin Matuska
19716fd348SMartin Matuskafilter_out_deleted_zvols() {
20716fd348SMartin Matuska	OIFS="$IFS"
21716fd348SMartin Matuska	IFS="
22716fd348SMartin Matuska"
23716fd348SMartin Matuska	# shellcheck disable=SC2086
24716fd348SMartin Matuska	zfs list -H -o name $zvols 2>/dev/null
25716fd348SMartin Matuska	IFS="$OIFS"
26716fd348SMartin Matuska}
27716fd348SMartin Matuska
28716fd348SMartin Matuskalist_zvols() {
29716fd348SMartin Matuska	read -r default_volmode < /sys/module/zfs/parameters/zvol_volmode
30716fd348SMartin Matuska	zfs list -t volume -H -o \
31716fd348SMartin Matuska	    name,volmode,receive_resume_token,redact_snaps,keystatus |
32716fd348SMartin Matuska	    while IFS="	" read -r name volmode token redacted keystatus; do # IFS=\t here!
33716fd348SMartin Matuska
34716fd348SMartin Matuska		# /dev links are not created for zvols with volmode = "none",
35716fd348SMartin Matuska		# redacted zvols, or encrypted zvols for which the key has not
36716fd348SMartin Matuska		# been loaded.
37716fd348SMartin Matuska		[ "$volmode" = "none" ] && continue
38716fd348SMartin Matuska		[ "$volmode" = "default" ] && [ "$default_volmode" = "3" ] &&
39716fd348SMartin Matuska		    continue
40716fd348SMartin Matuska		[ "$redacted" = "-" ] || continue
41716fd348SMartin Matuska		[ "$keystatus" = "unavailable" ] && continue
42716fd348SMartin Matuska
43716fd348SMartin Matuska		# We also ignore partially received zvols if it is
44716fd348SMartin Matuska		# not an incremental receive, as those won't even have a block
45716fd348SMartin Matuska		# device minor node created yet.
46716fd348SMartin Matuska		if [ "$token" != "-" ]; then
47716fd348SMartin Matuska
48716fd348SMartin Matuska			# Incremental receives create an invisible clone that
49716fd348SMartin Matuska			# is not automatically displayed by zfs list.
50716fd348SMartin Matuska			if ! zfs list "$name/%recv" >/dev/null 2>&1; then
51716fd348SMartin Matuska				continue
52716fd348SMartin Matuska			fi
53716fd348SMartin Matuska		fi
54716fd348SMartin Matuska		echo "$name"
55716fd348SMartin Matuska	done
56716fd348SMartin Matuska}
57716fd348SMartin Matuska
58716fd348SMartin Matuskazvols=$(list_zvols)
59716fd348SMartin Matuskazvols_count=$(count_zvols)
60716fd348SMartin Matuskaif [ "$zvols_count" -eq 0 ]; then
61716fd348SMartin Matuska	echo "No zvols found, nothing to do."
62716fd348SMartin Matuska	exit 0
63716fd348SMartin Matuskafi
64716fd348SMartin Matuska
65716fd348SMartin Matuskaecho "Testing $zvols_count zvol links"
66716fd348SMartin Matuska
67716fd348SMartin Matuskaouter_loop=0
68716fd348SMartin Matuskawhile [ "$outer_loop" -lt 20 ]; do
69716fd348SMartin Matuska	outer_loop=$((outer_loop + 1))
70716fd348SMartin Matuska
71716fd348SMartin Matuska	old_zvols_count=$(count_zvols)
72716fd348SMartin Matuska
73716fd348SMartin Matuska	inner_loop=0
74716fd348SMartin Matuska	while [ "$inner_loop" -lt 30 ]; do
75716fd348SMartin Matuska		inner_loop=$((inner_loop + 1))
76716fd348SMartin Matuska
77716fd348SMartin Matuska		zvols="$(filter_out_zvols_with_links)"
78716fd348SMartin Matuska
79716fd348SMartin Matuska		zvols_count=$(count_zvols)
80716fd348SMartin Matuska		if [ "$zvols_count" -eq 0 ]; then
81716fd348SMartin Matuska			echo "All zvol links are now present."
82716fd348SMartin Matuska			exit 0
83716fd348SMartin Matuska		fi
84716fd348SMartin Matuska		sleep 1
85716fd348SMartin Matuska	done
86716fd348SMartin Matuska
87716fd348SMartin Matuska	echo "Still waiting on $zvols_count zvol links ..."
88716fd348SMartin Matuska	#
89716fd348SMartin Matuska	# Although zvols should normally not be deleted at boot time,
90716fd348SMartin Matuska	# if that is the case then their links will be missing and
91716fd348SMartin Matuska	# we would stall.
92716fd348SMartin Matuska	#
93716fd348SMartin Matuska	if [ "$old_zvols_count" -eq "$zvols_count" ]; then
94716fd348SMartin Matuska		echo "No progress since last loop."
95716fd348SMartin Matuska		echo "Checking if any zvols were deleted."
96716fd348SMartin Matuska
97716fd348SMartin Matuska		zvols=$(filter_out_deleted_zvols)
98716fd348SMartin Matuska		zvols_count=$(count_zvols)
99716fd348SMartin Matuska
100716fd348SMartin Matuska		if [ "$old_zvols_count" -ne "$zvols_count" ]; then
101716fd348SMartin Matuska			echo "$((old_zvols_count - zvols_count)) zvol(s) deleted."
102716fd348SMartin Matuska		fi
103716fd348SMartin Matuska
104716fd348SMartin Matuska		if [ "$zvols_count" -ne 0 ]; then
105716fd348SMartin Matuska			echo "Remaining zvols:"
106716fd348SMartin Matuska			echo "$zvols"
107716fd348SMartin Matuska		else
108716fd348SMartin Matuska			echo "All zvol links are now present."
109716fd348SMartin Matuska			exit 0
110716fd348SMartin Matuska		fi
111716fd348SMartin Matuska	fi
112*dbd5678dSMartin Matuska
113*dbd5678dSMartin Matuska	#
114*dbd5678dSMartin Matuska	# zvol_count made some progress - let's stay in this loop.
115*dbd5678dSMartin Matuska	#
116*dbd5678dSMartin Matuska	if [ "$old_zvols_count" -gt "$zvols_count" ]; then
117*dbd5678dSMartin Matuska		outer_loop=$((outer_loop - 1))
118*dbd5678dSMartin Matuska	fi
119716fd348SMartin Matuskadone
120716fd348SMartin Matuska
121716fd348SMartin Matuskaecho "Timed out waiting on zvol links"
122716fd348SMartin Matuskaexit 1
123