summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2010-01-27 16:12:05 -0600
committerMike Christie <michaelc@cs.wisc.edu>2010-03-22 17:32:06 -0500
commit8c24522b2ce48136d4eac0d1137685327bd3a212 (patch)
treeea17a38648a0a0dc017128db983a35d1291e4cf9
parentd984c57aa084698488911d8a2ca94314666f685e (diff)
downloadopen-iscsi-8c24522b2ce48136d4eac0d1137685327bd3a212.tar.gz
iscsid: have iscsid watch for new portals using sendtargets
This patch has iscsid do SendTargets to the addresses pointed to discovery.daemon.sendtargets.addresses iscsid.conf. It will do it every discovery.daemon.sendtargets.poll_interval seconds. This is useful for setups where the target returns only the valid portals and you want to log into all the portals returned. If the target returns all portals, then this still works, but it is a little loud when a login fails. Notes: - It will use the ifaces setup in /etc/iscsi/ifaces. - For iscsi settings it will use the /etc/iscsi/iscsid.conf settings. - It currently only logs into new targets. It does not remove old ones. You have to run iscsiadm -m session -r $SID -u to remove stale sessions. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
-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