Skip to content

Commit

Permalink
zfs-mount-generator: generate zvol dependencies
Browse files Browse the repository at this point in the history
Signed-off-by: Antonio Russo <aerusso@aerusso.net>
  • Loading branch information
aerusso committed Feb 19, 2022
1 parent ca85fe5 commit 80452d5
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 4 deletions.
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}" |
IFS=" " while 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
2 changes: 2 additions & 0 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 Down
83 changes: 79 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,57 @@ fopenat(int dirfd, const char *pathname, int flags,
}

static int
line_worker(char *line, const char *cachefile)
line_worker_volume(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_filesystem(char *line, const char *cachefile)
{
int ret = 0;
void *tofree_all[8];
Expand Down Expand Up @@ -771,6 +822,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 +947,32 @@ 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_volume(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_filesystem(line, cachent->d_name);
else {
if (filename == NULL)
filename =
Expand All @@ -928,11 +999,15 @@ 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_filesystem(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

0 comments on commit 80452d5

Please sign in to comment.