2014-01-21 21:30:03 +00:00
|
|
|
/*
|
2015-05-06 22:56:03 +00:00
|
|
|
* This file is part of the ZFS Event Daemon (ZED)
|
|
|
|
* for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
|
2014-01-21 21:30:03 +00:00
|
|
|
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
|
|
|
|
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
|
2015-05-06 22:56:03 +00:00
|
|
|
* Refer to the ZoL git commit log for authoritative copyright attribution.
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the terms of the
|
|
|
|
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
|
|
|
|
* You can obtain a copy of the license from the top-level file
|
|
|
|
* "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
|
|
|
|
* You may not use this file except in compliance with the license.
|
2014-01-21 21:30:03 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include "zed.h"
|
|
|
|
#include "zed_conf.h"
|
|
|
|
#include "zed_event.h"
|
|
|
|
#include "zed_file.h"
|
|
|
|
#include "zed_log.h"
|
|
|
|
|
|
|
|
static volatile sig_atomic_t _got_exit = 0;
|
|
|
|
static volatile sig_atomic_t _got_hup = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Signal handler for SIGINT & SIGTERM.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_exit_handler(int signum)
|
|
|
|
{
|
|
|
|
_got_exit = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Signal handler for SIGHUP.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_hup_handler(int signum)
|
|
|
|
{
|
|
|
|
_got_hup = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Register signal handlers.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_setup_sig_handlers(void)
|
|
|
|
{
|
|
|
|
struct sigaction sa;
|
|
|
|
|
|
|
|
if (sigemptyset(&sa.sa_mask) < 0)
|
|
|
|
zed_log_die("Failed to initialize sigset");
|
|
|
|
|
|
|
|
sa.sa_flags = SA_RESTART;
|
|
|
|
sa.sa_handler = SIG_IGN;
|
|
|
|
|
|
|
|
if (sigaction(SIGPIPE, &sa, NULL) < 0)
|
|
|
|
zed_log_die("Failed to ignore SIGPIPE");
|
|
|
|
|
|
|
|
sa.sa_handler = _exit_handler;
|
|
|
|
if (sigaction(SIGINT, &sa, NULL) < 0)
|
|
|
|
zed_log_die("Failed to register SIGINT handler");
|
|
|
|
|
|
|
|
if (sigaction(SIGTERM, &sa, NULL) < 0)
|
|
|
|
zed_log_die("Failed to register SIGTERM handler");
|
|
|
|
|
|
|
|
sa.sa_handler = _hup_handler;
|
|
|
|
if (sigaction(SIGHUP, &sa, NULL) < 0)
|
|
|
|
zed_log_die("Failed to register SIGHUP handler");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lock all current and future pages in the virtual memory address space.
|
2014-09-10 21:22:39 +00:00
|
|
|
* Access to locked pages will never be delayed by a page fault.
|
|
|
|
*
|
2014-01-21 21:30:03 +00:00
|
|
|
* EAGAIN is tested up to max_tries in case this is a transient error.
|
2014-09-10 21:22:39 +00:00
|
|
|
*
|
2014-08-27 20:18:01 +00:00
|
|
|
* Note that memory locks are not inherited by a child created via fork()
|
2014-09-10 21:22:39 +00:00
|
|
|
* and are automatically removed during an execve(). As such, this must
|
|
|
|
* be called after the daemon fork()s (when running in the background).
|
2014-01-21 21:30:03 +00:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_lock_memory(void)
|
|
|
|
{
|
2014-04-01 21:21:56 +00:00
|
|
|
#if HAVE_MLOCKALL
|
2014-01-21 21:30:03 +00:00
|
|
|
int i = 0;
|
|
|
|
const int max_tries = 10;
|
|
|
|
|
|
|
|
for (i = 0; i < max_tries; i++) {
|
|
|
|
if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) {
|
|
|
|
zed_log_msg(LOG_INFO, "Locked all pages in memory");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (errno != EAGAIN)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
zed_log_die("Failed to lock memory pages: %s", strerror(errno));
|
|
|
|
|
2014-04-01 21:21:56 +00:00
|
|
|
#else /* HAVE_MLOCKALL */
|
|
|
|
zed_log_die("Failed to lock memory pages: mlockall() not supported");
|
|
|
|
#endif /* HAVE_MLOCKALL */
|
2014-01-21 21:30:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-08-27 20:18:01 +00:00
|
|
|
* Start daemonization of the process including the double fork().
|
2014-09-10 21:22:39 +00:00
|
|
|
*
|
2014-08-27 20:18:01 +00:00
|
|
|
* The parent process will block here until _finish_daemonize() is called
|
2014-09-10 21:22:39 +00:00
|
|
|
* (in the grandchild process), at which point the parent process will exit.
|
|
|
|
* This prevents the parent process from exiting until initialization is
|
|
|
|
* complete.
|
2014-01-21 21:30:03 +00:00
|
|
|
*/
|
|
|
|
static void
|
2014-08-27 20:18:01 +00:00
|
|
|
_start_daemonize(void)
|
2014-01-21 21:30:03 +00:00
|
|
|
{
|
|
|
|
pid_t pid;
|
2014-08-27 20:18:01 +00:00
|
|
|
struct sigaction sa;
|
|
|
|
|
|
|
|
/* Create pipe for communicating with child during daemonization. */
|
|
|
|
zed_log_pipe_open();
|
2014-01-21 21:30:03 +00:00
|
|
|
|
2014-08-27 20:18:01 +00:00
|
|
|
/* Background process and ensure child is not process group leader. */
|
2014-01-21 21:30:03 +00:00
|
|
|
pid = fork();
|
|
|
|
if (pid < 0) {
|
|
|
|
zed_log_die("Failed to create child process: %s",
|
|
|
|
strerror(errno));
|
|
|
|
} else if (pid > 0) {
|
2014-08-27 20:18:01 +00:00
|
|
|
|
|
|
|
/* Close writes since parent will only read from pipe. */
|
|
|
|
zed_log_pipe_close_writes();
|
|
|
|
|
|
|
|
/* Wait for notification that daemonization is complete. */
|
|
|
|
zed_log_pipe_wait();
|
|
|
|
|
|
|
|
zed_log_pipe_close_reads();
|
2014-01-21 21:30:03 +00:00
|
|
|
_exit(EXIT_SUCCESS);
|
|
|
|
}
|
2014-08-27 20:18:01 +00:00
|
|
|
|
|
|
|
/* Close reads since child will only write to pipe. */
|
|
|
|
zed_log_pipe_close_reads();
|
|
|
|
|
|
|
|
/* Create independent session and detach from terminal. */
|
2014-01-21 21:30:03 +00:00
|
|
|
if (setsid() < 0)
|
|
|
|
zed_log_die("Failed to create new session: %s",
|
|
|
|
strerror(errno));
|
|
|
|
|
2014-08-27 20:18:01 +00:00
|
|
|
/* Prevent child from terminating on HUP when session leader exits. */
|
|
|
|
if (sigemptyset(&sa.sa_mask) < 0)
|
|
|
|
zed_log_die("Failed to initialize sigset");
|
|
|
|
|
|
|
|
sa.sa_flags = 0;
|
|
|
|
sa.sa_handler = SIG_IGN;
|
|
|
|
|
|
|
|
if (sigaction(SIGHUP, &sa, NULL) < 0)
|
|
|
|
zed_log_die("Failed to ignore SIGHUP");
|
|
|
|
|
|
|
|
/* Ensure process cannot re-acquire terminal. */
|
2014-01-21 21:30:03 +00:00
|
|
|
pid = fork();
|
|
|
|
if (pid < 0) {
|
|
|
|
zed_log_die("Failed to create grandchild process: %s",
|
|
|
|
strerror(errno));
|
|
|
|
} else if (pid > 0) {
|
|
|
|
_exit(EXIT_SUCCESS);
|
|
|
|
}
|
2014-08-27 20:18:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Finish daemonization of the process by closing stdin/stdout/stderr.
|
2014-09-10 21:22:39 +00:00
|
|
|
*
|
2014-08-27 20:18:01 +00:00
|
|
|
* This must be called at the end of initialization after all external
|
2014-09-10 21:22:39 +00:00
|
|
|
* communication channels are established and accessible.
|
2014-08-27 20:18:01 +00:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_finish_daemonize(void)
|
|
|
|
{
|
|
|
|
int devnull;
|
2014-01-21 21:30:03 +00:00
|
|
|
|
2014-08-27 20:18:01 +00:00
|
|
|
/* Preserve fd 0/1/2, but discard data to/from stdin/stdout/stderr. */
|
|
|
|
devnull = open("/dev/null", O_RDWR);
|
|
|
|
if (devnull < 0)
|
2014-01-21 21:30:03 +00:00
|
|
|
zed_log_die("Failed to open /dev/null: %s", strerror(errno));
|
|
|
|
|
2014-08-27 20:18:01 +00:00
|
|
|
if (dup2(devnull, STDIN_FILENO) < 0)
|
2014-01-21 21:30:03 +00:00
|
|
|
zed_log_die("Failed to dup /dev/null onto stdin: %s",
|
|
|
|
strerror(errno));
|
|
|
|
|
2014-08-27 20:18:01 +00:00
|
|
|
if (dup2(devnull, STDOUT_FILENO) < 0)
|
2014-01-21 21:30:03 +00:00
|
|
|
zed_log_die("Failed to dup /dev/null onto stdout: %s",
|
|
|
|
strerror(errno));
|
|
|
|
|
2014-08-27 20:18:01 +00:00
|
|
|
if (dup2(devnull, STDERR_FILENO) < 0)
|
2014-01-21 21:30:03 +00:00
|
|
|
zed_log_die("Failed to dup /dev/null onto stderr: %s",
|
|
|
|
strerror(errno));
|
|
|
|
|
2016-03-01 20:23:55 +00:00
|
|
|
if ((devnull > STDERR_FILENO) && (close(devnull) < 0))
|
2014-01-21 21:30:03 +00:00
|
|
|
zed_log_die("Failed to close /dev/null: %s", strerror(errno));
|
2014-08-27 20:18:01 +00:00
|
|
|
|
|
|
|
/* Notify parent that daemonization is complete. */
|
|
|
|
zed_log_pipe_close_writes();
|
2014-01-21 21:30:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ZFS Event Daemon (ZED).
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
struct zed_conf *zcp;
|
|
|
|
uint64_t saved_eid;
|
|
|
|
int64_t saved_etime[2];
|
|
|
|
|
|
|
|
zed_log_init(argv[0]);
|
|
|
|
zed_log_stderr_open(LOG_NOTICE);
|
|
|
|
zcp = zed_conf_create();
|
|
|
|
zed_conf_parse_opts(zcp, argc, argv);
|
|
|
|
if (zcp->do_verbose)
|
|
|
|
zed_log_stderr_open(LOG_INFO);
|
|
|
|
|
|
|
|
if (geteuid() != 0)
|
|
|
|
zed_log_die("Must be run as root");
|
|
|
|
|
|
|
|
zed_conf_parse_file(zcp);
|
|
|
|
|
|
|
|
zed_file_close_from(STDERR_FILENO + 1);
|
|
|
|
|
2014-08-27 20:18:01 +00:00
|
|
|
(void) umask(0);
|
|
|
|
|
2014-01-21 21:30:03 +00:00
|
|
|
if (chdir("/") < 0)
|
|
|
|
zed_log_die("Failed to change to root directory");
|
|
|
|
|
|
|
|
if (zed_conf_scan_dir(zcp) < 0)
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
|
|
|
if (!zcp->do_foreground) {
|
2014-08-27 20:18:01 +00:00
|
|
|
_start_daemonize();
|
2014-01-21 21:30:03 +00:00
|
|
|
zed_log_syslog_open(LOG_DAEMON);
|
|
|
|
}
|
2014-08-27 20:18:01 +00:00
|
|
|
_setup_sig_handlers();
|
|
|
|
|
|
|
|
if (zcp->do_memlock)
|
|
|
|
_lock_memory();
|
2014-01-21 21:30:03 +00:00
|
|
|
|
2014-10-01 21:56:07 +00:00
|
|
|
if ((zed_conf_write_pid(zcp) < 0) && (!zcp->do_force))
|
|
|
|
exit(EXIT_FAILURE);
|
2014-01-21 21:30:03 +00:00
|
|
|
|
2014-08-27 20:18:01 +00:00
|
|
|
if (!zcp->do_foreground)
|
|
|
|
_finish_daemonize();
|
|
|
|
|
|
|
|
zed_log_msg(LOG_NOTICE,
|
|
|
|
"ZFS Event Daemon %s-%s (PID %d)",
|
2016-12-12 18:46:26 +00:00
|
|
|
ZFS_META_VERSION, ZFS_META_RELEASE, (int)getpid());
|
2014-08-27 20:18:01 +00:00
|
|
|
|
2014-01-21 21:30:03 +00:00
|
|
|
if (zed_conf_open_state(zcp) < 0)
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
|
|
|
if (zed_conf_read_state(zcp, &saved_eid, saved_etime) < 0)
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
zed additional features
This commit adds two features to zed, that macOS desires. The first
is that when you unload the kernel module, zed would enter into a
cpubusy loop calling zfs_events_next() repeatedly. We now look for
ENODEV, returned by kernel, so zed can exit gracefully.
Second feature is -I (idle) (alas -P persist was taken) is for the
deamon to;
1; if started without ZFS kernel module, stick around waiting for it.
2; if kernel module is unloaded, go back to 1.
This is due to daemons in macOS is started by launchctl, and is
expected to stick around.
Currently, the busy loop only exists when errno is ENODEV. This is
to ensure that functionality that upstream expects is not changed.
It did not care about errors before, and it still does not. (with the
exception of ENODEV).
However, it is probably better that all errors
(ERESTART notwithstanding) exits the loop, and the issues complaining
about zed taking all CPU will go away.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Jorgen Lundman <lundman@lundman.net>
Closes #10476
2020-06-22 16:53:34 +00:00
|
|
|
idle:
|
|
|
|
/*
|
|
|
|
* If -I is specified, attempt to open /dev/zfs repeatedly until
|
|
|
|
* successful.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
if (!zed_event_init(zcp))
|
|
|
|
break;
|
|
|
|
/* Wait for some time and try again. tunable? */
|
|
|
|
sleep(30);
|
|
|
|
} while (!_got_exit && zcp->do_idle);
|
|
|
|
|
|
|
|
if (_got_exit)
|
|
|
|
goto out;
|
|
|
|
|
2014-01-21 21:30:03 +00:00
|
|
|
zed_event_seek(zcp, saved_eid, saved_etime);
|
|
|
|
|
|
|
|
while (!_got_exit) {
|
zed additional features
This commit adds two features to zed, that macOS desires. The first
is that when you unload the kernel module, zed would enter into a
cpubusy loop calling zfs_events_next() repeatedly. We now look for
ENODEV, returned by kernel, so zed can exit gracefully.
Second feature is -I (idle) (alas -P persist was taken) is for the
deamon to;
1; if started without ZFS kernel module, stick around waiting for it.
2; if kernel module is unloaded, go back to 1.
This is due to daemons in macOS is started by launchctl, and is
expected to stick around.
Currently, the busy loop only exists when errno is ENODEV. This is
to ensure that functionality that upstream expects is not changed.
It did not care about errors before, and it still does not. (with the
exception of ENODEV).
However, it is probably better that all errors
(ERESTART notwithstanding) exits the loop, and the issues complaining
about zed taking all CPU will go away.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Jorgen Lundman <lundman@lundman.net>
Closes #10476
2020-06-22 16:53:34 +00:00
|
|
|
int rv;
|
2014-01-21 21:30:03 +00:00
|
|
|
if (_got_hup) {
|
|
|
|
_got_hup = 0;
|
|
|
|
(void) zed_conf_scan_dir(zcp);
|
|
|
|
}
|
zed additional features
This commit adds two features to zed, that macOS desires. The first
is that when you unload the kernel module, zed would enter into a
cpubusy loop calling zfs_events_next() repeatedly. We now look for
ENODEV, returned by kernel, so zed can exit gracefully.
Second feature is -I (idle) (alas -P persist was taken) is for the
deamon to;
1; if started without ZFS kernel module, stick around waiting for it.
2; if kernel module is unloaded, go back to 1.
This is due to daemons in macOS is started by launchctl, and is
expected to stick around.
Currently, the busy loop only exists when errno is ENODEV. This is
to ensure that functionality that upstream expects is not changed.
It did not care about errors before, and it still does not. (with the
exception of ENODEV).
However, it is probably better that all errors
(ERESTART notwithstanding) exits the loop, and the issues complaining
about zed taking all CPU will go away.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Jorgen Lundman <lundman@lundman.net>
Closes #10476
2020-06-22 16:53:34 +00:00
|
|
|
rv = zed_event_service(zcp);
|
|
|
|
|
|
|
|
/* ENODEV: When kernel module is unloaded (osx) */
|
|
|
|
if (rv == ENODEV)
|
|
|
|
break;
|
2014-01-21 21:30:03 +00:00
|
|
|
}
|
zed additional features
This commit adds two features to zed, that macOS desires. The first
is that when you unload the kernel module, zed would enter into a
cpubusy loop calling zfs_events_next() repeatedly. We now look for
ENODEV, returned by kernel, so zed can exit gracefully.
Second feature is -I (idle) (alas -P persist was taken) is for the
deamon to;
1; if started without ZFS kernel module, stick around waiting for it.
2; if kernel module is unloaded, go back to 1.
This is due to daemons in macOS is started by launchctl, and is
expected to stick around.
Currently, the busy loop only exists when errno is ENODEV. This is
to ensure that functionality that upstream expects is not changed.
It did not care about errors before, and it still does not. (with the
exception of ENODEV).
However, it is probably better that all errors
(ERESTART notwithstanding) exits the loop, and the issues complaining
about zed taking all CPU will go away.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Jorgen Lundman <lundman@lundman.net>
Closes #10476
2020-06-22 16:53:34 +00:00
|
|
|
|
2014-01-21 21:30:03 +00:00
|
|
|
zed_log_msg(LOG_NOTICE, "Exiting");
|
|
|
|
zed_event_fini(zcp);
|
zed additional features
This commit adds two features to zed, that macOS desires. The first
is that when you unload the kernel module, zed would enter into a
cpubusy loop calling zfs_events_next() repeatedly. We now look for
ENODEV, returned by kernel, so zed can exit gracefully.
Second feature is -I (idle) (alas -P persist was taken) is for the
deamon to;
1; if started without ZFS kernel module, stick around waiting for it.
2; if kernel module is unloaded, go back to 1.
This is due to daemons in macOS is started by launchctl, and is
expected to stick around.
Currently, the busy loop only exists when errno is ENODEV. This is
to ensure that functionality that upstream expects is not changed.
It did not care about errors before, and it still does not. (with the
exception of ENODEV).
However, it is probably better that all errors
(ERESTART notwithstanding) exits the loop, and the issues complaining
about zed taking all CPU will go away.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Jorgen Lundman <lundman@lundman.net>
Closes #10476
2020-06-22 16:53:34 +00:00
|
|
|
|
|
|
|
if (zcp->do_idle && !_got_exit)
|
|
|
|
goto idle;
|
|
|
|
|
|
|
|
out:
|
2014-01-21 21:30:03 +00:00
|
|
|
zed_conf_destroy(zcp);
|
|
|
|
zed_log_fini();
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|