summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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();