summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--etc/iscsid.conf26
-rw-r--r--usr/Makefile9
-rw-r--r--usr/discoveryd.c203
-rw-r--r--usr/discoveryd.h7
-rw-r--r--usr/iface.c39
-rw-r--r--usr/iface.h2
-rw-r--r--usr/initiator.c7
-rw-r--r--usr/iscsiadm.c22
-rw-r--r--usr/iscsid.c47
-rw-r--r--usr/session_mgmt.c10
-rw-r--r--usr/session_mgmt.h2
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