diff options
-rw-r--r-- | usr/event_poll.c | 21 | ||||
-rw-r--r-- | usr/event_poll.h | 1 | ||||
-rw-r--r-- | usr/iscsi_sysfs.c | 45 | ||||
-rw-r--r-- | usr/iscsi_sysfs.h | 1 | ||||
-rw-r--r-- | usr/iscsid.c | 60 |
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(); |