From 6896af7a1a076302470db07ac9e6e91eee8988df Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Tue, 16 Oct 2018 13:53:09 -0700 Subject: [PATCH 1/1] Update service files and add sd_notify support to iscsid and iscsiuio Cherry Picks the following changes from upstream: * Added service file for iscsi logins * Use sd_notify() to tell systemd when iscsid is ready. * Update systemd unit files for iscsid * Use pkg-config in Makefiles for newer libraries. * Improve daemon synchronization, fix err msgs * Fix pipe notification code * Add systemd support for iscsiuio * Make iscsid systemd usage optional * Handle systemd disablement correctly in iscsiuio --- Makefile | 10 +++++- etc/systemd/iscsi.service | 21 +++++------- etc/systemd/iscsid.service | 12 +++---- etc/systemd/iscsiuio.service | 8 +++-- iscsiuio/configure.ac | 8 +++++ iscsiuio/src/unix/logger.c | 2 +- iscsiuio/src/unix/main.c | 49 +++++++++++++++++++++----- usr/Makefile | 14 ++++++-- usr/event_poll.c | 21 ++++++++++-- usr/event_poll.h | 1 + usr/iscsi_sysfs.c | 44 ++++++++++++++++++++++++ usr/iscsi_sysfs.h | 1 + usr/iscsid.c | 66 +++++++++++++++++++++++++++++------- 13 files changed, 208 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 03175a3..340c457 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,14 @@ ifneq (,$(CFLAGS)) export CFLAGS endif +# export systemd disablement if set +ifneq ($(NO_SYSTEMD),) +export NO_SYSTEMD +WITHOUT_ARG = --without-systemd +else +WITHOUT_ARG = +endif + # Random comments: # using '$(MAKE)' instead of just 'make' allows make to run in parallel # over multiple makefile. @@ -59,7 +67,7 @@ utils/open-isns/Makefile: utils/open-isns/configure utils/open-isns/Makefile.in cd utils/open-isns; ./configure --with-security=no iscsiuio/Makefile: iscsiuio/configure iscsiuio/Makefile.in - cd iscsiuio; ./configure + cd iscsiuio; ./configure $(WITHOUT_ARG) iscsiuio/configure iscsiuio/Makefile.in: iscsiuio/configure.ac iscsiuio/Makefile.am cd iscsiuio; autoreconf --install diff --git a/etc/systemd/iscsi.service b/etc/systemd/iscsi.service index 2736956..0edcf51 100644 --- a/etc/systemd/iscsi.service +++ b/etc/systemd/iscsi.service @@ -1,20 +1,17 @@ [Unit] Description=Login and scanning of iSCSI devices -Documentation=man:iscsid(8) man:iscsiadm(8) -DefaultDependencies=no -Conflicts=shutdown.target -After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service -Before=remote-fs-pre.target -Wants=remote-fs-pre.target iscsi-shutdown.service -ConditionDirectoryNotEmpty=|/var/lib/iscsi/nodes -ConditionDirectoryNotEmpty=|/sys/class/iscsi_session +Documentation=man:iscsiadm(8) man:iscsid(8) +Before=remote-fs.target +After=network.target network-online.target iscsid.service +ConditionPathExists=/etc/iscsi/initiatorname.iscsi [Service] Type=oneshot -RemainAfterExit=true -ExecStart=-/usr/libexec/iscsi-mark-root-nodes ExecStart=-/sbin/iscsiadm -m node --loginall=automatic -ExecReload=-/sbin/iscsiadm -m node --loginall=automatic +ExecStop=/sbin/iscsiadm -m node --logoutall=automatic +ExecStop=/sbin/iscsiadm -m node --logoutall=manual +SuccessExitStatus=21 +RemainAfterExit=true [Install] -WantedBy=sysinit.target +WantedBy=remote-fs.target diff --git a/etc/systemd/iscsid.service b/etc/systemd/iscsid.service index 653dd08..f5e8979 100644 --- a/etc/systemd/iscsid.service +++ b/etc/systemd/iscsid.service @@ -1,16 +1,16 @@ [Unit] Description=Open-iSCSI -Documentation=man:iscsid(8) man:iscsiadm(8) +Documentation=man:iscsid(8) man:iscsiuio(8) man:iscsiadm(8) DefaultDependencies=no -Conflicts=shutdown.target After=network.target iscsiuio.service Before=remote-fs-pre.target [Service] -Type=forking -PIDFile=/var/run/iscsid.pid -ExecStart=/usr/sbin/iscsid -ExecStop=/sbin/iscsiadm -k 0 2 +Type=notify +NotifyAccess=main +ExecStart=/sbin/iscsid -f +KillMode=mixed [Install] WantedBy=multi-user.target +Also=iscsid.socket diff --git a/etc/systemd/iscsiuio.service b/etc/systemd/iscsiuio.service index f0410b7..e4d9fd0 100644 --- a/etc/systemd/iscsiuio.service +++ b/etc/systemd/iscsiuio.service @@ -9,9 +9,11 @@ After=network.target Before=remote-fs-pre.target iscsid.service [Service] -Type=forking -PIDFile=/var/run/iscsiuio.pid -ExecStart=/usr/sbin/iscsiuio +Type=notify +NotifyAccess=main +ExecStart=/sbin/iscsiuio -f +KillMode=mixed +Restart=on-failure [Install] WantedBy=multi-user.target diff --git a/iscsiuio/configure.ac b/iscsiuio/configure.ac index 7d53323..b41df0e 100644 --- a/iscsiuio/configure.ac +++ b/iscsiuio/configure.ac @@ -63,6 +63,14 @@ AC_ARG_ENABLE(debug, CFLAGS="${CFLAGS} -g -O0" fi]) AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) +## check for systemd support, default on +AC_ARG_WITH([systemd], + AS_HELP_STRING([--without-systemd], [Build without systemd]), + [case "${withval}" in + yes) LDFLAGS="`pkg-config --libs libsystemd`" ;; + no) CFLAGS="${CFLAGS} -DNO_SYSTEMD" ;; + *) AC_MSG_ERROR([bad value $withval for --with-systemd]) ;; + esac],[LDFLAGS="`pkg-config --libs libsystemd`"]) AC_CONFIG_COMMANDS([default],[[ if [ -n "$SOURCE_DATE_EPOCH" ] ; then diff --git a/iscsiuio/src/unix/logger.c b/iscsiuio/src/unix/logger.c index d41f9e8..87e16cd 100644 --- a/iscsiuio/src/unix/logger.c +++ b/iscsiuio/src/unix/logger.c @@ -135,7 +135,7 @@ int init_logger(char *filename) } main_log.fp = fopen(filename, "a"); if (main_log.fp == NULL) { - printf("Could not create log file: %s <%s>\n", + fprintf(stderr, "WARN: Could not create log file: %s <%s>\n", filename, strerror(errno)); rc = -EIO; } diff --git a/iscsiuio/src/unix/main.c b/iscsiuio/src/unix/main.c index 39d5339..188b96e 100644 --- a/iscsiuio/src/unix/main.c +++ b/iscsiuio/src/unix/main.c @@ -48,6 +48,9 @@ #include #include #include +#ifndef NO_SYSTEMD +#include +#endif #include "uip.h" #include "uip_arp.h" @@ -146,7 +149,7 @@ signal_wait: fini_logger(SHUTDOWN_LOGGER); rc = init_logger(main_log.log_file); if (rc != 0) - printf("Could not initialize the logger in " + fprintf(stderr, "WARN: Could not initialize the logger in " "signal!\n"); goto signal_wait; default: @@ -239,6 +242,7 @@ int main(int argc, char *argv[]) int foreground = 0; pid_t pid; pthread_attr_t attr; + int pipefds[2]; /* Record the start time for the user space daemon */ opt.start_time = time(NULL); @@ -281,7 +285,7 @@ int main(int argc, char *argv[]) /* initialize the logger */ rc = init_logger(main_log.log_file); if (rc != 0 && opt.debug == DEBUG_ON) - printf("WARN: Could not initialize the logger\n"); + fprintf(stderr, "WARN: Could not initialize the logger\n"); } LOG_INFO("Started iSCSI uio stack: Ver " PACKAGE_VERSION); @@ -316,38 +320,53 @@ int main(int argc, char *argv[]) fd = open(pid_file, O_WRONLY | O_CREAT, 0644); if (fd < 0) { - printf("Unable to create pid file: %s", pid_file); + fprintf(stderr, "ERR: Unable to create pid file: %s\n", + pid_file); + exit(1); + } + + if (pipe(pipefds) < 0) { + fprintf(stderr, "ERR: Unable to create a PIPE: %s\n", + strerror(errno)); exit(1); } pid = fork(); if (pid < 0) { - printf("Starting daemon failed"); + fprintf(stderr, "ERR: Starting daemon failed\n"); exit(1); } else if (pid) { + char msgbuf[4]; + + /* parent: wait for child msg then exit */ + close(pipefds[1]); + read(pipefds[0], msgbuf, sizeof(msgbuf)); exit(0); } + /* the child */ rc = chdir("/"); if (rc == -1) - printf("Unable to chdir(\") [%s]", strerror(errno)); + fprintf(stderr, "WARN: Unable to chdir(\") [%s]\n", strerror(errno)); if (lockf(fd, F_TLOCK, 0) < 0) { - printf("Unable to lock pid file: %s [%s]", + fprintf(stderr, "ERR: Unable to lock pid file: %s [%s]\n", pid_file, strerror(errno)); exit(1); } rc = ftruncate(fd, 0); if (rc == -1) - printf("ftruncate(%d, 0) failed [%s]", + fprintf(stderr, "WARN: ftruncate(%d, 0) failed [%s]\n", fd, strerror(errno)); sprintf(buf, "%d\n", getpid()); written_bytes = write(fd, buf, strlen(buf)); - if (written_bytes == -1) - printf("Could not write pid file [%s]", + if (written_bytes == -1) { + fprintf(stderr, "ERR: Could not write pid file [%s]\n", strerror(errno)); + exit(1); + } close(fd); daemon_init(); @@ -393,6 +412,18 @@ int main(int argc, char *argv[]) if (rc != 0) goto error; + if (!foreground) { + /* signal parent they can go away now */ + close(pipefds[0]); + write(pipefds[1], "ok\n", 3); + close(pipefds[1]); + } + +#ifndef NO_SYSTEMD + sd_notify(0, "READY=1\n" + "STATUS=Ready to process requests\n"); +#endif + /* NetLink connection to listen to NETLINK_ISCSI private messages */ if (nic_nl_open() != 0) goto error; diff --git a/usr/Makefile b/usr/Makefile index 865d001..742a0fb 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -28,10 +28,18 @@ IPC_OBJ=ioctl.o endif endif +PKG_CONFIG = /usr/bin/pkg-config + CFLAGS ?= -O2 -g WARNFLAGS ?= -Wall -Wstrict-prototypes CFLAGS += $(WARNFLAGS) -I../include -I. -I../utils/open-isns \ -D$(OSNAME) $(IPC_CFLAGS) -DISNS_ENABLE +CFLAGS += $(shell $(PKG_CONFIG) --cflags libkmod) +CFLAGS += $(shell $(PKG_CONFIG) --cflags libsystemd) +LDFLAGS += $(shell $(PKG_CONFIG) --libs libkmod) +ifeq ($(NO_SYSTEMD),) +LDFLAGS += $(shell $(PKG_CONFIG) --libs libsystemd) +endif PROGRAMS = iscsid iscsiadm iscsistart # libc compat files @@ -55,14 +63,14 @@ all: $(PROGRAMS) iscsid: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \ iscsid.o session_mgmt.o discoveryd.o mntcheck.o - $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lrt -lmount + $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lrt -lmount $(LDFLAGS) iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o mntcheck.o - $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lmount + $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns -lmount $(LDFLAGS) iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \ iscsistart.o statics.o - $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -lrt + $(CC) $(CFLAGS) $^ -o $@ -lrt $(LDFLAGS) clean: rm -f *.o $(PROGRAMS) .depend $(LIBSYS) diff --git a/usr/event_poll.c b/usr/event_poll.c index ac25044..4cf4ce2 100644 --- a/usr/event_poll.c +++ b/usr/event_poll.c @@ -41,6 +41,10 @@ static unsigned int reap_count; +/* track pid of reload fork, while running */ +static pid_t reload_pid = 0; +static void (*reload_callback)(void); + #define REAP_WAKEUP 1000 /* in millisecs */ void reap_inc(void) @@ -48,9 +52,18 @@ void reap_inc(void) reap_count++; } +/* track the reload process to be reaped, when done */ +void reap_track_reload_process(pid_t reload_proc_pid, void (*reload_done_callback)(void)) +{ + reload_pid = reload_proc_pid; + reload_callback = reload_done_callback; + reap_inc(); +} + void reap_proc(void) { - int rc, i, max_reaps; + int i, max_reaps; + pid_t rc; /* * We don't really need reap_count, but calling wait() all the @@ -60,9 +73,13 @@ void reap_proc(void) for (i = 0; i < max_reaps; i++) { rc = waitpid(0, NULL, WNOHANG); if (rc > 0) { + if (rc == reload_pid) { + log_debug(6, "reaped reload process"); + reload_callback(); + } reap_count--; log_debug(6, "reaped pid %d, reap_count now %d", - rc, reap_count); + (int)rc, reap_count); } } } diff --git a/usr/event_poll.h b/usr/event_poll.h index c0eed5c..f23132b 100644 --- a/usr/event_poll.h +++ b/usr/event_poll.h @@ -25,6 +25,7 @@ struct queue_task; int shutdown_callback(pid_t pid); void reap_proc(void); void reap_inc(void); +void reap_track_reload_process(pid_t realod_proc_pid, void (*reload_done_callback)(void)); void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd); void event_loop_exit(struct queue_task *qtask); diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c index 3395590..b9d5a84 100644 --- a/usr/iscsi_sysfs.c +++ b/usr/iscsi_sysfs.c @@ -1512,6 +1512,50 @@ free_info: return rc; } +/* + * count the number of sessions -- a much-simplified + * version of iscsi_sysfs_for_each_session + * + * TODO: return an array of the session info we find, for use + * by iscsi_sysfs_for_each_session(), so it doesn't have to + * do it all over again + */ +int iscsi_sysfs_count_sessions(void) +{ + struct dirent **namelist = NULL; + int n, i; + struct session_info *info; + + + info = calloc(1, sizeof(*info)); + if (!info) + /* no sessions found */ + return 0; + + n = scandir(ISCSI_SESSION_DIR, &namelist, trans_filter, alphasort); + if (n <= 0) + /* no sessions found */ + goto free_info; + + /* + * try to get session info for each session found, but ignore + * errors if any since it may be a race condition + */ + for (i = 0; i < n; i++) + if (iscsi_sysfs_get_sessioninfo_by_id(info, + namelist[i]->d_name) != 0) + log_warning("could not find session info for %s", + namelist[i]->d_name); + + for (i = 0; i < n; i++) + free(namelist[i]); + free(namelist); + +free_info: + free(info); + return n; +} + int iscsi_sysfs_get_session_state(char *state, int sid) { char id[NAME_SIZE]; diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h index cdcefa6..1d0377f 100644 --- a/usr/iscsi_sysfs.h +++ b/usr/iscsi_sysfs.h @@ -53,6 +53,7 @@ extern int iscsi_sysfs_for_each_iface_on_host(void *data, uint32_t host_no, extern int iscsi_sysfs_for_each_session(void *data, int *nr_found, iscsi_sysfs_session_op_fn *fn, int in_parallel); +extern int iscsi_sysfs_count_sessions(void); extern int iscsi_sysfs_for_each_host(void *data, int *nr_found, iscsi_sysfs_host_op_fn *fn); extern uint32_t iscsi_sysfs_get_host_no_from_sid(uint32_t sid, int *err); diff --git a/usr/iscsid.c b/usr/iscsid.c index 01b90c9..b0629f4 100644 --- a/usr/iscsid.c +++ b/usr/iscsid.c @@ -34,6 +34,9 @@ #include #include #include +#ifndef NO_SYSTEMD +#include +#endif #include "iscsid.h" #include "mgmt_ipc.h" @@ -62,6 +65,7 @@ static pid_t log_pid; static gid_t gid; static int daemonize = 1; static int mgmt_ipc_fd; +static int sessions_to_recover = 0; static struct option const long_options[] = { {"config", required_argument, NULL, 'c'}, @@ -334,6 +338,30 @@ static void missing_iname_warn(char *initiatorname_file) "ignored.", initiatorname_file, initiatorname_file); } +/* called right before we enter the event loop */ +static void set_state_to_ready(void) +{ +#ifndef NO_SYSTEMD + if (sessions_to_recover) + sd_notify(0, "READY=1\n" + "RELOADING=1\n" + "STATUS=Syncing existing session(s)\n"); + else + sd_notify(0, "READY=1\n" + "STATUS=Ready to process requests\n"); +#endif +} + +/* called when recovery process has been reaped */ +static void set_state_done_reloading(void) +{ +#ifndef NO_SYSTEMD + sessions_to_recover = 0; + sd_notifyf(0, "READY=1\n" + "STATUS=Ready to process requests\n"); +#endif +} + int main(int argc, char *argv[]) { struct utsname host_info; /* will use to compound initiator alias */ @@ -526,18 +554,31 @@ int main(int argc, char *argv[]) daemon_config.safe_logout = 1; free(safe_logout); - pid = fork(); - if (pid == 0) { - int nr_found = 0; - /* child */ - /* TODO - test with async support enabled */ - iscsi_sysfs_for_each_session(NULL, &nr_found, sync_session, 0); - exit(0); - } else if (pid < 0) { - log_error("Fork failed error %d: existing sessions" - " will not be synced", errno); - } else - reap_inc(); + /* see if we have any stale sessions to recover */ + sessions_to_recover = iscsi_sysfs_count_sessions(); + if (sessions_to_recover) { + + /* + * recover stale sessions in the background + */ + + pid = fork(); + if (pid == 0) { + int nr_found; /* not used */ + /* child */ + /* TODO - test with async support enabled */ + iscsi_sysfs_for_each_session(NULL, &nr_found, sync_session, 0); + exit(0); + } else if (pid < 0) { + log_error("Fork failed error %d: existing sessions" + " will not be synced", errno); + } else { + /* parent */ + log_debug(8, "forked child (pid=%d) to recover %d session(s)", + (int)pid, sessions_to_recover); + reap_track_reload_process(pid, set_state_done_reloading); + } + } iscsi_initiator_init(); increase_max_files(); @@ -554,6 +595,7 @@ int main(int argc, char *argv[]) exit(ISCSI_ERR); } + set_state_to_ready(); event_loop(ipc, control_fd, mgmt_ipc_fd); idbm_terminate(); -- 2.21.0