Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

systemd zvol target #9016

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cmd/zed/zed.d/history_event-zfs-list-cacher.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ PROPS="name,mountpoint,canmount,atime,relatime,devices,exec\
,org.openzfs.systemd:nofail,org.openzfs.systemd:ignore"

"${ZFS}" list -H -t filesystem -o "${PROPS}" -r "${ZEVENT_POOL}" > "${FSLIST_TMP}"
"${ZFS}" list -H -t volume -o "name,org.openzfs.systemd:ignore" -r "${ZEVENT_POOL}" |
while IFS=" " read -r name ignore ; do
[ "${ignore}" = "on" ] && continue

# fake "zvol" mountpoint
printf '%s\tzvol\n' "${name}" >> "${FSLIST_TMP}"
done

# Sort the output so that it is stable
sort "${FSLIST_TMP}" -o "${FSLIST_TMP}"
Expand Down
82 changes: 60 additions & 22 deletions cmd/zvol_wait/zvol_wait
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/bin/sh

read -r default_volmode < /sys/module/zfs/parameters/zvol_volmode

count_zvols() {
if [ -z "$zvols" ]; then
echo 0
Expand All @@ -25,34 +27,70 @@ filter_out_deleted_zvols() {
IFS="$OIFS"
}

should_process_zvol() {
# IFS=\t here!
name="${1}"
volmode="${2}"
token="${3}"
redacted="${4}"

# /dev links are not created for zvols with volmode = "none"
# or for redacted zvols.
[ "$volmode" = "none" ] && return 1
[ "$volmode" = "default" ] && [ "$default_volmode" = "3" ] &&
return 1
[ "$redacted" = "-" ] || return 1

# We also ignore partially received zvols if it is
# not an incremental receive, as those won't even have a block
# device minor node created yet.
if [ "$token" != "-" ]; then
# Incremental receives create an invisible clone that
# is not automatically displayed by zfs list.
if ! zfs list "$name/%recv" >/dev/null 2>&1; then
return 1
fi
fi
return 0
}

list_zvols() {
read -r default_volmode < /sys/module/zfs/parameters/zvol_volmode
zfs list -t volume -H -o \
name,volmode,receive_resume_token,redact_snaps |
while IFS=" " read -r name volmode token redacted; do # IFS=\t here!

# /dev links are not created for zvols with volmode = "none"
# or for redacted zvols.
[ "$volmode" = "none" ] && continue
[ "$volmode" = "default" ] && [ "$default_volmode" = "3" ] &&
continue
[ "$redacted" = "-" ] || continue

# We also ignore partially received zvols if it is
# not an incremental receive, as those won't even have a block
# device minor node created yet.
if [ "$token" != "-" ]; then

# Incremental receives create an invisible clone that
# is not automatically displayed by zfs list.
if ! zfs list "$name/%recv" >/dev/null 2>&1; then
continue
fi
fi
echo "$name"
while IFS=" " read -r _a _b _c _d ; do # IFS=\t here!
should_process_zvol "${_a}" "${_b}" "${_c}" "${_d}" && echo "$name"
done
}

if [ -n "$1" ] ; then
devnode="/dev/zvol/${1}"
OLDIFS="$IFS"
IFS=" "
# shellcheck disable=SC2046
if ! should_process_zvol $(zfs list -H -o name,volmode,receive_resume_token,redact_snaps "$1") ; then
exit 0
fi
IFS="$OLDIFS"

outerloop=0
while [ "$outerloop" -lt 20 ] ; do
innerloop=0
while [ "$innerloop" -lt 30 ] ; do
[ -e "$devnode" ] && [ ! -L "$devnode" ] && exit 0
innerloop="$(( innerloop + 1))"
sleep 1
done
if ! zfs list "$1" 2>/dev/null >/dev/null ; then
# The dataset was deleted
exit 0
fi
outerloop="$(( outerloop + 1 ))"
sleep 1
done

exit 1
fi

zvols=$(list_zvols)
zvols_count=$(count_zvols)
if [ "$zvols_count" -eq 0 ]; then
Expand Down
4 changes: 2 additions & 2 deletions etc/systemd/system-generators/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
include $(top_srcdir)/config/Rules.am

AM_CPPFLAGS += -DSYSTEMDUNITDIR=\"$(systemdunitdir)\"

systemdgenerator_PROGRAMS = \
zfs-mount-generator

Expand All @@ -9,6 +11,4 @@ zfs_mount_generator_SOURCES = \
zfs_mount_generator_LDADD = \
$(abs_top_builddir)/lib/libzfs/libzfs.la

zfs_mount_generator_LDFLAGS = -pthread

include $(top_srcdir)/config/CppCheck.am
84 changes: 80 additions & 4 deletions etc/systemd/system-generators/zfs-mount-generator.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017 Antonio Russo <antonio.e.russo@gmail.com>
* Copyright (c) 2017, 2022 Antonio Russo <aerusso@aerusso.net>
* Copyright (c) 2020 InsanePrawn <insane.prawny@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
Expand Down Expand Up @@ -56,6 +56,7 @@
#define PROGNAME "zfs-mount-generator"
#define FSLIST SYSCONFDIR "/zfs/zfs-list.cache"
#define ZFS SBINDIR "/zfs"
#define ZVOL_TARGET_DIR "zfs-volumes.target.requires"

#define OUTPUT_HEADER \
"# Automatically generated by " PROGNAME "\n" \
Expand Down Expand Up @@ -194,7 +195,58 @@ fopenat(int dirfd, const char *pathname, int flags,
}

static int
line_worker(char *line, const char *cachefile)
line_worker_zvol(char *line, int *zvol_depdir_fd)
{
char *toktmp;
const char *dataset = strtok_r(line, "\t", &toktmp);

if (*zvol_depdir_fd < 0) {
(void) mkdirat(destdir_fd, ZVOL_TARGET_DIR, 0755);
*zvol_depdir_fd = openat(destdir_fd, ZVOL_TARGET_DIR,
O_PATH | O_DIRECTORY | O_CLOEXEC);
if (*zvol_depdir_fd < 0) {
fprintf(stderr, PROGNAME "[%d]: "
"can't open %s/" ZVOL_TARGET_DIR ": %s\n",
getpid(), destdir, strerror(errno));
return (1);
}
}

char *zvol_service = systemd_escape(dataset, "zfs-volume@", ".service");
if (zvol_service == NULL)
return (1);

int retval = 0;

if (symlinkat(SYSTEMDUNITDIR "/zfs-volume@.service",
*zvol_depdir_fd, zvol_service) == -1) {
struct stat stbuf;

if ((fstatat(*zvol_depdir_fd, zvol_service, &stbuf,
AT_SYMLINK_NOFOLLOW) == 0) &&
((stbuf.st_mode & S_IFMT) == S_IFLNK)) {
fprintf(stderr, PROGNAME "[%d]: %s: "
"symlink at %s under %s/"
ZVOL_TARGET_DIR " already exists: Skipping.\n",
getpid(), dataset, zvol_service, destdir);
} else {
fprintf(stderr, PROGNAME "[%d]: %s: "
"couldn't symlink at %s under "
"%s/" ZVOL_TARGET_DIR ": %s\n",
getpid(), dataset, zvol_service,
destdir, strerror(errno));
retval = 1;
}
}

free(zvol_service);

return (retval);
}


static int
line_worker_fs(char *line, const char *cachefile)
{
int ret = 0;
void *tofree_all[8];
Expand Down Expand Up @@ -771,6 +823,7 @@ int
main(int argc, char **argv)
{
struct timespec time_init = {};
int zvol_depdir_fd = -1;
clock_gettime(CLOCK_MONOTONIC_RAW, &time_init);

{
Expand Down Expand Up @@ -895,13 +948,33 @@ main(int argc, char **argv)

char *canmount = line;
canmount += strcspn(canmount, "\t");

/* This SHOULD contain the dataset name */
if (canmount == line) {
/* Throw an error if we didn't find anything */
fprintf(stderr,
PROGNAME "[%d]: %s: not enough tokens!\n",
getpid(), cachent->d_name);
ret = 1;
continue;
}

canmount += strspn(canmount, "\t");

/* This is the second attribute in the zfs-list file */
if ((strncmp(canmount, "zvol", 4) == 0) &&
((canmount[4] == '\0') || (canmount[4] == '\t'))) {
/* special case of zvol */
ret |= line_worker_zvol(line, &zvol_depdir_fd);
continue;
}

canmount += strcspn(canmount, "\t");
canmount += strspn(canmount, "\t");
bool canmount_on = strncmp(canmount, "on", 2) == 0;

if (canmount_on)
ret |= line_worker(line, cachent->d_name);
ret |= line_worker_fs(line, cachent->d_name);
else {
if (filename == NULL)
filename =
Expand All @@ -928,11 +1001,14 @@ main(int argc, char **argv)
}
free(line);

if (zvol_depdir_fd >= 0)
(void) close(zvol_depdir_fd);

while (lines_canmount_not_on) {
struct line *l = lines_canmount_not_on;
lines_canmount_not_on = l->next;

ret |= line_worker(l->line, l->fname);
ret |= line_worker_fs(l->line, l->fname);
if (FREE_STATICS) {
free(l->line);
free(l);
Expand Down
1 change: 1 addition & 0 deletions etc/systemd/system/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ systemdunit_DATA = \
zfs-mount.service \
zfs-share.service \
zfs-volume-wait.service \
zfs-volume@.service \
zfs-import.target \
zfs-volumes.target \
zfs.target \
Expand Down
10 changes: 10 additions & 0 deletions etc/systemd/system/zfs-volume@.service.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Unit]
Description=Wait for ZFS volume %I
Documentation=man:zfs-mount-generator(8)
After=zfs-import.target
ConditionPathIsDirectory=/sys/module/zfs

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=@bindir@/zvol_wait %I