summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLee Duncan <lduncan@suse.com>2018-10-16 13:54:04 -0700
committerLee Duncan <lduncan@suse.com>2018-10-16 13:54:04 -0700
commit93fb910880604fe9509e7efa7b8d32098fc0ef1f (patch)
tree20957042f385c352f5a393df71ec24811deb7932
parent666694ed3654e333751af0897c8b71f8cc1829f8 (diff)
downloadopen-iscsi-93fb910880604fe9509e7efa7b8d32098fc0ef1f.tar.gz
Use sd_notify() to tell systemd when iscsid is ready.
In addition, to be able to tells systemd when we are reloading sessions, the code around forking a copy and restoring sessions gets its PID saved so that we know when it is done and can update systemd status. Note that this requires systemd unit file iscsid.service to use Type=notify and NotifyAccess=main.
-rw-r--r--usr/event_poll.c21
-rw-r--r--usr/event_poll.h1
-rw-r--r--usr/iscsi_sysfs.c45
-rw-r--r--usr/iscsi_sysfs.h1
-rw-r--r--usr/iscsid.c60
5 files changed, 114 insertions, 14 deletions
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 8e89b30..f79a1af 100644
--- a/usr/iscsi_sysfs.c
+++ b/usr/iscsi_sysfs.c
@@ -1514,6 +1514,51 @@ 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;
+ info->iscsid_req_tmo = -1;
+
+ 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 35e95ba..0c98440 100644
--- a/usr/iscsid.c
+++ b/usr/iscsid.c
@@ -34,6 +34,7 @@
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <systemd/sd-daemon.h>
#include "iscsid.h"
#include "mgmt_ipc.h"
@@ -62,6 +63,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 +336,26 @@ 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)
+{
+ 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");
+}
+
+/* called when recovery process has been reaped */
+static void set_state_done_reloading(void)
+{
+ sessions_to_recover = 0;
+ sd_notifyf(0, "READY=1\n"
+ "STATUS=Ready to process requests\n");
+}
+
int main(int argc, char *argv[])
{
struct utsname host_info; /* will use to compound initiator alias */
@@ -526,18 +548,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 +589,7 @@ int main(int argc, char *argv[])
exit(ISCSI_ERR);
}
+ set_state_to_ready();
event_loop(ipc, control_fd, mgmt_ipc_fd);
idbm_terminate();