|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* iSCSI daemon event handler
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
|
|
Packit |
eace71 |
* Copyright (C) 2006 Mike Christie
|
|
Packit |
eace71 |
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
|
|
Packit |
eace71 |
* maintained by open-iscsi@googlegroups.com
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Originally based on:
|
|
Packit |
eace71 |
* (C) 2004 FUJITA Tomonori <tomof@acm.org>
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
eace71 |
* it under the terms of the GNU General Public License as published
|
|
Packit |
eace71 |
* by the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
eace71 |
* (at your option) any later version.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
eace71 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
eace71 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
eace71 |
* General Public License for more details.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* See the file COPYING included with this distribution for more details.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
#include <stdlib.h>
|
|
Packit |
eace71 |
#include <errno.h>
|
|
Packit |
eace71 |
#include <sys/poll.h>
|
|
Packit |
eace71 |
#include <sys/types.h>
|
|
Packit |
eace71 |
#include <sys/wait.h>
|
|
Packit |
eace71 |
#include <sys/signalfd.h>
|
|
Packit |
eace71 |
#include <unistd.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "mgmt_ipc.h"
|
|
Packit |
eace71 |
#include "iscsi_ipc.h"
|
|
Packit |
eace71 |
#include "sysfs.h"
|
|
Packit |
eace71 |
#include "iscsid.h"
|
|
Packit |
eace71 |
#include "log.h"
|
|
Packit |
eace71 |
#include "iscsi_ipc.h"
|
|
Packit |
eace71 |
#include "actor.h"
|
|
Packit |
eace71 |
#include "initiator.h"
|
|
Packit |
eace71 |
#include "iscsi_err.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static unsigned int reap_count;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* track pid of reload fork, while running */
|
|
Packit |
eace71 |
static pid_t reload_pid = 0;
|
|
Packit |
eace71 |
static void (*reload_callback)(void);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define REAP_WAKEUP 1000 /* in millisecs */
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void reap_inc(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
reap_count++;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* track the reload process to be reaped, when done */
|
|
Packit |
eace71 |
void reap_track_reload_process(pid_t reload_proc_pid, void (*reload_done_callback)(void))
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
reload_pid = reload_proc_pid;
|
|
Packit |
eace71 |
reload_callback = reload_done_callback;
|
|
Packit |
eace71 |
reap_inc();
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void reap_proc(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int i, max_reaps;
|
|
Packit |
eace71 |
pid_t rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* We don't really need reap_count, but calling wait() all the
|
|
Packit |
eace71 |
* time seems excessive.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
max_reaps = reap_count;
|
|
Packit |
eace71 |
for (i = 0; i < max_reaps; i++) {
|
|
Packit |
eace71 |
rc = waitpid(0, NULL, WNOHANG);
|
|
Packit |
eace71 |
if (rc > 0) {
|
|
Packit |
eace71 |
if (rc == reload_pid) {
|
|
Packit |
eace71 |
log_debug(6, "reaped reload process");
|
|
Packit |
eace71 |
reload_callback();
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
reap_count--;
|
|
Packit |
eace71 |
log_debug(6, "reaped pid %d, reap_count now %d",
|
|
Packit |
eace71 |
(int)rc, reap_count);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static LIST_HEAD(shutdown_callbacks);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct shutdown_callback {
|
|
Packit |
eace71 |
struct list_head list;
|
|
Packit |
eace71 |
pid_t pid;
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
int shutdown_callback(pid_t pid)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct shutdown_callback *cb;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
cb = calloc(1, sizeof(*cb));
|
|
Packit |
eace71 |
if (!cb)
|
|
Packit |
eace71 |
return ENOMEM;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&cb->list);
|
|
Packit |
eace71 |
cb->pid = pid;
|
|
Packit |
eace71 |
log_debug(1, "adding %d for shutdown cb", pid);
|
|
Packit |
eace71 |
list_add_tail(&cb->list, &shutdown_callbacks);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void shutdown_notify_pids(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct shutdown_callback *cb;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry(cb, &shutdown_callbacks, list) {
|
|
Packit |
eace71 |
log_debug(1, "Killing %d", cb->pid);
|
|
Packit |
eace71 |
kill(cb->pid, SIGTERM);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int shutdown_wait_pids(void)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct shutdown_callback *cb, *tmp;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry_safe(cb, tmp, &shutdown_callbacks, list) {
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* the proc reaper could clean it up, so wait for any
|
|
Packit |
eace71 |
* sign that it is gone.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (waitpid(cb->pid, NULL, WNOHANG)) {
|
|
Packit |
eace71 |
log_debug(1, "%d done", cb->pid);
|
|
Packit |
eace71 |
list_del(&cb->list);
|
|
Packit |
eace71 |
free(cb);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return list_empty(&shutdown_callbacks);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define POLL_CTRL 0
|
|
Packit |
eace71 |
#define POLL_IPC 1
|
|
Packit |
eace71 |
#define POLL_ALARM 2
|
|
Packit |
eace71 |
#define POLL_MAX 3
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static volatile int event_loop_stop;
|
|
Packit |
eace71 |
static queue_task_t *shutdown_qtask;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void event_loop_exit(queue_task_t *qtask)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
shutdown_qtask = qtask;
|
|
Packit |
eace71 |
event_loop_stop = 1;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct pollfd poll_array[POLL_MAX];
|
|
Packit |
eace71 |
int res, has_shutdown_children = 0;
|
|
Packit |
eace71 |
sigset_t sigset;
|
|
Packit |
eace71 |
int sig_fd;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Mask off SIGALRM so we can recv it via signalfd */
|
|
Packit |
eace71 |
sigemptyset(&sigset);
|
|
Packit |
eace71 |
sigaddset(&sigset, SIGALRM);
|
|
Packit |
eace71 |
sigprocmask(SIG_SETMASK, &sigset, NULL);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
sig_fd = signalfd(-1, &sigset, SFD_NONBLOCK);
|
|
Packit |
eace71 |
if (sig_fd == -1) {
|
|
Packit |
eace71 |
log_error("signalfd failed: %m");
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
poll_array[POLL_CTRL].fd = control_fd;
|
|
Packit |
eace71 |
poll_array[POLL_CTRL].events = POLLIN;
|
|
Packit |
eace71 |
poll_array[POLL_IPC].fd = mgmt_ipc_fd;
|
|
Packit |
eace71 |
poll_array[POLL_IPC].events = POLLIN;
|
|
Packit |
eace71 |
poll_array[POLL_ALARM].fd = sig_fd;
|
|
Packit |
eace71 |
poll_array[POLL_ALARM].events = POLLIN;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
event_loop_stop = 0;
|
|
Packit |
eace71 |
while (1) {
|
|
Packit |
eace71 |
if (event_loop_stop) {
|
|
Packit |
eace71 |
if (!has_shutdown_children) {
|
|
Packit |
eace71 |
has_shutdown_children = 1;
|
|
Packit |
eace71 |
shutdown_notify_pids();
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (shutdown_wait_pids())
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Runs actors and may set alarm for future actors */
|
|
Packit |
eace71 |
actor_poll();
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
res = poll(poll_array, POLL_MAX, reap_count ? REAP_WAKEUP : -1);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (res > 0) {
|
|
Packit |
eace71 |
log_debug(6, "poll result %d", res);
|
|
Packit |
eace71 |
if (poll_array[POLL_CTRL].revents)
|
|
Packit |
eace71 |
ipc->ctldev_handle();
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (poll_array[POLL_IPC].revents)
|
|
Packit |
eace71 |
mgmt_ipc_handle(mgmt_ipc_fd);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (poll_array[POLL_ALARM].revents) {
|
|
Packit |
eace71 |
struct signalfd_siginfo si;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (read(sig_fd, &si, sizeof(si)) == -1) {
|
|
Packit |
eace71 |
log_error("got sigfd read() error, errno (%d), "
|
|
Packit |
eace71 |
"exiting", errno);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
log_debug(1, "Poll was woken by an alarm");
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
} else if (res < 0) {
|
|
Packit |
eace71 |
if (errno == EINTR) {
|
|
Packit |
eace71 |
log_debug(1, "event_loop interrupted");
|
|
Packit |
eace71 |
} else {
|
|
Packit |
eace71 |
log_error("got poll() error (%d), errno (%d), "
|
|
Packit |
eace71 |
"exiting", res, errno);
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
reap_proc();
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* flush sysfs cache since kernel objs may
|
|
Packit |
eace71 |
* have changed as a result of handling op
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
sysfs_cleanup();
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (shutdown_qtask)
|
|
Packit |
eace71 |
mgmt_ipc_write_rsp(shutdown_qtask, ISCSI_SUCCESS);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
close(sig_fd);
|
|
Packit |
eace71 |
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
|
|
Packit |
eace71 |
}
|