Skip to content
Permalink
Browse files

Systemd mount generator: Generate noauto units

This commit makes the following changes:
- the systemd mount generator now generates units for datasets marked
canmount=noauto too. Unlike canmount=on, these units are NOT WantedBy
local-fs.target.
If there are multiple noauto datasets for a path, no noauto unit will be
created.
Datasets with canmount=on are prioritized.

- introduces handling of the user property org.open-zfs.systemd:noauto,
which is now included in the zfs-list.cache files and will cause a
canmount=on dataset to be treated like noauto by the generator.

Signed-off-by: InsanePrawn <insane.prawny@gmail.com>
  • Loading branch information
InsanePrawn committed Jan 3, 2020
1 parent fd55bdb commit 07fccd3bb535e5afefb0f2c1739f2a0291876f10
@@ -47,7 +47,8 @@ case "${ZEVENT_HISTORY_INTERNAL_NAME}" in
# Only act if one of the tracked properties is altered.
case "${ZEVENT_HISTORY_INTERNAL_STR%%=*}" in
canmount|mountpoint|atime|relatime|devices|exec| \
readonly|setuid|nbmand|encroot|keylocation) ;;
readonly|setuid|nbmand|encroot|keylocation| \
org.open-zfs.systemd:noauto) ;;
*) exit 0 ;;
esac
;;
@@ -62,7 +63,7 @@ zed_lock zfs-list
trap abort_alter EXIT

PROPS="name,mountpoint,canmount,atime,relatime,devices,exec,readonly"
PROPS="${PROPS},setuid,nbmand,encroot,keylocation"
PROPS="${PROPS},setuid,nbmand,encroot,keylocation,org.open-zfs.systemd:noauto"

"${ZFS}" list -H -t filesystem -o $PROPS -r "${ZEVENT_POOL}" > "${FSLIST_TMP}"

@@ -33,6 +33,20 @@ do_fail() {
exit 1
}

# test if $1 is in space-separated list $2
is_known() {
query="$1"
IFS=' '
# protect against special characters
set -f
for element in $2 ; do
if [ "$query" = "$element" ] ; then
return 0
fi
done
return 1
}

# see systemd.generator
if [ $# -eq 0 ] ; then
dest_norm="/tmp"
@@ -42,11 +56,11 @@ else
do_fail "zero or three arguments required"
fi

# For ZFSs marked "auto", a dependency is created for local-fs.target. To
# For datasets 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}"
wants_dir="${dest_norm}/local-fs.target.wants/"
mkdir -p "${wants_dir}"

# All needed information about each ZFS is available from
# zfs list -H -t filesystem -o <properties>
@@ -74,6 +88,7 @@ process_line() {
p_nbmand="${10}"
p_encroot="${11}"
p_keyloc="${12}"
p_systemd_noauto="${13}"

# Minimal pre-requisites to mount a ZFS dataset
wants="zfs-import.target"
@@ -140,10 +155,7 @@ ExecStop=@sbindir@/zfs unload-key '${dataset}'" > "${dest_norm}/${keyloadunit}
# Check for canmount=off .
if [ "${p_canmount}" = "off" ] ; then
return
elif [ "${p_canmount}" = "noauto" ] ; then
# Don't let a noauto marked mountpoint block an "auto" marked mountpoint
return
elif [ "${p_canmount}" = "on" ] ; then
elif [ "${p_canmount}" = "noauto" ] || [ "${p_canmount}" = "on" ] ; then
: # This is OK
else
do_fail "invalid canmount"
@@ -233,25 +245,65 @@ ExecStop=@sbindir@/zfs unload-key '${dataset}'" > "${dest_norm}/${keyloadunit}
"${dataset}" >/dev/kmsg
fi

# If the mountpoint has already been created, give it precedence.
# Handle existing files:
# 1. We never overwrite existing files, although we may delete
# files if we're sure they were created by us. (see 5.)
# 2. Units with canmount=on always have precedence over noauto.
# This is enforced by the sort pipe in the loop around this function.
# 3. If no unit file exists for a noauto dataset, we create one.
# Additionally, we use a $noauto_files to track the unit file names
# (which are the systemd-escaped mountpoints) of all (exclusively)
# noauto datasets that had a file created.
# 4. If the file to be created is not in the tracking variaable,
# we do NOT create it.
# 5. If a file exists for a noauto dataset, we check whether the file
# name is in the variable. If it is, we have multiple noauto datasets
# for the same mountpoint. In such cases, we remove the file for safety.
# To avoid further noauto datasets creating a file for this path again,
# we leave the file name in the tracking variable.
if [ -e "${dest_norm}/${mountfile}" ] ; then
printf 'zfs-mount-generator: %s already exists\n' "${mountfile}" \
>/dev/kmsg
if is_known "$mountfile" "$noauto_files" ; then
# if it's in $noauto_files, we must be noauto too. See 2.
printf 'zfs-mount-generator: removing duplicate noauto %s\n' \
"${mountfile}" >/dev/kmsg
# See 5.
rm "${dest_norm}/${mountfile}"
else
# don't log for noauto
if [ "${p_canmount}" = "on" ] && [ "${p_systemd_noauto}" != "on" ] ; then
printf 'zfs-mount-generator: %s already exists. Skipping.\n' \
"${mountfile}" >/dev/kmsg
fi
fi
# file exists; Skip current dataset.
return
else
if is_known "${mountfile}" "${noauto_files}" ; then
# See 4.
return
elif [ "${p_canmount}" = "noauto" ] || \
[ "${p_systemd_noauto}" = "on" ] ; then
noauto_files="${mountfile} ${noauto_files}"
fi
fi

# Create the .mount unit file.
# By ordering before zfs-mount.service, we avoid race conditions.
#
# (Do not use `<<EOF`-style here-documents for this, see warning above)
#
before="zfs-mount.service"
if [ "${p_canmount}" = "on" ] && [ "${p_systemd_noauto}" != "on" ] ; then
before="${before} local-fs.target"
fi
echo \
"# Automatically generated by zfs-mount-generator
[Unit]
SourcePath=${cachefile}
Documentation=man:zfs-mount-generator(8)
Before=local-fs.target zfs-mount.service
Before=${before}
After=${wants}
Wants=${wants}
@@ -262,12 +314,19 @@ Type=zfs
Options=defaults${opts},zfsutil" > "${dest_norm}/${mountfile}"

# Finally, create the appropriate dependency
ln -s "../${mountfile}" "${req_dir}"
if [ "${p_canmount}" = "on" ] && [ "${p_systemd_noauto}" != "on" ] ; then
ln -s "../${mountfile}" "${wants_dir}"
fi
}

# Feed each line into process_line
for cachefile in "${FSLIST}/"* ; do
while read -r fs ; do
process_line "${fs}"
done < "${cachefile}"
# Sort cachefile's lines by canmount, "on" before "noauto"
# and feed each line into process_line
sort -t "$(printf '\t')" -k 3 -r "${cachefile}" | \
( # subshell is necessary for `sort|while read` and $noauto_files
noauto_files=""
while read -r fs ; do
process_line "${fs}"
done
)
done

0 comments on commit 07fccd3

Please sign in to comment.
You can’t perform that action at this time.