summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/Makefile.am2
-rw-r--r--cmd/zvol_wait/Makefile.am1
-rwxr-xr-xcmd/zvol_wait/zvol_wait93
-rw-r--r--configure.ac1
-rw-r--r--etc/systemd/system/50-zfs.preset.in1
-rw-r--r--etc/systemd/system/Makefile.am4
-rw-r--r--etc/systemd/system/zfs-volume-wait.service.in13
-rw-r--r--etc/systemd/system/zfs-volumes.target.in7
-rw-r--r--man/man1/Makefile.am2
-rw-r--r--man/man1/zvol_wait.121
-rw-r--r--rpm/generic/zfs.spec.in3
11 files changed, 145 insertions, 3 deletions
diff --git a/cmd/Makefile.am b/cmd/Makefile.am
index 0d990789b..88609e455 100644
--- a/cmd/Makefile.am
+++ b/cmd/Makefile.am
@@ -5,4 +5,4 @@ if USING_PYTHON
SUBDIRS += arcstat arc_summary dbufstat
endif
-SUBDIRS += mount_zfs zed zvol_id
+SUBDIRS += mount_zfs zed zvol_id zvol_wait
diff --git a/cmd/zvol_wait/Makefile.am b/cmd/zvol_wait/Makefile.am
new file mode 100644
index 000000000..564031c97
--- /dev/null
+++ b/cmd/zvol_wait/Makefile.am
@@ -0,0 +1 @@
+dist_bin_SCRIPTS = zvol_wait
diff --git a/cmd/zvol_wait/zvol_wait b/cmd/zvol_wait/zvol_wait
new file mode 100755
index 000000000..d512be41b
--- /dev/null
+++ b/cmd/zvol_wait/zvol_wait
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+count_zvols() {
+ if [ -z "$zvols" ]; then
+ echo 0
+ else
+ echo "$zvols" | wc -l
+ fi
+}
+
+filter_out_zvols_with_links() {
+ while read -r zvol; do
+ if [ ! -L "/dev/zvol/$zvol" ]; then
+ echo "$zvol"
+ fi
+ done
+}
+
+filter_out_deleted_zvols() {
+ while read -r zvol; do
+ if zfs list "$zvol" >/dev/null 2>&1; then
+ echo "$zvol"
+ fi
+ done
+}
+
+list_zvols() {
+ zfs list -t volume -H -o name,volmode | while read -r zvol_line; do
+ name=$(echo "$zvol_line" | awk '{print $1}')
+ volmode=$(echo "$zvol_line" | awk '{print $2}')
+ # /dev links are not created for zvols with volmode = "none".
+ [ "$volmode" = "none" ] || 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="$(echo "$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=$(echo "$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
diff --git a/configure.ac b/configure.ac
index f1d3ddc20..9e4f8ff11 100644
--- a/configure.ac
+++ b/configure.ac
@@ -123,6 +123,7 @@ AC_CONFIG_FILES([
cmd/zed/zed.d/Makefile
cmd/raidz_test/Makefile
cmd/zgenhostid/Makefile
+ cmd/zvol_wait/Makefile
contrib/Makefile
contrib/bash_completion.d/Makefile
contrib/dracut/Makefile
diff --git a/etc/systemd/system/50-zfs.preset.in b/etc/systemd/system/50-zfs.preset.in
index 884a69b5b..e4056a92c 100644
--- a/etc/systemd/system/50-zfs.preset.in
+++ b/etc/systemd/system/50-zfs.preset.in
@@ -5,4 +5,5 @@ enable zfs-import.target
enable zfs-mount.service
enable zfs-share.service
enable zfs-zed.service
+enable zfs-volume-wait.service
enable zfs.target
diff --git a/etc/systemd/system/Makefile.am b/etc/systemd/system/Makefile.am
index 1586209ca..9249f15eb 100644
--- a/etc/systemd/system/Makefile.am
+++ b/etc/systemd/system/Makefile.am
@@ -7,7 +7,9 @@ systemdunit_DATA = \
zfs-import-scan.service \
zfs-mount.service \
zfs-share.service \
+ zfs-volume-wait.service \
zfs-import.target \
+ zfs-volumes.target \
zfs.target
EXTRA_DIST = \
@@ -17,6 +19,8 @@ EXTRA_DIST = \
$(top_srcdir)/etc/systemd/system/zfs-mount.service.in \
$(top_srcdir)/etc/systemd/system/zfs-share.service.in \
$(top_srcdir)/etc/systemd/system/zfs-import.target.in \
+ $(top_srcdir)/etc/systemd/system/zfs-volume-wait.service.in \
+ $(top_srcdir)/etc/systemd/system/zfs-volumes.target.in \
$(top_srcdir)/etc/systemd/system/zfs.target.in \
$(top_srcdir)/etc/systemd/system/50-zfs.preset.in
diff --git a/etc/systemd/system/zfs-volume-wait.service.in b/etc/systemd/system/zfs-volume-wait.service.in
new file mode 100644
index 000000000..75bd9fcdd
--- /dev/null
+++ b/etc/systemd/system/zfs-volume-wait.service.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=Wait for ZFS Volume (zvol) links in /dev
+DefaultDependencies=no
+After=systemd-udev-settle.service
+After=zfs-import.target
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=@bindir@/zvol_wait
+
+[Install]
+WantedBy=zfs-volumes.target
diff --git a/etc/systemd/system/zfs-volumes.target.in b/etc/systemd/system/zfs-volumes.target.in
new file mode 100644
index 000000000..5cb9a10f4
--- /dev/null
+++ b/etc/systemd/system/zfs-volumes.target.in
@@ -0,0 +1,7 @@
+[Unit]
+Description=ZFS volumes are ready
+After=zfs-volume-wait.service
+Requires=zfs-volume-wait.service
+
+[Install]
+WantedBy=zfs.target
diff --git a/man/man1/Makefile.am b/man/man1/Makefile.am
index bd78be145..2af917fa5 100644
--- a/man/man1/Makefile.am
+++ b/man/man1/Makefile.am
@@ -1,4 +1,4 @@
-dist_man_MANS = zhack.1 ztest.1 raidz_test.1
+dist_man_MANS = zhack.1 ztest.1 raidz_test.1 zvol_wait.1
EXTRA_DIST = cstyle.1
install-data-local:
diff --git a/man/man1/zvol_wait.1 b/man/man1/zvol_wait.1
new file mode 100644
index 000000000..0366da537
--- /dev/null
+++ b/man/man1/zvol_wait.1
@@ -0,0 +1,21 @@
+.Dd July 5, 2019
+.Dt ZVOL_WAIT 1 SMM
+.Os Linux
+.Sh NAME
+.Nm zvol_wait
+.Nd Wait for ZFS volume links in
+.Em /dev
+to be created.
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+When a ZFS pool is imported, ZFS will register each ZFS volume
+(zvol) as a disk device with the system. As the disks are registered,
+.Xr \fBudev 7\fR
+will asynchronously create symlinks under
+.Em /dev/zvol
+using the zvol's name.
+.Nm
+will wait for all those symlinks to be created before returning.
+.Sh SEE ALSO
+.Xr \fBudev 7\fR
diff --git a/rpm/generic/zfs.spec.in b/rpm/generic/zfs.spec.in
index 0864a72a1..4fdf7bb69 100644
--- a/rpm/generic/zfs.spec.in
+++ b/rpm/generic/zfs.spec.in
@@ -322,7 +322,7 @@ image which is ZFS aware.
%if 0%{?_systemd}
%define systemd --enable-systemd --with-systemdunitdir=%{_unitdir} --with-systemdpresetdir=%{_presetdir} --with-systemdmodulesloaddir=%{_modulesloaddir} --with-systemdgeneratordir=%{_systemdgeneratordir} --disable-sysvinit
- %define systemd_svcs zfs-import-cache.service zfs-import-scan.service zfs-mount.service zfs-share.service zfs-zed.service zfs.target zfs-import.target
+ %define systemd_svcs zfs-import-cache.service zfs-import-scan.service zfs-mount.service zfs-share.service zfs-zed.service zfs.target zfs-import.target zfs-volume-wait.service zfs-volumes.target
%else
%define systemd --enable-sysvinit --disable-systemd
%endif
@@ -419,6 +419,7 @@ systemctl --system daemon-reload >/dev/null || true
%{_sbindir}/*
%{_bindir}/raidz_test
%{_bindir}/zgenhostid
+%{_bindir}/zvol_wait
# Optional Python 2/3 scripts
%{_bindir}/arc_summary
%{_bindir}/arcstat