📄 iscsid.c
字号:
/* * iSCSI driver for Linux * Copyright (C) 2002 Cisco Systems, Inc. * maintained by linux-iscsi-devel@lists.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * See the file COPYING included with this distribution for more details. * * $Id: iscsid.c,v 1.7 2005/01/11 03:47:09 mikenc Exp $ * * iSCSI Daemon * */#include <stdint.h>#include <unistd.h>#include <errno.h>#include <poll.h>#include <sys/wait.h>#include <sysfs/libsysfs.h>#include "iscsi-sfnet.h"#include "iscsi-protocol.h"#include "iscsi-discovery.h"#include "iscsi-hooks.h"#define ISCSI_TRANSPORT_CLASS "iscsi_transport_class"/* global config info */struct iscsi_daemon_config daemon_config;/* global so that the signal handlers can reset the pids */static struct iscsi_discovery_process_list discovery_processes;static struct iscsi_session_process_list session_processes;static struct iscsi_target_list targets;static voidsigpipe_handler(int unused){ debugmsg(1, "received sigpipe");}voidsigchld_handler(int unused){ pid_t pid = 0; int status = 0; struct iscsi_discovery_process *discovery; struct iscsi_session_process *session; wait_pid: while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { if (WIFEXITED(status)) debugmsg(1, "child %d exited with status %d", pid, WEXITSTATUS(status)); if (WIFSIGNALED(status)) debugmsg(1, "child %d exited on signal %d", pid, WTERMSIG(status)); if (WIFSTOPPED(status)) debugmsg(1, "child %d stopped on signal %d", pid, WSTOPSIG(status)); /* reset pids if the child was a discovery or target process */ for (discovery = discovery_processes.head; discovery; discovery = discovery->next) { if (discovery->pid == pid) { discovery->pid = 0; if (WIFSIGNALED(status)) { /* if the process doesn't want a * particular signal to restart it, * it should catch the signal and exit * (0); */ discovery->restart = 1; discovery_processes.changed = 1; debugmsg(1, "discovery process %p " "needs restart because pid %d" " killed by signal %d", discovery, pid, WTERMSIG(status)); } else if (WIFEXITED(status) && WEXITSTATUS(status)) { /* abnormal exit, try again */ discovery->restart = 1; discovery_processes.changed = 1; debugmsg(1, "discovery process %p " "needs restart because pid %d" " exited with status 0x%x", discovery, pid, WEXITSTATUS(status)); } else { /* normal exit. */ discovery->remove = 1; discovery_processes.changed = 1; debugmsg(1, "discovery process %p pid " "%d fd %d exited normally, " "marking for removal", discovery, pid, discovery->pipe_fd); } goto wait_pid; } } for (session = session_processes.head; session; session = session->next) { if (session->pid == pid) { session->pid = 0; if (WIFSIGNALED(status)) { /* if the process doesn't want a * particular signal to restart it, * it should catch the signal and exit * (0); */ session_processes.changed = 1; session->restart = 1; debugmsg(1, "session process %p needs " "restart because pid %d " "killed by signal %d", session, pid, WTERMSIG(status)); } else if (WIFEXITED(status)) { switch (WEXITSTATUS(status)) { case 0: /* normal exit. we don't * remove session processes * that exit with status 0, * since that always happens * on Linux because the * session process exits as * soon as the kernel module * ioctl returns, and the * kernel module does all the * real work */ debugmsg(1, "session process " "%p with pid %d " "exited normally", session, pid); session->pid = 0; break; case ISCSI_SESSION_FAILED_NO_RETRY: /* the session process died * after the session failed, * but we don't want * to restart it unless the * user asks for a config * reload. This can occur if * the session fails due to * authentication or * authorization failures to * all portals. * We don't want to retry * because we might have * discovered a target that we * aren't authorized to use, * and retrying forever would * fill the log. * We do want the user to be * able to request a retry, in * case they've changed * the access controls on the * target and we're now * authorized. */ debugmsg(1, "session process " "%p with pid %d " "exited, no retry", session, pid); session->pid = 0; session->failed = 1; break; default: session_processes.changed = 1; session->restart = 1; debugmsg(1, "session process " "%p needs restart " "becaused pid %d " "exited with status " "0x%x", session, pid, WEXITSTATUS(status)); break; } } goto wait_pid; } } }}static voidfork_discovery_process(struct iscsi_discovery_process *discovery){ int pipes[2]; discovery->in_progress = 1; /* make pipes */ if (pipe(pipes) < 0) { discovery->restart = 1; return; } fork_again: if (iscsi_process_should_exit()) return; discovery->pid = fork(); if (discovery->pid == 0) { /* close the read side */ close(pipes[0]); /* save the write side */ discovery->pipe_fd = pipes[1]; discovery->pid = getpid(); debugmsg(3, "started discovery process %p for entry %p", discovery, discovery->entry); discovery_process(discovery); exit(0); } else if (discovery->pid < 0) { errormsg("cannot fork discovery %p", discovery); sleep(1); goto fork_again; } else { /* close the write side */ close(pipes[1]); /* save the read side */ discovery->pipe_fd = pipes[0]; debugmsg(3, "forked child %d for discovery %p, pipe fd %d", discovery->pid, discovery, discovery->pipe_fd); }}static voidkill_discovery(struct iscsi_discovery_process *discovery){ pid_t pid = discovery->pid; if (pid) { debugmsg(3, "kill_discovery %p sending SIGTERM to pid %d", discovery, pid); kill(pid, SIGTERM); }}static voidtrigger_rediscovery(struct iscsi_discovery_process *discovery){ pid_t pid = discovery->pid; debugmsg(1, "triggering rediscovery from process %p", discovery); if (pid) { kill(pid, SIGHUP); }}static voidadd_discovery(struct iscsi_discovery_process_list *list, struct iscsi_discovery_process *discovery){ sigset_t chld; debugmsg(7, "adding discovery %p, head %p, tail %p", discovery, list->head, list->tail); /* block SIGCHLD while we're doing this */ sigemptyset(&chld); sigaddset(&chld, SIGCHLD); sigprocmask(SIG_BLOCK, &chld, NULL); if (list->head) { /* append at the tail */ discovery->next = NULL; discovery->prev = list->tail; list->tail->next = discovery; list->tail = discovery; } else { /* become the only list element */ discovery->next = discovery->prev = NULL; list->head = list->tail = discovery; } list->count++; sigprocmask(SIG_UNBLOCK, &chld, NULL);}voidremove_discovery(struct iscsi_discovery_process_list *list, struct iscsi_discovery_process *discovery){ sigset_t chld; /* block SIGCHLD while we're doing this */ sigemptyset(&chld); sigaddset(&chld, SIGCHLD); sigprocmask(SIG_BLOCK, &chld, NULL); if (discovery == list->head) { debugmsg(7, "removing discovery head %p, tail %p", discovery, list->tail); list->head = discovery->next; if (list->head == NULL) list->tail = NULL; discovery->next = discovery->prev = NULL; } else if (discovery == list->tail) { debugmsg(7, "removing discovery tail %p, head %p", discovery, list->head); list->tail = discovery->prev; list->tail->next = NULL; discovery->next = discovery->prev = NULL; } else if (discovery->next && discovery->prev) { debugmsg(7, "removing interior discovery %p, head %p, tail %p", discovery, list->head, list->tail); discovery->next->prev = discovery->prev; discovery->prev->next = discovery->next; discovery->next = discovery->prev = NULL; } else { logmsg(AS_ERROR, "couldn't remove discovery process %p from list %p", discovery, list); } list->count--; sigprocmask(SIG_UNBLOCK, &chld, NULL);}/* recursively free dynamically allocated memory */static voidfree_discovery(struct iscsi_discovery_process *discovery){ if (discovery->entry) { debugmsg(6, "freeing discovery %p with config %p", discovery, discovery->entry); free_config_entry(discovery->entry); discovery->entry = NULL; } else { debugmsg(6, "freeing discovery %p with no config", discovery); } free(discovery);}voidshow_target(struct iscsi_target *target){ int p = 0; struct iscsi_portal_descriptor *portal; debugmsg(1, "target %p name %s", target, target->TargetName); for (portal = target->current_portals; portal; portal = portal->next) { debugmsg(1, "target %p portal[%d]=%p, address %s, ip %u.%u.%u." "%u, port %d, tag %d", target, p++, portal, portal-> address, portal->ip[0], portal->ip[1], portal->ip[2], portal->ip[3], portal->port, portal->tag); }}static voidfork_session_process(struct iscsi_session_process *process){ struct iscsi_session_config *config = process->config; fork_again: if (iscsi_process_should_exit()) return; process->pid = fork(); if (process->pid == 0) { process->pid = getpid(); debugmsg(2, "starting iSCSI session process %p config %p for " "bus %d target %d, TargetName %s", process, config, config->iscsi_bus, config->target_id, config->target->TargetName); iscsi_session_process(process, process->config); exit(0); } else if (process->pid < 0) { errormsg("cannot fork session process %p", process); sleep(1); goto fork_again; } else { debugmsg(2, "forked pid %d for session process %p", process->pid, process); }}voidadd_session_process(struct iscsi_session_process_list *list, struct iscsi_session_process *process){ sigset_t chld; /* block SIGCHLD while we're doing this */ sigemptyset(&chld); sigaddset(&chld, SIGCHLD); sigprocmask(SIG_BLOCK, &chld, NULL); debugmsg(7, "adding session process %p, head %p, tail %p", process, list->head, list->tail); if (list->head) { /* append at the tail */ process->next = NULL; process->prev = list->tail; list->tail->next = process; list->tail = process; } else { /* become the only list element */ process->next = process->prev = NULL; list->head = list->tail = process; } list->count++; sigprocmask(SIG_UNBLOCK, &chld, NULL);}voidremove_session_process(struct iscsi_session_process_list *list, struct iscsi_session_process *process){ sigset_t chld; /* block SIGCHLD while we're doing this */ sigemptyset(&chld); sigaddset(&chld, SIGCHLD); sigprocmask(SIG_BLOCK, &chld, NULL); if (process == list->head) { debugmsg(7, "removing session process head %p, tail %p", process, list->tail); list->head = process->next; if (list->head == NULL) list->tail = NULL; process->next = process->prev = NULL; } else if (process == list->tail) { debugmsg(7, "removing session process tail %p, head %p", process, list->head); list->tail = process->prev; list->tail->next = NULL; process->next = process->prev = NULL; } else if (process->next && process->prev) { debugmsg(7, "removing interior process %p, head %p, tail %p", process, list->head, list->tail); process->next->prev = process->prev; process->prev->next = process->next; process->next = process->prev = NULL; } else { logmsg(AS_ERROR, "couldn't remove session process %p from list %p", process, list); } list->count--; sigprocmask(SIG_UNBLOCK, &chld, NULL);}voidfree_session_process(struct iscsi_session_process *process){ if (process->config) { debugmsg(6, "freeing session process %p with config %p", process, process->config); /* Note: caller must free the config if appropriate to do so */ process->config->process = NULL; process->config = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -