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_ram...@dell.com> --- etc/iscsid.conf | 4 ++ usr/config.h | 1 + usr/idbm.c | 3 + usr/idbm_fields.h | 1 + usr/iscsi_util.c | 8 +++ usr/iscsi_util.h | 1 + usr/iscsiadm.c | 152 ++++++++++++++++++++++++++++++++++++++++++++-------- usr/session_mgmt.c | 47 ++++++++++++++-- usr/session_mgmt.h | 4 ++ 9 files changed, 192 insertions(+), 29 deletions(-) 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..49cf5aa 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@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,98 @@ 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 log into 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 fdb7357..5093849 100644 --- a/usr/session_mgmt.c +++ b/usr/session_mgmt.c @@ -222,19 +222,21 @@ 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, +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 *)) { @@ -259,13 +261,46 @@ 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..cd20714 100644 --- a/usr/session_mgmt.h +++ b/usr/session_mgmt.h @@ -12,6 +12,10 @@ extern 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 *)); +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); extern int iscsi_logout_portals(void *data, int *nr_found, int wait, -- 1.7.5.3 -- You received this message because you are subscribed to the Google Groups "open-iscsi" group. To post to this group, send email to open-iscsi@googlegroups.com. To unsubscribe from this group, send email to open-iscsi+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/open-iscsi?hl=en.