diff options
-rw-r--r-- | etc/iscsid.conf | 26 | ||||
-rw-r--r-- | usr/Makefile | 9 | ||||
-rw-r--r-- | usr/discoveryd.c | 203 | ||||
-rw-r--r-- | usr/discoveryd.h | 7 | ||||
-rw-r--r-- | usr/iface.c | 39 | ||||
-rw-r--r-- | usr/iface.h | 2 | ||||
-rw-r--r-- | usr/initiator.c | 7 | ||||
-rw-r--r-- | usr/iscsiadm.c | 22 | ||||
-rw-r--r-- | usr/iscsid.c | 47 | ||||
-rw-r--r-- | usr/session_mgmt.c | 10 | ||||
-rw-r--r-- | usr/session_mgmt.h | 2 |
11 files changed, 312 insertions, 62 deletions
diff --git a/etc/iscsid.conf b/etc/iscsid.conf index b0ac7c9..e3a13cb 100644 --- a/etc/iscsid.conf +++ b/etc/iscsid.conf @@ -29,6 +29,32 @@ # Default for upstream open-iscsi scripts (uncomment to activate). iscsid.startup = /sbin/iscsid +# If instead of doing discovery with iscsiadm and then logging +# into the targets stored in the node db, set the following value +# to have iscsid perform SendTargets discovery and log into all +# the portals found. +# +# This will use the ifaces that are set up when iscsid is started up. +# +# This value for this is a list of addresses and ports. The address and +# port should be separated by a comma. Each address port tuple should be +# separated by a space. The port is optional. If not set then the iSCSI +# default 3260 will be used. +# +# Example (first address has a port and the final two use the default 3260): +# discovery.daemon.sendtargets.addresses = 192.168.0.21,1234 192.168.1.20 192.168.10.10 +# +# By default iscsid will check the discovery addresses above every 30 +# seconds. To change this change the following value. poll_interval is +# in seconds, and 0 will instruct iscsid to not poll (will do discovery +# once then complete). +# +# discovery.daemon.sendtargets.poll_interval = 30 +# +# Note: This currently only logs into new portals. It does not +# log out of portals that are no longer returned from SendTargets. +# To remove them run "iscsiadm -m session -r $SID -u" + ############################# # NIC/HBA and driver settings diff --git a/usr/Makefile b/usr/Makefile index 166e717..4bde4be 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -45,13 +45,16 @@ INITIATOR_SRCS = initiator.o scsi.o actor.o event_poll.o mgmt_ipc.o isns.o \ # fw boot files FW_BOOT_SRCS = $(wildcard ../utils/fwparam_ibft/*.o) +# core discovery files +DISCOVERY_SRCS = $(FW_BOOT_SRCS) strings.o discovery.o + all: $(PROGRAMS) -iscsid: $(ISCSI_LIB_SRCS) $(IPC_OBJ) $(INITIATOR_SRCS) iscsid.o +iscsid: $(ISCSI_LIB_SRCS) $(IPC_OBJ) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \ + iscsid.o session_mgmt.o discoveryd.o $(CC) $(CFLAGS) $^ -o $@ -iscsiadm: $(ISCSI_LIB_SRCS) $(FW_BOOT_SRCS) strings.o discovery.o iscsiadm.o \ - session_mgmt.o +iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o $(CC) $(CFLAGS) $^ -o $@ iscsistart: $(IPC_OBJ) $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \ diff --git a/usr/discoveryd.c b/usr/discoveryd.c new file mode 100644 index 0000000..cae228b --- /dev/null +++ b/usr/discoveryd.c @@ -0,0 +1,203 @@ +/* + * iSCSI Initiator discovery daemon + * + * Copyright (C) 2010 Mike Christie + * Copyright (C) 2010 Red Hat, Inc. All rights reserved. + + * maintained by open-iscsi@googlegroups.com + * + * 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. + */ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "discovery.h" +#include "idbm.h" +#include "list.h" +#include "iscsi_proto.h" +#include "sysdeps.h" +#include "log.h" +#include "session_mgmt.h" +#include "util.h" +#include "event_poll.h" +#include "iface.h" + +#define DISC_ST_ADDR_CFG_STR "discovery.daemon.sendtargets.addresses" +#define DISC_ST_POLL_INVL "discovery.daemon.sendtargets.poll_interval" + +#define DISC_DEF_POLL_INVL 30 + +typedef void (do_disc_and_login_fn)(char *addr, int port); + +static int do_disc_to_addrs(char *disc_addrs, + do_disc_and_login_fn *do_disc_and_login) +{ + pid_t pid; + int nr_procs = 0, portn; + char *saveptr1, *saveptr2; + char *ip_str, *addr, *port_str; + + addr = strtok_r(disc_addrs, " ", &saveptr1); + if (!addr) + return 0; + + do { + ip_str = strtok_r(addr, ",", &saveptr2); + if (!ip_str) { + log_error("Invalid disc addr %s", addr); + continue; + } + + port_str = strtok_r(NULL, " ", &saveptr2); + if (!port_str) + portn = ISCSI_LISTEN_PORT; + else + portn = atoi(port_str); + + pid = fork(); + if (pid == 0) { + do_disc_and_login(ip_str, portn); + exit(0); + } else if (pid < 0) + log_error("Fork failed (err %d - %s). Will not be able " + "to perform discovery to %s.\n", + errno, strerror(errno), ip_str); + else { + log_debug(1, "iSCSI disc and login helper pid=%d", pid); + nr_procs++; + } + + + } while ((addr = strtok_r(NULL, " ", &saveptr1))); + + return nr_procs; +} + +static void discoveryd_start(char *addr_cfg_str, char *poll_cfg_str, + do_disc_and_login_fn *do_disc_and_login) +{ + char *disc_addrs, *disc_poll_param; + int disc_poll_invl = DISC_DEF_POLL_INVL; + pid_t pid; + + disc_addrs = cfg_get_string_param(CONFIG_FILE, addr_cfg_str); + if (!disc_addrs) + return; + free(disc_addrs); + + pid = fork(); + if (pid == 0) { + do { + /* check for updates */ + disc_addrs = cfg_get_string_param(CONFIG_FILE, + addr_cfg_str); + if (!disc_addrs) + continue; + + disc_poll_param = cfg_get_string_param(CONFIG_FILE, + poll_cfg_str); + if (disc_poll_param) { + disc_poll_invl = atoi(disc_poll_param); + free(disc_poll_param); + } + + log_debug(1, "%s=%s poll interval %d", addr_cfg_str, + disc_addrs, disc_poll_invl); + + do_disc_to_addrs(disc_addrs, do_disc_and_login); + free(disc_addrs); + + /* + * wait for the procs to complete, or we could + * end up flooding the targets with pdus. + */ + while ((pid = waitpid(0, NULL, 0)) > 0) + log_debug(7, "disc cleaned up pid %d", pid); + + if (!disc_poll_invl) + break; + } while (!sleep(disc_poll_invl)); + + log_debug(1, "disc process done"); + exit(0); + } else if (pid < 0) + log_error("Fork failed (err %d - %s). Will not be able " + "to perform discovery.\n", + errno, strerror(errno)); + else + need_reap(); + + log_debug(1, "iSCSI discovery daemon for %s pid=%d", + addr_cfg_str, pid); +} + +/* SendTargets */ +static void do_st_disc_and_login(char *disc_addr, int port) +{ + discovery_rec_t drec; + struct list_head rec_list, setup_ifaces; + int rc, nr_found; + struct node_rec *rec, *tmp_rec; + + INIT_LIST_HEAD(&rec_list); + INIT_LIST_HEAD(&setup_ifaces); + + idbm_sendtargets_defaults(&drec.u.sendtargets); + strlcpy(drec.address, disc_addr, sizeof(drec.address)); + drec.port = port; + + /* + * The disc daemon will try agin in poll_interval secs + * so no need to retry here + */ + drec.u.sendtargets.reopen_max = 0; + + iface_link_ifaces(&setup_ifaces); + /* + * disc code assumes this is not set and wants to use + * the userspace IO code. + */ + ipc = NULL; + + rc = idbm_bind_ifaces_to_nodes(discovery_sendtargets, &drec, + &setup_ifaces, &rec_list); + if (rc) { + log_error("Could not perform SendTargets to %s.", + disc_addr); + return; + } + + list_for_each_entry_safe(rec, tmp_rec, &rec_list, list) { + if (iscsi_check_for_running_session(rec)) { + list_del(&rec->list); + free(rec); + } + + /* no need to retry since the disc daemon will retry */ + rec->session.initial_login_retry_max = 0; + } + + iscsi_login_portals(NULL, &nr_found, &rec_list, iscsi_login_portal); +} + +void discoveryd_start_st(void) +{ + discoveryd_start(DISC_ST_ADDR_CFG_STR, DISC_ST_POLL_INVL, + do_st_disc_and_login); +} diff --git a/usr/discoveryd.h b/usr/discoveryd.h new file mode 100644 index 0000000..e68bd70 --- /dev/null +++ b/usr/discoveryd.h @@ -0,0 +1,7 @@ +#ifndef _DISC_DAEMON_H +#define _DISC_DAEMON_H + +extern void discoveryd_start_st(void); +extern void discoveryd_start_isns(void); + +#endif diff --git a/usr/iface.c b/usr/iface.c index e08946b..27b59d0 100644 --- a/usr/iface.c +++ b/usr/iface.c @@ -414,7 +414,7 @@ int iface_get_by_net_binding(struct iface_rec *pattern, search.pattern = pattern; search.found = out_rec; - rc = iface_for_each_iface(&search, &num_found, + rc = iface_for_each_iface(&search, 0, &num_found, __iface_get_by_net_binding); if (rc == 1) return 0; @@ -666,25 +666,29 @@ int iface_print_flat(void *data, struct iface_rec *iface) return 0; } -int iface_for_each_iface(void *data, int *nr_found, iface_op_fn *fn) +int iface_for_each_iface(void *data, int skip_def, int *nr_found, + iface_op_fn *fn) { DIR *iface_dirfd; struct dirent *iface_dent; struct iface_rec *iface, *def_iface; int err = 0, i = 0; - while ((def_iface = default_ifaces[i++])) { - iface = iface_alloc(def_iface->name, &err); - if (!iface) { - log_error("Could not add iface %s.", def_iface->name); - continue; + if (!skip_def) { + while ((def_iface = default_ifaces[i++])) { + iface = iface_alloc(def_iface->name, &err); + if (!iface) { + log_error("Could not add iface %s.", + def_iface->name); + continue; + } + iface_copy(iface, def_iface); + err = fn(data, iface); + free(iface); + if (err) + return err; + (*nr_found)++; } - iface_copy(iface, def_iface); - err = fn(data, iface); - free(iface); - if (err) - return err; - (*nr_found)++; } iface_dirfd = opendir(IFACE_CONFIG_DIR); @@ -760,11 +764,18 @@ static int iface_link(void *data, struct iface_rec *iface) return 0; } +/** + * iface_link_ifaces - link non default ifaces + * @ifaces: list to add ifaces to + * + * This will return a list of the ifaces created by iscsiadm + * or the user. It does not return the static default ones. + */ void iface_link_ifaces(struct list_head *ifaces) { int nr_found = 0; - iface_for_each_iface(ifaces, &nr_found, iface_link); + iface_for_each_iface(ifaces, 1, &nr_found, iface_link); } void iface_setup_from_boot_context(struct iface_rec *iface, diff --git a/usr/iface.h b/usr/iface.h index 401f3cc..f948686 100644 --- a/usr/iface.h +++ b/usr/iface.h @@ -36,7 +36,7 @@ extern int iface_is_bound_by_hwaddr(struct iface_rec *iface); extern int iface_is_bound_by_netdev(struct iface_rec *iface); extern int iface_is_bound_by_ipaddr(struct iface_rec *iface); typedef int (iface_op_fn)(void *data, struct iface_rec *iface); -extern int iface_for_each_iface(void *data, int *nr_found, +extern int iface_for_each_iface(void *data, int skip_def, int *nr_found, iface_op_fn *fn); extern void iface_print(struct iface_rec *iface, char *prefix); extern int iface_print_flat(void *data, struct iface_rec *iface); diff --git a/usr/initiator.c b/usr/initiator.c index 2dbfb7f..f8df8e6 100644 --- a/usr/initiator.c +++ b/usr/initiator.c @@ -2075,7 +2075,7 @@ static iscsi_session_t* session_find_by_rec(node_rec_t *rec) * a session could be running in the kernel but not in iscsid * due to a resync or becuase some other app started the session */ -int session_is_running(node_rec_t *rec) +static int session_is_running(node_rec_t *rec) { int nr_found = 0; @@ -2139,11 +2139,8 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask) iscsi_conn_t *conn; struct iscsi_transport *t; - if (session_is_running(rec)) { - log_error("session [%s,%s,%d] already running.", rec->name, - rec->conn[0].address, rec->conn[0].port); + if (session_is_running(rec)) return MGMT_IPC_ERR_EXISTS; - } t = iscsi_sysfs_get_transport_by_name(rec->iface.transport_name); if (!t) diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c index 5c171f9..3a141f5 100644 --- a/usr/iscsiadm.c +++ b/usr/iscsiadm.c @@ -225,7 +225,7 @@ static int print_ifaces(struct iface_rec *iface, int info_level) switch (info_level) { case 0: case -1: - err = iface_for_each_iface(NULL, &num_found, + err = iface_for_each_iface(NULL, 0, &num_found, iface_print_flat); break; case 1: @@ -239,7 +239,7 @@ static int print_ifaces(struct iface_rec *iface, int info_level) iface_print_tree(NULL, iface); num_found = 1; } else - err = iface_for_each_iface(NULL, &num_found, + err = iface_for_each_iface(NULL, 0, &num_found, iface_print_tree); break; default: @@ -788,19 +788,9 @@ do_offload_sendtargets(discovery_rec_t *drec, int host_no, int do_login) return discovery_offload_sendtargets(host_no, do_login, drec); } -/* TODO merge with initiator.c implementation */ -/* And add locking */ -static int check_for_session_through_iface(struct node_rec *rec) -{ - int nr_found = 0; - if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session)) - return 1; - return 0; -} - static int delete_node(void *data, struct node_rec *rec) { - if (check_for_session_through_iface(rec)) { + if (iscsi_check_for_running_session(rec)) { /* * We could log out the session for the user, but if * the session is being used the user may get something @@ -1069,7 +1059,7 @@ static int exec_iface_op(int op, int do_show, int info_level, } rec = idbm_create_rec(NULL, -1, NULL, -1, iface, 0); - if (rec && check_for_session_through_iface(rec)) { + if (rec && iscsi_check_for_running_session(rec)) { rc = EBUSY; goto new_fail; } @@ -1125,7 +1115,7 @@ delete_fail: goto update_fail; } - if (check_for_session_through_iface(rec)) + if (iscsi_check_for_running_session(rec)) log_warning("Updating iface while iscsi sessions " "are using it. You must logout the running " "sessions then log back in for the " @@ -1298,7 +1288,7 @@ static int exec_node_op(int op, int do_login, int do_logout, * and we can mark stable. */ if (!strcmp(name, "iface.transport_name")) { - if (check_for_session_through_iface(rec)) { + if (iscsi_check_for_running_session(rec)) { log_warning("Cannot modify node/iface " "transport name while a session " "is using it. Log out the session " diff --git a/usr/iscsid.c b/usr/iscsid.c index fce0c59..c939119 100644 --- a/usr/iscsid.c +++ b/usr/iscsid.c @@ -29,6 +29,8 @@ #include <signal.h> #include <sys/mman.h> #include <sys/utsname.h> +#include <sys/types.h> +#include <sys/wait.h> #include "iscsid.h" #include "mgmt_ipc.h" @@ -44,6 +46,7 @@ #include "iface.h" #include "session_info.h" #include "sysdeps.h" +#include "discoveryd.h" /* global config info */ struct iscsi_daemon_config daemon_config; @@ -52,6 +55,7 @@ struct iscsi_daemon_config *dconfig = &daemon_config; static char program_name[] = "iscsid"; int control_fd, mgmt_ipc_fd; static pid_t log_pid; +static gid_t gid; static struct option const long_options[] = { {"config", required_argument, NULL, 'c'}, @@ -279,36 +283,28 @@ static char *iscsid_get_config_file(void) return daemon_config.config_file; } -static void iscsid_exit(void) -{ - isns_exit(); - ipc->ctldev_close(); - mgmt_ipc_close(mgmt_ipc_fd); - if (daemon_config.initiator_name) - free(daemon_config.initiator_name); - if (daemon_config.initiator_alias) - free(daemon_config.initiator_alias); - free_initiator(); -} - static void iscsid_shutdown(void) { + pid_t pid; + + killpg(gid, SIGTERM); + while ((pid = waitpid(0, NULL, 0) > 0)) + log_debug(7, "cleaned up pid %d", pid); + log_warning("iscsid shutting down."); if (log_daemon && log_pid >= 0) { log_debug(1, "daemon stopping"); log_close(log_pid); - fprintf(stderr, "done done\n"); } - exit(0); } static void catch_signal(int signo) { log_debug(1, "%d caught signal -%d...", signo, getpid()); - switch (signo) { case SIGTERM: iscsid_shutdown(); + exit(0); break; default: break; @@ -338,7 +334,6 @@ int main(int argc, char *argv[]) int ch, longindex; int isns_fd; uid_t uid = 0; - gid_t gid = 0; struct sigaction sa_old; struct sigaction sa_new; pid_t pid; @@ -410,11 +405,6 @@ int main(int argc, char *argv[]) control_fd = -1; daemon_config.initiator_name = NULL; daemon_config.initiator_alias = NULL; - if (atexit(iscsid_exit)) { - log_error("failed to set exit function\n"); - log_close(log_pid); - exit(1); - } if ((mgmt_ipc_fd = mgmt_ipc_listen()) < 0) { log_close(log_pid); @@ -506,6 +496,9 @@ int main(int argc, char *argv[]) } else need_reap(); + increase_max_files(); + discoveryd_start_st(); + /* oom-killer will not kill us at the night... */ if (oom_adjust()) log_debug(1, "can not adjust oom-killer's pardon"); @@ -517,12 +510,20 @@ int main(int argc, char *argv[]) exit(1); } - increase_max_files(); actor_init(); isns_fd = isns_init(); event_loop(ipc, control_fd, mgmt_ipc_fd, isns_fd); - iscsid_shutdown(); + idbm_terminate(); sysfs_cleanup(); + isns_exit(); + ipc->ctldev_close(); + mgmt_ipc_close(mgmt_ipc_fd); + if (daemon_config.initiator_name) + free(daemon_config.initiator_name); + if (daemon_config.initiator_alias) + free(daemon_config.initiator_alias); + free_initiator(); + iscsid_shutdown(); return 0; } diff --git a/usr/session_mgmt.c b/usr/session_mgmt.c index c22d730..547e7eb 100644 --- a/usr/session_mgmt.c +++ b/usr/session_mgmt.c @@ -299,3 +299,13 @@ int iscsi_logout_portals(void *data, int *nr_found, session_info_free_list(&session_list); return ret; } + +/* TODO merge with initiator.c implementation */ +/* And add locking */ +int iscsi_check_for_running_session(struct node_rec *rec) +{ + int nr_found = 0; + if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session)) + return 1; + return 0; +} diff --git a/usr/session_mgmt.h b/usr/session_mgmt.h index a101175..c310d49 100644 --- a/usr/session_mgmt.h +++ b/usr/session_mgmt.h @@ -16,4 +16,6 @@ extern int iscsi_logout_portal(struct session_info *info, extern int iscsi_logout_portals(void *data, int *nr_found, int (*logout_fn)(void *, struct list_head *, struct session_info *)); +extern int iscsi_check_for_running_session(struct node_rec *rec); + #endif |