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
This commit is contained in:
parent
42d8d1d66a
commit
68301ba20e
|
@ -263,18 +263,43 @@ main(int argc, char *argv[])
|
||||||
if (zed_conf_read_state(zcp, &saved_eid, saved_etime) < 0)
|
if (zed_conf_read_state(zcp, &saved_eid, saved_etime) < 0)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
zed_event_init(zcp);
|
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;
|
||||||
|
|
||||||
zed_event_seek(zcp, saved_eid, saved_etime);
|
zed_event_seek(zcp, saved_eid, saved_etime);
|
||||||
|
|
||||||
while (!_got_exit) {
|
while (!_got_exit) {
|
||||||
|
int rv;
|
||||||
if (_got_hup) {
|
if (_got_hup) {
|
||||||
_got_hup = 0;
|
_got_hup = 0;
|
||||||
(void) zed_conf_scan_dir(zcp);
|
(void) zed_conf_scan_dir(zcp);
|
||||||
}
|
}
|
||||||
zed_event_service(zcp);
|
rv = zed_event_service(zcp);
|
||||||
|
|
||||||
|
/* ENODEV: When kernel module is unloaded (osx) */
|
||||||
|
if (rv == ENODEV)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
zed_log_msg(LOG_NOTICE, "Exiting");
|
zed_log_msg(LOG_NOTICE, "Exiting");
|
||||||
zed_event_fini(zcp);
|
zed_event_fini(zcp);
|
||||||
|
|
||||||
|
if (zcp->do_idle && !_got_exit)
|
||||||
|
goto idle;
|
||||||
|
|
||||||
|
out:
|
||||||
zed_conf_destroy(zcp);
|
zed_conf_destroy(zcp);
|
||||||
zed_log_fini();
|
zed_log_fini();
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
|
|
@ -153,6 +153,8 @@ _zed_conf_display_help(const char *prog, int got_err)
|
||||||
"Force daemon to run.");
|
"Force daemon to run.");
|
||||||
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-F",
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-F",
|
||||||
"Run daemon in the foreground.");
|
"Run daemon in the foreground.");
|
||||||
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-I",
|
||||||
|
"Idle daemon until kernel module is (re)loaded.");
|
||||||
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-M",
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-M",
|
||||||
"Lock all pages in memory.");
|
"Lock all pages in memory.");
|
||||||
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-P",
|
fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-P",
|
||||||
|
@ -249,7 +251,7 @@ _zed_conf_parse_path(char **resultp, const char *path)
|
||||||
void
|
void
|
||||||
zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
|
zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
|
||||||
{
|
{
|
||||||
const char * const opts = ":hLVc:d:p:P:s:vfFMZ";
|
const char * const opts = ":hLVc:d:p:P:s:vfFMZI";
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
if (!zcp || !argv || !argv[0])
|
if (!zcp || !argv || !argv[0])
|
||||||
|
@ -274,6 +276,9 @@ zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
|
||||||
case 'd':
|
case 'd':
|
||||||
_zed_conf_parse_path(&zcp->zedlet_dir, optarg);
|
_zed_conf_parse_path(&zcp->zedlet_dir, optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'I':
|
||||||
|
zcp->do_idle = 1;
|
||||||
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
_zed_conf_parse_path(&zcp->pid_file, optarg);
|
_zed_conf_parse_path(&zcp->pid_file, optarg);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -25,6 +25,7 @@ struct zed_conf {
|
||||||
unsigned do_memlock:1; /* true if locking memory */
|
unsigned do_memlock:1; /* true if locking memory */
|
||||||
unsigned do_verbose:1; /* true if verbosity enabled */
|
unsigned do_verbose:1; /* true if verbosity enabled */
|
||||||
unsigned do_zero:1; /* true if zeroing state */
|
unsigned do_zero:1; /* true if zeroing state */
|
||||||
|
unsigned do_idle:1; /* true if idle enabled */
|
||||||
int syslog_facility; /* syslog facility value */
|
int syslog_facility; /* syslog facility value */
|
||||||
int min_events; /* RESERVED FOR FUTURE USE */
|
int min_events; /* RESERVED FOR FUTURE USE */
|
||||||
int max_events; /* RESERVED FOR FUTURE USE */
|
int max_events; /* RESERVED FOR FUTURE USE */
|
||||||
|
|
|
@ -41,25 +41,36 @@
|
||||||
/*
|
/*
|
||||||
* Open the libzfs interface.
|
* Open the libzfs interface.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
zed_event_init(struct zed_conf *zcp)
|
zed_event_init(struct zed_conf *zcp)
|
||||||
{
|
{
|
||||||
if (!zcp)
|
if (!zcp)
|
||||||
zed_log_die("Failed zed_event_init: %s", strerror(EINVAL));
|
zed_log_die("Failed zed_event_init: %s", strerror(EINVAL));
|
||||||
|
|
||||||
zcp->zfs_hdl = libzfs_init();
|
zcp->zfs_hdl = libzfs_init();
|
||||||
if (!zcp->zfs_hdl)
|
if (!zcp->zfs_hdl) {
|
||||||
|
if (zcp->do_idle)
|
||||||
|
return (-1);
|
||||||
zed_log_die("Failed to initialize libzfs");
|
zed_log_die("Failed to initialize libzfs");
|
||||||
|
}
|
||||||
|
|
||||||
zcp->zevent_fd = open(ZFS_DEV, O_RDWR);
|
zcp->zevent_fd = open(ZFS_DEV, O_RDWR);
|
||||||
if (zcp->zevent_fd < 0)
|
if (zcp->zevent_fd < 0) {
|
||||||
|
if (zcp->do_idle)
|
||||||
|
return (-1);
|
||||||
zed_log_die("Failed to open \"%s\": %s",
|
zed_log_die("Failed to open \"%s\": %s",
|
||||||
ZFS_DEV, strerror(errno));
|
ZFS_DEV, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
zfs_agent_init(zcp->zfs_hdl);
|
zfs_agent_init(zcp->zfs_hdl);
|
||||||
|
|
||||||
if (zed_disk_event_init() != 0)
|
if (zed_disk_event_init() != 0) {
|
||||||
|
if (zcp->do_idle)
|
||||||
|
return (-1);
|
||||||
zed_log_die("Failed to initialize disk events");
|
zed_log_die("Failed to initialize disk events");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -873,7 +884,7 @@ _zed_event_add_time_strings(uint64_t eid, zed_strings_t *zsp, int64_t etime[])
|
||||||
/*
|
/*
|
||||||
* Service the next zevent, blocking until one is available.
|
* Service the next zevent, blocking until one is available.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
zed_event_service(struct zed_conf *zcp)
|
zed_event_service(struct zed_conf *zcp)
|
||||||
{
|
{
|
||||||
nvlist_t *nvl;
|
nvlist_t *nvl;
|
||||||
|
@ -891,13 +902,13 @@ zed_event_service(struct zed_conf *zcp)
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
zed_log_msg(LOG_ERR, "Failed to service zevent: %s",
|
zed_log_msg(LOG_ERR, "Failed to service zevent: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return;
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped, ZEVENT_NONE,
|
rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped, ZEVENT_NONE,
|
||||||
zcp->zevent_fd);
|
zcp->zevent_fd);
|
||||||
|
|
||||||
if ((rv != 0) || !nvl)
|
if ((rv != 0) || !nvl)
|
||||||
return;
|
return (errno);
|
||||||
|
|
||||||
if (n_dropped > 0) {
|
if (n_dropped > 0) {
|
||||||
zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
|
zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
|
||||||
|
@ -950,4 +961,5 @@ zed_event_service(struct zed_conf *zcp)
|
||||||
zed_strings_destroy(zsp);
|
zed_strings_destroy(zsp);
|
||||||
}
|
}
|
||||||
nvlist_free(nvl);
|
nvlist_free(nvl);
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,13 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void zed_event_init(struct zed_conf *zcp);
|
int zed_event_init(struct zed_conf *zcp);
|
||||||
|
|
||||||
void zed_event_fini(struct zed_conf *zcp);
|
void zed_event_fini(struct zed_conf *zcp);
|
||||||
|
|
||||||
int zed_event_seek(struct zed_conf *zcp, uint64_t saved_eid,
|
int zed_event_seek(struct zed_conf *zcp, uint64_t saved_eid,
|
||||||
int64_t saved_etime[]);
|
int64_t saved_etime[]);
|
||||||
|
|
||||||
void zed_event_service(struct zed_conf *zcp);
|
int zed_event_service(struct zed_conf *zcp);
|
||||||
|
|
||||||
#endif /* !ZED_EVENT_H */
|
#endif /* !ZED_EVENT_H */
|
||||||
|
|
|
@ -24,6 +24,7 @@ ZED \- ZFS Event Daemon
|
||||||
[\fB\-f\fR]
|
[\fB\-f\fR]
|
||||||
[\fB\-F\fR]
|
[\fB\-F\fR]
|
||||||
[\fB\-h\fR]
|
[\fB\-h\fR]
|
||||||
|
[\fB\-I\fR]
|
||||||
[\fB\-L\fR]
|
[\fB\-L\fR]
|
||||||
[\fB\-M\fR]
|
[\fB\-M\fR]
|
||||||
[\fB\-p\fR \fIpidfile\fR]
|
[\fB\-p\fR \fIpidfile\fR]
|
||||||
|
@ -66,6 +67,12 @@ Lock all current and future pages in the virtual memory address space.
|
||||||
This may help the daemon remain responsive when the system is under heavy
|
This may help the daemon remain responsive when the system is under heavy
|
||||||
memory pressure.
|
memory pressure.
|
||||||
.TP
|
.TP
|
||||||
|
.BI \-I
|
||||||
|
Request that the daemon idle rather than exit when the kernel modules are
|
||||||
|
not loaded. Processing of events will start, or resume, when the kernel
|
||||||
|
modules are (re)loaded. Under Linux the kernel modules cannot be unloaded
|
||||||
|
while the daemon is running.
|
||||||
|
.TP
|
||||||
.BI \-Z
|
.BI \-Z
|
||||||
Zero the daemon's state, thereby allowing zevents still within the kernel
|
Zero the daemon's state, thereby allowing zevents still within the kernel
|
||||||
to be reprocessed.
|
to be reprocessed.
|
||||||
|
|
Loading…
Reference in New Issue