[Pkg-iscsi-maintainers] [SCM] Debian Open-iSCSI Packaging branch, upstream-mnc, updated. 2.0-872-193-gde2c0e7

Mike Christie michaelc at cs.wisc.edu
Sat Apr 7 15:43:35 UTC 2012


The following commit has been merged in the upstream-mnc branch:
commit ec7d7431c8ec19d6c17c2e0fe3aec47fdfc12796
Author: Jim Ramsay <jim_ramsay at dell.com>
Date:   Fri Jul 1 11:55:08 2011 -0400

    Implement leading-login support
    
    Leading-login only takes effect when performing "login-by-startup" (ie,
    iscsiadm -m node -L ...).  For any nodes with the new
    'node.leading_login' config value set to "Yes" (The default is "No"), a
    login attempt will be made on each successive iface record until one
    succeeds.
    
    The intent is to only have a single iSCSI session for each configured
    target at startup but also allow for fallthrough to alternate ifaces in
    case of network issues.
    
    Signed-off-by: Jim Ramsay <jim_ramsay at dell.com>

diff --git a/etc/iscsid.conf b/etc/iscsid.conf
index 4e8c08d..ef76dc0 100644
--- a/etc/iscsid.conf
+++ b/etc/iscsid.conf
@@ -39,6 +39,10 @@ iscsid.startup = /sbin/iscsid
 # To manually startup the session set to "manual". The default is manual.
 node.startup = manual
 
+# For "automatic" startup nodes, setting this to "Yes" will try logins on each
+# available iface until one succeeds, and then stop.  The default "No" will try
+# logins on all availble ifaces simultaneously.
+node.leading_login = No
 
 # *************
 # CHAP Settings
diff --git a/usr/config.h b/usr/config.h
index 1736382..0d475c2 100644
--- a/usr/config.h
+++ b/usr/config.h
@@ -231,6 +231,7 @@ typedef struct node_rec {
 	char			name[TARGET_NAME_MAXLEN];
 	int			tpgt;
 	iscsi_startup_e		startup;
+	int			leading_login;
 	session_rec_t		session;
 	conn_rec_t		conn[ISCSI_CONN_MAX];
 	iface_rec_t		iface;
diff --git a/usr/idbm.c b/usr/idbm.c
index 93b5882..cca32e2 100644
--- a/usr/idbm.c
+++ b/usr/idbm.c
@@ -209,6 +209,8 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri)
 	__recinfo_int(NODE_TPGT, ri, r, tpgt, IDBM_SHOW, num, 0);
 	__recinfo_int_o3(NODE_STARTUP, ri, r, startup,
 			IDBM_SHOW, "manual", "automatic", "onboot", num, 1);
+	__recinfo_int_o2(NODE_LEADING_LOGIN, ri, r, leading_login, IDBM_SHOW,
+			 "No", "Yes", num, 1);
 	/*
 	 * Note: because we do not add the iface.iscsi_ifacename to
 	 * sysfs iscsiadm does some weird matching. We can change the iface
@@ -2400,6 +2402,7 @@ void idbm_node_setup_defaults(node_rec_t *rec)
 
 	rec->tpgt = PORTAL_GROUP_TAG_UNKNOWN;
 	rec->disc_type = DISCOVERY_TYPE_STATIC;
+	rec->leading_login = 0;
 	rec->session.cmds_max = CMDS_MAX;
 	rec->session.xmit_thread_priority = XMIT_THREAD_PRIORITY;
 	rec->session.initial_cmdsn = 0;
diff --git a/usr/idbm_fields.h b/usr/idbm_fields.h
index 824a7a9..904ccdc 100644
--- a/usr/idbm_fields.h
+++ b/usr/idbm_fields.h
@@ -10,6 +10,7 @@
 #define NODE_NAME	"node.name"
 #define NODE_TPGT	"node.tpgt"
 #define NODE_STARTUP	"node.startup"
+#define NODE_LEADING_LOGIN "node.leading_login"
 #define NODE_DISC_ADDR	"node.discovery_address"
 #define NODE_DISC_PORT	"node.discovery_port"
 #define NODE_DISC_TYPE	"node.discovery_type"
diff --git a/usr/iscsi_util.c b/usr/iscsi_util.c
index 9502d37..293ec54 100644
--- a/usr/iscsi_util.c
+++ b/usr/iscsi_util.c
@@ -344,3 +344,11 @@ int iscsi_match_session_count(void *data, struct session_info *info)
 		return 0;
 	return -1;
 }
+
+int iscsi_match_target(void *data, struct session_info *info)
+{
+	return __iscsi_match_session(data, info->targetname,
+				     info->persistent_address,
+				     info->persistent_port, NULL,
+				     MATCH_ANY_SID);
+}
diff --git a/usr/iscsi_util.h b/usr/iscsi_util.h
index 13a5eb2..110dfa8 100644
--- a/usr/iscsi_util.h
+++ b/usr/iscsi_util.h
@@ -14,6 +14,7 @@ extern int increase_max_files(void);
 extern char *str_to_ipport(char *str, int *port, int *tgpt);
 
 extern int iscsi_match_session(void *data, struct session_info *info);
+extern int iscsi_match_target(void *data, struct session_info *info);
 extern int iscsi_match_session_count(void *data, struct session_info *info);
 extern int __iscsi_match_session(struct node_rec *rec, char *targetname,
 				 char *address, int port,
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index f2f0281..91d886b 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
  * Copyright (C) 2006 Mike Christie
  * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2011 Dell Inc.
  * maintained by open-iscsi at googlegroups.com
  *
  * This program is free software; you can redistribute it and/or modify
@@ -379,18 +380,54 @@ logout_by_startup(char *mode)
 	return rc; 
 }
 
-/*
- * TODO: merged this and logout into the common for_each_matched_rec by making
- * the matching more generic
- */
+struct startup_data {
+	char *mode;
+	struct list_head all_logins;
+	struct list_head leading_logins;
+};
+
+static int link_startup_recs(void *data, struct node_rec *rec)
+{
+	struct startup_data *startup = data;
+	struct node_rec *rec_copy;
+
+	if (match_startup_mode(rec, startup->mode))
+		return -1;
+
+	rec_copy = calloc(1, sizeof(*rec_copy));
+	if (!rec_copy)
+		return ISCSI_ERR_NOMEM;
+	memcpy(rec_copy, rec, sizeof(*rec_copy));
+	INIT_LIST_HEAD(&rec_copy->list);
+
+	if (rec_copy->leading_login)
+		list_add_tail(&rec_copy->list, &startup->leading_logins);
+	else
+		list_add_tail(&rec_copy->list, &startup->all_logins);
+	return 0;
+}
+
 static int
-__login_by_startup(void *data, struct list_head *list, struct node_rec *rec)
+__do_leading_login(void *data, struct list_head *list, struct node_rec *rec)
 {
-	char *mode = data;
+	struct iface_rec *pattern_iface = data;
+	int nr_found;
+
+	/* Skip any records that do not match the pattern iface */
+	if (!iface_match(pattern_iface, &rec->iface))
+		return -1;
 
-	if (match_startup_mode(rec, mode))
+	/*
+	 * If there is an existing session that matcthes the target,
+	 * the leading login is complete.
+	 */
+	if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_target)) {
+		log_debug(1, "Skipping %s: Already a session for that target",
+			  rec->name);
 		return -1;
+	}
 
+	/* No existing session: Attempt a login. */
 	return iscsi_login_portal(NULL, list, rec);
 }
 
@@ -398,7 +435,7 @@ static int
 login_by_startup(char *mode)
 {
 	int nr_found = 0, err, rc;
-	struct list_head rec_list;
+	struct startup_data startup;
 
 	if (!mode || !(!strcmp(mode, "automatic") || !strcmp(mode, "all") ||
 		       !strcmp(mode,"manual") || !strcmp(mode, "onboot"))) {
@@ -407,29 +444,99 @@ login_by_startup(char *mode)
 		return ISCSI_ERR_INVAL;
 	}
 
-	INIT_LIST_HEAD(&rec_list);
-	err = idbm_for_each_rec(&nr_found, &rec_list, link_recs);
-	if (err && !list_empty(&rec_list))
+	/*
+	 * Filter all node records that match the given 'mode' into 2 lists:
+	 * Those with leading_login enabled, and those without.
+	 */
+	startup.mode = mode;
+	INIT_LIST_HEAD(&startup.all_logins);
+	INIT_LIST_HEAD(&startup.leading_logins);
+	err = idbm_for_each_rec(&nr_found, &startup, link_startup_recs);
+	if (err && (!list_empty(&startup.all_logins) ||
+		    !list_empty(&startup.leading_logins)))
 		/* log msg and try to log into what we found */
 		log_error("Could not read all records: %s",
 			  iscsi_err_to_str(err));
-	else if (err && list_empty(&rec_list)) {
-		log_error("Could not read node DB: %s.",
-			  iscsi_err_to_str(err));
+	else if (list_empty(&startup.all_logins) &&
+		 list_empty(&startup.leading_logins)) {
+		if (err) {
+			log_error("Could not read node DB: %s.",
+				  iscsi_err_to_str(err));
+		} else {
+			log_error("No records found");
+			err = ISCSI_ERR_NO_OBJS_FOUND;
+		}
 		return err;
-	} else if (list_empty(&rec_list)) {
-		log_error("No records found");
-		return ISCSI_ERR_NO_OBJS_FOUND;
 	}
 	rc = err;
 
-	err = iscsi_login_portals(mode, &nr_found, 1, &rec_list,
-				  __login_by_startup);
-	if (err)
-		log_error("Could not log into all portals");
+	if (!list_empty(&startup.all_logins)) {
+		log_debug(1, "Logging into normal (non-leading-login) portals");
+		/* Login all regular (non-leading-login) portals first */
+		err = iscsi_login_portals(NULL, &nr_found, 1,
+				&startup.all_logins, iscsi_login_portal);
+		if (err)
+			log_error("Could not log into all portals");
+		if (err && !rc)
+			rc = err;
+	}
+
+	if (!list_empty(&startup.leading_logins)) {
+		/*
+		 * For each iface in turn, try to login all portals on that
+		 * iface that do not already have a session present.
+		 */
+		struct iface_rec *pattern_iface, *tmp_iface;
+		struct node_rec *rec, *tmp_rec;
+		struct list_head iface_list;
+		int missed_leading_login = 0;
+		log_debug(1, "Logging into leading-login portals");
+		INIT_LIST_HEAD(&iface_list);
+		iface_link_ifaces(&iface_list);
+		list_for_each_entry_safe(pattern_iface, tmp_iface, &iface_list,
+					 list) {
+			log_debug(1, "Establishing leading-logins via iface %s",
+				  pattern_iface->name);
+			err = iscsi_login_portals_safe(pattern_iface, &nr_found,
+						       1,
+						       &startup.leading_logins,
+						       __do_leading_login);
+			if (err)
+				log_error("Could not log into all portals on "
+					  "%s, trying next interface",
+					  pattern_iface->name);
+
+			/*
+			 * Note: We always try all iface records in case there
+			 * are targets that are associated with only a subset
+			 * of iface records.  __do_leading_login already
+			 * prevents duplicate sessions if an iface has succeded
+			 * for a particular target.
+			 */
+		}
+		/*
+		 * Double-check that all leading-login portals have at least
+		 * one session
+		 */
+		list_for_each_entry_safe(rec, tmp_rec, &startup.leading_logins,
+					 list) {
+			if (!iscsi_sysfs_for_each_session(rec, &nr_found,
+							  iscsi_match_target))
+				missed_leading_login++;
+			/*
+			 * Cleanup the list, since 'iscsi_login_portals_safe'
+			 * does not
+			 */
+			list_del(&rec->list);
+			free(rec);
+		}
+		if (missed_leading_login) {
+			log_error("Could not login all leading-login portals");
+			if (!rc)
+				rc = ISCSI_ERR_FATAL_LOGIN;
+		}
+	}
 
-	if (err && !rc)
-		rc = err;
 	return rc;
 }
 
diff --git a/usr/session_mgmt.c b/usr/session_mgmt.c
index 7918954..914471c 100644
--- a/usr/session_mgmt.c
+++ b/usr/session_mgmt.c
@@ -225,20 +225,22 @@ int iscsi_login_portal_nowait(struct node_rec *rec)
 }
 
 /**
- * iscsi_login_portals - login into portals on @rec_list,
+ * __iscsi_login_portals - login into portals on @rec_list,
  * @data: data to pass to login_fn
  * @nr_found: returned with number of portals logged into
  * @wait: bool indicating if the fn should wait for the result
  * @rec_list: list of portals to log into
+ * @clear_list: If set, delete and free rec_list after iterating through.
  * @login_fn: list iter function
  *
  * This will loop over the list of portals and login. It
  * will attempt to login asynchronously, and then wait for
  * them to complete if wait is set.
  */
-int iscsi_login_portals(void *data, int *nr_found, int wait,
-			struct list_head *rec_list,
-			int (* login_fn)(void *, struct list_head *,
+static
+int __iscsi_login_portals(void *data, int *nr_found, int wait,
+			struct list_head *rec_list, int clear_list,
+			int (*login_fn)(void *, struct list_head *,
 					 struct node_rec *))
 {
 	struct node_rec *curr_rec, *tmp;
@@ -262,13 +264,50 @@ int iscsi_login_portals(void *data, int *nr_found, int wait,
 	} else
 		iscsid_reqs_close(&login_list);
 
-	list_for_each_entry_safe(curr_rec, tmp, rec_list, list) {
-		list_del(&curr_rec->list);
-		free(curr_rec);
+	if (clear_list) {
+		list_for_each_entry_safe(curr_rec, tmp, rec_list, list) {
+			list_del(&curr_rec->list);
+			free(curr_rec);
+		}
 	}
 	return ret;
 }
 
+/**
+ * iscsi_login_portals - login into portals on @rec_list,
+ * @data: data to pass to login_fn
+ * @nr_found: returned with number of portals logged into
+ * @wait: bool indicating if the fn should wait for the result
+ * @rec_list: list of portals to log into.  This list is deleted after
+ *            iterating through it.
+ * @login_fn: list iter function
+ *
+ * This will loop over the list of portals and login. It
+ * will attempt to login asynchronously, and then wait for
+ * them to complete if wait is set.
+ */
+int iscsi_login_portals(void *data, int *nr_found, int wait,
+			struct list_head *rec_list,
+			int (*login_fn)(void *, struct list_head *,
+					 struct node_rec *))
+{
+	return __iscsi_login_portals(data, nr_found, wait, rec_list,
+				     1, login_fn);
+}
+
+/**
+ * iscsi_login_portals_safe - login into portals on @rec_list, but do not
+ *			      clear out rec_list.
+ */
+int iscsi_login_portals_safe(void *data, int *nr_found, int wait,
+			struct list_head *rec_list,
+			int (*login_fn)(void *, struct list_head *,
+					 struct node_rec *))
+{
+	return __iscsi_login_portals(data, nr_found, wait, rec_list,
+				     0, login_fn);
+}
+
 static void log_logout_msg(struct session_info *info, int rc)
 {
 	if (rc) {
diff --git a/usr/session_mgmt.h b/usr/session_mgmt.h
index b800fd7..a28bfa4 100644
--- a/usr/session_mgmt.h
+++ b/usr/session_mgmt.h
@@ -10,7 +10,11 @@ extern int iscsi_login_portal(void *data, struct list_head *list,
 extern int iscsi_login_portal_nowait(struct node_rec *rec);
 extern int iscsi_login_portals(void *data, int *nr_found, int wait,
 			       struct list_head *rec_list,
-			       int (* login_fn)(void *, struct list_head *,
+			       int (*login_fn)(void *, struct list_head *,
+						struct node_rec *));
+extern int iscsi_login_portals_safe(void *data, int *nr_found, int wait,
+			       struct list_head *rec_list,
+			       int (*login_fn)(void *, struct list_head *,
 						struct node_rec *));
 extern int iscsi_logout_portal(struct session_info *info,
 			       struct list_head *list);

-- 
Debian Open-iSCSI Packaging



More information about the Pkg-iscsi-maintainers mailing list