summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/zed/Makefile.am11
-rw-r--r--cmd/zed/zed.d/.gitignore1
-rwxr-xr-xcmd/zed/zed.d/history_event-zfs-list-cacher.sh.in73
-rw-r--r--config/user-systemd.m48
-rw-r--r--configure.ac1
-rw-r--r--etc/systemd/Makefile.am2
-rw-r--r--etc/systemd/system-generators/.gitignore1
-rw-r--r--etc/systemd/system-generators/Makefile.am15
-rwxr-xr-xetc/systemd/system-generators/zfs-mount-generator.in115
-rw-r--r--man/man8/Makefile.am1
-rw-r--r--man/man8/zfs-mount-generator.856
-rw-r--r--rpm/generic/zfs.spec.in1
12 files changed, 282 insertions, 3 deletions
diff --git a/cmd/zed/Makefile.am b/cmd/zed/Makefile.am
index 37739696e..e9e38d8e5 100644
--- a/cmd/zed/Makefile.am
+++ b/cmd/zed/Makefile.am
@@ -4,7 +4,8 @@ DEFAULT_INCLUDES += \
-I$(top_srcdir)/include \
-I$(top_srcdir)/lib/libspl/include
-EXTRA_DIST = zed.d/README
+EXTRA_DIST = zed.d/README \
+ zed.d/history_event-zfs-list-cacher.sh.in
sbin_PROGRAMS = zed
@@ -60,6 +61,7 @@ dist_zedexec_SCRIPTS = \
zed.d/all-syslog.sh \
zed.d/data-notify.sh \
zed.d/generic-notify.sh \
+ zed.d/history_event-zfs-list-cacher.sh \
zed.d/resilver_finish-notify.sh \
zed.d/scrub_finish-notify.sh \
zed.d/statechange-led.sh \
@@ -69,6 +71,13 @@ dist_zedexec_SCRIPTS = \
zed.d/pool_import-led.sh \
zed.d/resilver_finish-start-scrub.sh
+zed.d/history_event-zfs-list-cacher.sh: %: %.in
+ -$(SED) -e 's,@bindir\@,$(bindir),g' \
+ -e 's,@runstatedir\@,$(runstatedir),g' \
+ -e 's,@sbindir\@,$(sbindir),g' \
+ -e 's,@sysconfdir\@,$(sysconfdir),g' \
+ $< >'$@'
+
zedconfdefaults = \
all-syslog.sh \
data-notify.sh \
diff --git a/cmd/zed/zed.d/.gitignore b/cmd/zed/zed.d/.gitignore
new file mode 100644
index 000000000..46a00945a
--- /dev/null
+++ b/cmd/zed/zed.d/.gitignore
@@ -0,0 +1 @@
+history_event-zfs-list-cacher.sh
diff --git a/cmd/zed/zed.d/history_event-zfs-list-cacher.sh.in b/cmd/zed/zed.d/history_event-zfs-list-cacher.sh.in
new file mode 100755
index 000000000..348c8d67a
--- /dev/null
+++ b/cmd/zed/zed.d/history_event-zfs-list-cacher.sh.in
@@ -0,0 +1,73 @@
+#!/bin/sh
+#
+# Track changes to enumerated pools for use in early-boot
+set -ef
+
+FSLIST_DIR="@sysconfdir@/zfs/zfs-list.cache"
+FSLIST_TMP="@runstatedir@/zfs-list.cache.new"
+FSLIST="${FSLIST_DIR}/${ZEVENT_POOL}"
+
+# If the pool specific cache file is not writeable, abort
+[ -w "${FSLIST}" ] || exit 0
+
+[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
+. "${ZED_ZEDLET_DIR}/zed-functions.sh"
+
+zed_exit_if_ignoring_this_event
+zed_check_cmd "${ZFS}" sort diff grep
+
+# If we are acting on a snapshot, we have nothing to do
+printf '%s' "${ZEVENT_HISTORY_DSNAME}" | grep '@' && exit 0
+
+# We obtain a lock on zfs-list to avoid any simultaneous writes.
+# If we run into trouble, log and drop the lock
+abort_alter() {
+ zed_log_msg "Error updating zfs-list.cache!"
+ zed_unlock zfs-list
+}
+
+finished() {
+ zed_unlock zfs-list
+ trap - EXIT
+ exit 0
+}
+
+case "${ZEVENT_HISTORY_INTERNAL_NAME}" in
+ create|"finish receiving"|import|destroy|rename)
+ ;;
+
+ export)
+ zed_lock zfs-list
+ trap abort_alter EXIT
+ echo > "${FSLIST}"
+ finished
+ ;;
+
+ set|inherit)
+ # Only act if the mountpoint or canmount setting is altered.
+ case "${ZEVENT_HISTORY_INTERNAL_STR}" in
+ canmount=*|mountpoint=*) ;;
+ *) exit 0 ;;
+ esac
+ ;;
+
+ *)
+ # Ignore all other events.
+ exit 0
+ ;;
+esac
+
+zed_lock zfs-list
+trap abort_alter EXIT
+
+"${ZFS}" list -H -tfilesystem -oname,mountpoint,canmount -r "${ZEVENT_POOL}" \
+ >"${FSLIST_TMP}"
+
+# Sort the output so that it is stable
+sort "${FSLIST_TMP}" -o "${FSLIST_TMP}"
+
+# Don't modify the file if it hasn't changed
+diff -q "${FSLIST_TMP}" "${FSLIST}" || mv "${FSLIST_TMP}" "${FSLIST}"
+rm -f "${FSLIST_TMP}"
+
+finished
diff --git a/config/user-systemd.m4 b/config/user-systemd.m4
index de2a44f10..5d1f5618a 100644
--- a/config/user-systemd.m4
+++ b/config/user-systemd.m4
@@ -20,6 +20,11 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_SYSTEMD], [
[install systemd module load files into dir [[/usr/lib/modules-load.d]]]),
systemdmoduleloaddir=$withval,systemdmodulesloaddir=/usr/lib/modules-load.d)
+ AC_ARG_WITH(systemdgeneratordir,
+ AC_HELP_STRING([--with-systemdgeneratordir=DIR],
+ [install systemd generators in dir [[/usr/lib/systemd/system-generators]]]),
+ systemdgeneratordir=$withval,systemdgeneratordir=/usr/lib/systemd/system-generators)
+
AS_IF([test "x$enable_systemd" = xcheck], [
AS_IF([systemctl --version >/dev/null 2>&1],
[enable_systemd=yes],
@@ -32,7 +37,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_SYSTEMD], [
AS_IF([test "x$enable_systemd" = xyes], [
ZFS_INIT_SYSTEMD=systemd
ZFS_MODULE_LOAD=modules-load.d
- DEFINE_SYSTEMD='--with systemd --define "_unitdir $(systemdunitdir)" --define "_presetdir $(systemdpresetdir)"'
+ DEFINE_SYSTEMD='--with systemd --define "_unitdir $(systemdunitdir)" --define "_presetdir $(systemdpresetdir)" --define "_generatordir $(systemdgeneratordir)"'
modulesloaddir=$systemdmodulesloaddir
],[
DEFINE_SYSTEMD='--without systemd'
@@ -43,5 +48,6 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_SYSTEMD], [
AC_SUBST(DEFINE_SYSTEMD)
AC_SUBST(systemdunitdir)
AC_SUBST(systemdpresetdir)
+ AC_SUBST(systemdgeneratordir)
AC_SUBST(modulesloaddir)
])
diff --git a/configure.ac b/configure.ac
index 5a84ffcbf..0893af42e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,6 +67,7 @@ AC_CONFIG_FILES([
etc/zfs/Makefile
etc/systemd/Makefile
etc/systemd/system/Makefile
+ etc/systemd/system-generators/Makefile
etc/sudoers.d/Makefile
etc/modules-load.d/Makefile
man/Makefile
diff --git a/etc/systemd/Makefile.am b/etc/systemd/Makefile.am
index d4008c0dd..7b47b93fc 100644
--- a/etc/systemd/Makefile.am
+++ b/etc/systemd/Makefile.am
@@ -1 +1 @@
-SUBDIRS = system
+SUBDIRS = system system-generators
diff --git a/etc/systemd/system-generators/.gitignore b/etc/systemd/system-generators/.gitignore
new file mode 100644
index 000000000..fc2ebc1a2
--- /dev/null
+++ b/etc/systemd/system-generators/.gitignore
@@ -0,0 +1 @@
+zfs-mount-generator
diff --git a/etc/systemd/system-generators/Makefile.am b/etc/systemd/system-generators/Makefile.am
new file mode 100644
index 000000000..c730982a5
--- /dev/null
+++ b/etc/systemd/system-generators/Makefile.am
@@ -0,0 +1,15 @@
+systemdgenerator_SCRIPTS = \
+ zfs-mount-generator
+
+EXTRA_DIST = \
+ $(top_srcdir)/etc/systemd/system-generators/zfs-mount-generator.in
+
+$(systemdgenerator_SCRIPTS): %: %.in
+ -$(SED) -e 's,@bindir\@,$(bindir),g' \
+ -e 's,@runstatedir\@,$(runstatedir),g' \
+ -e 's,@sbindir\@,$(sbindir),g' \
+ -e 's,@sysconfdir\@,$(sysconfdir),g' \
+ $< >'$@'
+
+distclean-local::
+ -$(RM) $(systemdgenerator_SCRIPTS)
diff --git a/etc/systemd/system-generators/zfs-mount-generator.in b/etc/systemd/system-generators/zfs-mount-generator.in
new file mode 100755
index 000000000..e39a03036
--- /dev/null
+++ b/etc/systemd/system-generators/zfs-mount-generator.in
@@ -0,0 +1,115 @@
+#!/bin/sh
+
+# zfs-mount-generator - generates systemd mount units for zfs
+# Copyright (c) 2017 Antonio Russo <[email protected]>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+set -ef
+
+FSLIST="@sysconfdir@/zfs/zfs-list.cache"
+
+[ -d "${FSLIST}" ] || exit 0
+
+do_fail() {
+ printf 'zfs-mount-generator.sh: %s\n' "$*" > /dev/kmsg
+ exit 1
+}
+
+# see systemd.generator
+if [ $# -eq 0 ] ; then
+ dest_norm="/tmp"
+elif [ $# -eq 3 ] ; then
+ dest_norm="${1}"
+else
+ do_fail "zero or three arguments required"
+fi
+
+# For ZFSs marked "auto", a dependency is created for local-fs.target. To
+# avoid regressions, this dependency is reduced to "wants" rather than
+# "requires". **THIS MAY CHANGE**
+req_dir="${dest_norm}/local-fs.target.wants/"
+mkdir -p "${req_dir}"
+
+# All needed information about each ZFS is available from
+# zfs list -H -t filesystem -oname,mountpoint,canmount
+# cached in $FSLIST, and each line is processed by the following function:
+
+process_line() {
+
+ # Check for canmount=off .
+ if [ "${3}" = "off" ] ; then
+ return
+ elif [ "${3}" = "noauto" ] ; then
+ # Don't let a noauto marked mountpoint block an "auto" market mountpoint
+ return
+ elif [ "${3}" = "on" ] ; then
+ : # This is OK
+ else
+ do_fail "invalid canmount"
+ fi
+
+ # Check for legacy and blank mountpoints.
+ if [ "${2}" = "legacy" ] ; then
+ return
+ elif [ "${2}" = "none" ] ; then
+ return
+ elif [ "${2%"${2#?}"}" != "/" ] ; then
+ do_fail "invalid mountpoint $*"
+ fi
+
+ # Escape the mountpoint per systemd policy.
+ mountfile="$(systemd-escape "${2#?}").mount"
+
+ # If the mountpoint has already been created, give it precedence.
+ if [ -e "${dest_norm}/${mountfile}" ] ; then
+ printf 'zfs-mount-generator.sh: %s.mount already exists\n' "${2}" \
+ >/dev/kmsg
+ return
+ fi
+
+ # By ordering before zfs-mount.service, we avoid race conditions.
+ cat > "${dest_norm}/${mountfile}" << EOF
+# Automatically generated by zfs-mount-generator
+
+[Unit]
+SourcePath=${FSLIST}/${cachefile}
+Documentation=man:zfs-mount-generator(8)
+Before=local-fs.target zfs-mount.service
+After=zfs-import.target
+Wants=zfs-import.target
+
+[Mount]
+Where=${2}
+What=${1}
+Type=zfs
+Options=zfsutil,auto
+EOF
+
+ # Finally, create the appropriate dependencies based on the ZFS properties.
+ [ "$3" = "on" ] & ln -s "../${mountfile}" "${req_dir}"
+}
+
+# Feed each line into process_line
+for cachefile in $(ls "${FSLIST}") ; do
+ while read -r fs ; do
+ process_line $fs
+ done < "${FSLIST}/${cachefile}"
+done
diff --git a/man/man8/Makefile.am b/man/man8/Makefile.am
index 5c60bdfa7..b6408ddf2 100644
--- a/man/man8/Makefile.am
+++ b/man/man8/Makefile.am
@@ -4,6 +4,7 @@ dist_man_MANS = \
vdev_id.8 \
zdb.8 \
zfs.8 \
+ zfs-mount-generator.8 \
zfs-program.8 \
zgenhostid.8 \
zinject.8 \
diff --git a/man/man8/zfs-mount-generator.8 b/man/man8/zfs-mount-generator.8
new file mode 100644
index 000000000..af471e7c9
--- /dev/null
+++ b/man/man8/zfs-mount-generator.8
@@ -0,0 +1,56 @@
+.TH "ZFS\-MOUNT\-GENERATOR" "8" "ZFS" "zfs-mount-generator" "\""
+.SH "NAME"
+zfs\-mount\-generator \- generates systemd mount units for zfs
+.SH SYNOPSIS
+.B /lib/systemd/system-generators/zfs\-mount\-generator
+.sp
+.SH DESCRIPTION
+The zfs\-mount\-generator implements the \fBGenerators Specification\fP
+of
+.BR systemd (1),
+and is called during early boot to generate
+.BR systemd.mount (5)
+units for automatically mounted datasets. Mount ordering and dependencies
+are created for all tracked pools (see below). If a dataset has
+.BR canmount=on
+and
+.BR mountpoint
+set, the
+.BR auto
+mount option will be set, and a dependency for
+.BR local-fs.target
+on the mount will be created.
+
+Because zfs pools may not be available very early in the boot process,
+information on ZFS mountpoints must be stored separately. The output
+of the command
+.PP
+.RS 4
+zfs list -H -oname,mountpoint,canmount
+.RE
+.PP
+for datasets that should be mounted by systemd, should be kept
+separate from the pool, at
+.PP
+.RS 4
+.RI @sysconfdir@/zfs/zfs-list.cache/ POOLNAME
+.
+.RE
+.PP
+The cache file, if writeable, will be kept synchronized with the pool
+state by the ZEDLET
+.PP
+.RS 4
+history_event-zfs-list-cacher.sh .
+.RE
+.PP
+.sp
+.SH SEE ALSO
+.BR zfs (5)
+.BR zfs-events (5)
+.BR zed (8)
+.BR zpool (5)
+.BR systemd (1)
+.BR systemd.target (5)
+.BR systemd.special (7)
+.BR systemd.mount (7)
diff --git a/rpm/generic/zfs.spec.in b/rpm/generic/zfs.spec.in
index beb7671a1..b06cf3002 100644
--- a/rpm/generic/zfs.spec.in
+++ b/rpm/generic/zfs.spec.in
@@ -338,6 +338,7 @@ systemctl --system daemon-reload >/dev/null || true
/usr/lib/modules-load.d/*
%{_unitdir}/*
%{_presetdir}/*
+%{_generatordir}/*
%else
%config(noreplace) %{_sysconfdir}/init.d/*
%config(noreplace) %{_initconfdir}/zfs