summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2010-01-18 22:12:03 -0600
committerMike Christie <michaelc@cs.wisc.edu>2010-03-22 17:32:06 -0500
commit38030899b5fda60fc853b6319c85ac59d9910b3a (patch)
tree6aee11708aa6737a2bc6ed5e602143d35019b0de
parent213c88562f68875bad2c9cbdf74d869e5a57c295 (diff)
downloadopen-iscsi-38030899b5fda60fc853b6319c85ac59d9910b3a.tar.gz
iscsiadm: mv session management functions to new file
This mvs the session management functions to a new file so they can be used by the discovery daemons. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
-rw-r--r--etc/iscsid.conf1
-rw-r--r--usr/Makefile3
-rw-r--r--usr/idbm.h1
-rw-r--r--usr/iscsiadm.c341
-rw-r--r--usr/session_mgmt.c301
-rw-r--r--usr/session_mgmt.h19
6 files changed, 370 insertions, 296 deletions
diff --git a/etc/iscsid.conf b/etc/iscsid.conf
index e8b62f0..b0ac7c9 100644
--- a/etc/iscsid.conf
+++ b/etc/iscsid.conf
@@ -46,6 +46,7 @@ iscsid.startup = /sbin/iscsid
# To manually startup the session set to "manual". The default is manual.
node.startup = manual
+
# *************
# CHAP Settings
# *************
diff --git a/usr/Makefile b/usr/Makefile
index 1caf4f1..166e717 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -50,7 +50,8 @@ all: $(PROGRAMS)
iscsid: $(ISCSI_LIB_SRCS) $(IPC_OBJ) $(INITIATOR_SRCS) iscsid.o
$(CC) $(CFLAGS) $^ -o $@
-iscsiadm: $(ISCSI_LIB_SRCS) $(FW_BOOT_SRCS) strings.o discovery.o iscsiadm.o
+iscsiadm: $(ISCSI_LIB_SRCS) $(FW_BOOT_SRCS) strings.o discovery.o iscsiadm.o \
+ session_mgmt.o
$(CC) $(CFLAGS) $^ -o $@
iscsistart: $(IPC_OBJ) $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \
diff --git a/usr/idbm.h b/usr/idbm.h
index 51946c7..f390315 100644
--- a/usr/idbm.h
+++ b/usr/idbm.h
@@ -22,6 +22,7 @@
#ifndef IDBM_H
#define IDBM_H
+#include <stdio.h>
#include <sys/types.h>
#include "initiator.h"
#include "config.h"
diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c
index 75cd520..5c171f9 100644
--- a/usr/iscsiadm.c
+++ b/usr/iscsiadm.c
@@ -45,6 +45,7 @@
#include "host.h"
#include "sysdeps.h"
#include "idbm_fields.h"
+#include "session_mgmt.h"
struct iscsi_ipc *ipc = NULL; /* dummy */
static char program_name[] = "iscsiadm";
@@ -281,80 +282,6 @@ match_startup_mode(node_rec_t *rec, char *mode)
return -1;
}
-static void log_login_msg(struct node_rec *rec, int rc)
-{
- if (rc) {
- log_error("Could not login to [iface: %s, target: %s, "
- "portal: %s,%d].", rec->iface.name,
- rec->name, rec->conn[0].address,
- rec->conn[0].port);
- iscsid_handle_error(rc);
- } else
- printf("Login to [iface: %s, target: %s, portal: "
- "%s,%d] successful.\n", rec->iface.name,
- rec->name, rec->conn[0].address,
- rec->conn[0].port);
-}
-
-struct iscsid_async_req {
- struct list_head list;
- void *data;
- int fd;
-};
-
-static int iscsid_login_reqs_wait(struct list_head *list)
-{
- struct iscsid_async_req *tmp, *curr;
- struct node_rec *rec;
- int ret = 0;
-
- list_for_each_entry_safe(curr, tmp, list, list) {
- int err;
-
- rec = curr->data;
- err = iscsid_req_wait(MGMT_IPC_SESSION_LOGIN, curr->fd);
- log_login_msg(rec, err);
- list_del(&curr->list);
- free(curr);
- }
- return ret;
-}
-
-static void log_logout_msg(struct session_info *info, int rc)
-{
- if (rc) {
- log_error("Could not logout of [sid: %d, target: %s, "
- "portal: %s,%d].", info->sid,
- info->targetname,
- info->persistent_address, info->port);
- iscsid_handle_error(rc);
- } else
- printf("Logout of [sid: %d, target: %s, "
- "portal: %s,%d] successful.\n",
- info->sid, info->targetname,
- info->persistent_address, info->port);
-}
-
-static int iscsid_logout_reqs_wait(struct list_head *list)
-{
- struct iscsid_async_req *tmp, *curr;
- struct session_info *info;
- int ret = 0;
-
- list_for_each_entry_safe(curr, tmp, list, list) {
- int err;
-
- info = curr->data;
- err = iscsid_req_wait(MGMT_IPC_SESSION_LOGOUT, curr->fd);
- log_logout_msg(info, err);
- if (err)
- ret = err;
- list_del(&curr->list);
- free(curr);
- }
- return ret;
-}
-
static int
for_each_session(struct node_rec *rec, iscsi_sysfs_session_op_fn *fn)
{
@@ -386,90 +313,6 @@ static int link_recs(void *data, struct node_rec *rec)
return 0;
}
-static int __logout_portal(struct session_info *info, struct list_head *list)
-{
- struct iscsid_async_req *async_req = NULL;
- int fd, rc;
-
- /* TODO: add fn to add session prefix info like dev_printk */
- printf("Logging out of session [sid: %d, target: %s, portal: %s,%d]\n",
- info->sid, info->targetname, info->persistent_address,
- info->port);
-
- async_req = calloc(1, sizeof(*async_req));
- if (!async_req) {
- log_error("Could not allocate memory for async logout "
- "handling. Using sequential logout instead.");
- rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid);
- } else {
- INIT_LIST_HEAD(&async_req->list);
- rc = iscsid_req_by_sid_async(MGMT_IPC_SESSION_LOGOUT,
- info->sid, &fd);
- }
-
- /* we raced with another app or instance of iscsiadm */
- if (rc) {
- log_logout_msg(info, rc);
- if (async_req)
- free(async_req);
-
- if (rc == MGMT_IPC_ERR_NOT_FOUND)
- return 0;
-
- return EIO;
- }
-
- if (async_req) {
- list_add_tail(&async_req->list, list);
- async_req->fd = fd;
- async_req->data = info;
- } else
- log_logout_msg(info, rc);
-
- return 0;
-}
-
-static int
-__logout_portals(void *data, int *nr_found,
- int (*logout_fn)(void *, struct list_head *,
- struct session_info *))
-{
- struct session_info *curr_info;
- struct session_link_info link_info;
- struct list_head session_list, logout_list;
- int ret = 0, err;
-
- INIT_LIST_HEAD(&session_list);
- INIT_LIST_HEAD(&logout_list);
-
- memset(&link_info, 0, sizeof(link_info));
- link_info.list = &session_list;
- link_info.data = NULL;
- link_info.match_fn = NULL;
- *nr_found = 0;
-
- err = iscsi_sysfs_for_each_session(&link_info, nr_found,
- session_info_create_list);
- if (err || !*nr_found)
- return err;
-
- *nr_found = 0;
- list_for_each_entry(curr_info, &session_list, list) {
- err = logout_fn(data, &logout_list, curr_info);
- if (err > 0 && !ret)
- ret = err;
- if (!err)
- (*nr_found)++;
- }
-
- err = iscsid_logout_reqs_wait(&logout_list);
- if (err)
- ret = err;
-
- session_info_free_list(&session_list);
- return ret;
-}
-
static int
__logout_by_startup(void *data, struct list_head *list,
struct session_info *info)
@@ -503,7 +346,7 @@ __logout_by_startup(void *data, struct list_head *list,
return -1;
if (!match_startup_mode(&rec, mode))
- rc = __logout_portal(info, list);
+ rc = iscsi_logout_portal(info, list);
return rc;
}
@@ -519,116 +362,7 @@ logout_by_startup(char *mode)
return EINVAL;
}
- return __logout_portals(mode, &nr_found, __logout_by_startup);
-}
-
-static int
-logout_portal(void *data, struct list_head *list, struct session_info *info)
-{
- struct node_rec *pattern_rec = data;
- struct iscsi_transport *t;
-
- t = iscsi_sysfs_get_transport_by_sid(info->sid);
- if (!t)
- return -1;
-
- if (!iscsi_match_session(pattern_rec, info))
- return -1;
-
- /* we do not support this yet */
- if (t->caps & CAP_FW_DB) {
- log_error("Could not logout session of [sid: %d, "
- "target: %s, portal: %s,%d].", info->sid,
- info->targetname, info->persistent_address,
- info->port);
- log_error("Logout not supported for driver: %s.", t->name);
- return -1;
- }
- return __logout_portal(info, list);
-}
-
-static int logout_portals(struct node_rec *pattern_rec)
-{
- int nr_found;
-
- return __logout_portals(pattern_rec, &nr_found, logout_portal);
-}
-
-static int login_portal(void *data, struct list_head *list,
- struct node_rec *rec)
-{
- struct iscsid_async_req *async_req = NULL;
- int rc = 0, fd;
-
- printf("Logging in to [iface: %s, target: %s, portal: %s,%d]\n",
- rec->iface.name, rec->name, rec->conn[0].address,
- rec->conn[0].port);
-
- if (list) {
- async_req = calloc(1, sizeof(*async_req));
- if (!async_req)
- log_error("Could not allocate memory for async login "
- "handling. Using sequential login instead.");
- else
- INIT_LIST_HEAD(&async_req->list);
- }
-
- if (async_req)
- rc = iscsid_req_by_rec_async(MGMT_IPC_SESSION_LOGIN,
- rec, &fd);
- else
- rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec);
-
- if (rc) {
- log_login_msg(rec, rc);
- if (async_req)
- free(async_req);
- /* we raced with another app or instance of iscsiadm */
- if (rc == MGMT_IPC_ERR_EXISTS)
- return 0;
-
- return ENOTCONN;
- }
-
- if (async_req) {
- list_add_tail(&async_req->list, list);
- async_req->fd = fd;
- async_req->data = rec;
- } else
- log_login_msg(rec, rc);
-
- return 0;
-}
-
-static int __login_portals(void *data, int *nr_found,
- struct list_head *rec_list,
- int (* login_fn)(void *, struct list_head *,
- struct node_rec *))
-{
- struct node_rec *curr_rec, *tmp;
- struct list_head login_list;
- int ret = 0, err;
-
- *nr_found = 0;
- INIT_LIST_HEAD(&login_list);
-
- list_for_each_entry(curr_rec, rec_list, list) {
- err = login_fn(data, &login_list, curr_rec);
- if (err > 0 && !ret)
- ret = err;
- if (!err)
- (*nr_found)++;
- }
-
- err = iscsid_login_reqs_wait(&login_list);
- if (err && !ret)
- ret = err;
-
- list_for_each_entry_safe(curr_rec, tmp, rec_list, list) {
- list_del(&curr_rec->list);
- free(curr_rec);
- }
- return ret;
+ return iscsi_logout_portals(mode, &nr_found, __logout_by_startup);
}
/*
@@ -649,7 +383,7 @@ __login_by_startup(void *data, struct list_head *list, struct node_rec *rec)
if (match_startup_mode(rec, mode))
return -1;
- login_portal(NULL, list, rec);
+ iscsi_login_portal(NULL, list, rec);
return 0;
}
@@ -668,8 +402,8 @@ login_by_startup(char *mode)
INIT_LIST_HEAD(&rec_list);
rc = idbm_for_each_rec(&nr_found, &rec_list, link_recs);
- err = __login_portals(mode, &nr_found, &rec_list,
- __login_by_startup);
+ err = iscsi_login_portals(mode, &nr_found, &rec_list,
+ __login_by_startup);
if (err && !rc)
rc = err;
@@ -682,6 +416,37 @@ login_by_startup(char *mode)
return rc;
}
+/**
+ * iscsi_logout_matched_portal - logout of targets matching the rec info
+ * @data: record to session with
+ * @list: list to add logout rec to
+ * @info: session to match with rec
+ */
+static int iscsi_logout_matched_portal(void *data, struct list_head *list,
+ struct session_info *info)
+{
+ struct node_rec *pattern_rec = data;
+ struct iscsi_transport *t;
+
+ t = iscsi_sysfs_get_transport_by_sid(info->sid);
+ if (!t)
+ return -1;
+
+ if (!iscsi_match_session(pattern_rec, info))
+ return -1;
+
+ /* we do not support this yet */
+ if (t->caps & CAP_FW_DB) {
+ log_error("Could not logout session of [sid: %d, "
+ "target: %s, portal: %s,%d].", info->sid,
+ info->targetname, info->persistent_address,
+ info->port);
+ log_error("Logout not supported for driver: %s.", t->name);
+ return -1;
+ }
+ return iscsi_logout_portal(info, list);
+}
+
static int iface_fn(void *data, node_rec_t *rec)
{
struct rec_op_data *op_data = data;
@@ -732,8 +497,8 @@ static int login_portals(struct node_rec *pattern_rec)
INIT_LIST_HEAD(&rec_list);
ret = for_each_rec(pattern_rec, &rec_list, link_recs);
- err = __login_portals(NULL, &nr_found, &rec_list,
- login_portal);
+ err = iscsi_login_portals(NULL, &nr_found, &rec_list,
+ iscsi_login_portal);
if (err && !ret)
ret = err;
return ret;
@@ -1023,24 +788,6 @@ do_offload_sendtargets(discovery_rec_t *drec, int host_no, int do_login)
return discovery_offload_sendtargets(host_no, do_login, drec);
}
-static int login_discovered_portal(void *data, struct list_head *list,
- node_rec_t *rec)
-{
- discovery_rec_t *drec = data;
-
- if (rec->disc_type != drec->type ||
- rec->disc_port != drec->port ||
- strcmp(rec->disc_address, drec->address))
- return -1;
-
- login_portal(NULL, list, rec);
- /*
- * This is used during the initial setup, so we want to see
- * what portals we can or cannot log into and we will just continue
- */
- return 0;
-}
-
/* TODO merge with initiator.c implementation */
/* And add locking */
static int check_for_session_through_iface(struct node_rec *rec)
@@ -1144,7 +891,8 @@ exec_disc_op_on_recs(discovery_rec_t *drec, struct list_head *rec_list,
if (!do_login)
return 0;
- err = __login_portals(drec, &found, rec_list, login_discovered_portal);
+ err = iscsi_login_portals(NULL, &found, rec_list,
+ iscsi_login_portal);
if (err && !rc)
rc = err;
return rc;
@@ -1509,7 +1257,10 @@ static int exec_node_op(int op, int do_login, int do_logout,
}
if (do_logout) {
- if (logout_portals(rec))
+ int nr_found;
+
+ if (iscsi_logout_portals(rec, &nr_found,
+ iscsi_logout_matched_portal))
rc = -1;
goto out;
}
@@ -1695,7 +1446,7 @@ static int exec_fw_op(discovery_rec_t *drec, struct list_head *ifaces,
break;
}
- login_portal(NULL, NULL, rec);
+ iscsi_login_portal(NULL, NULL, rec);
free(rec);
}
} else {
diff --git a/usr/session_mgmt.c b/usr/session_mgmt.c
new file mode 100644
index 0000000..c22d730
--- /dev/null
+++ b/usr/session_mgmt.c
@@ -0,0 +1,301 @@
+/*
+ * iSCSI session management helpers
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "idbm.h"
+#include "list.h"
+#include "util.h"
+#include "mgmt_ipc.h"
+#include "session_info.h"
+#include "iscsi_sysfs.h"
+#include "log.h"
+
+static void log_login_msg(struct node_rec *rec, int rc)
+{
+ if (rc) {
+ log_error("Could not login to [iface: %s, target: %s, "
+ "portal: %s,%d].", rec->iface.name,
+ rec->name, rec->conn[0].address,
+ rec->conn[0].port);
+ iscsid_handle_error(rc);
+ } else
+ printf("Login to [iface: %s, target: %s, portal: "
+ "%s,%d] successful.\n", rec->iface.name,
+ rec->name, rec->conn[0].address,
+ rec->conn[0].port);
+}
+
+struct iscsid_async_req {
+ struct list_head list;
+ void *data;
+ int fd;
+};
+
+static int iscsid_login_reqs_wait(struct list_head *list)
+{
+ struct iscsid_async_req *tmp, *curr;
+ struct node_rec *rec;
+ int ret = 0;
+
+ list_for_each_entry_safe(curr, tmp, list, list) {
+ int err;
+
+ rec = curr->data;
+ err = iscsid_req_wait(MGMT_IPC_SESSION_LOGIN, curr->fd);
+ log_login_msg(rec, err);
+ list_del(&curr->list);
+ free(curr);
+ }
+ return ret;
+}
+
+/**
+ * iscsi_login_portal - request iscsid to login to portal
+ * @data: Unused. Only needed so this can be used in iscsi_login_portals
+ * @list: If async, list to add session to
+ * @rec: portal rec to log into
+ */
+int iscsi_login_portal(void *data, struct list_head *list, struct node_rec *rec)
+{
+ struct iscsid_async_req *async_req = NULL;
+ int rc = 0, fd;
+
+ printf("Logging in to [iface: %s, target: %s, portal: %s,%d]\n",
+ rec->iface.name, rec->name, rec->conn[0].address,
+ rec->conn[0].port);
+
+ if (list) {
+ async_req = calloc(1, sizeof(*async_req));
+ if (!async_req)
+ log_error("Could not allocate memory for async login "
+ "handling. Using sequential login instead.");
+ else
+ INIT_LIST_HEAD(&async_req->list);
+ }
+
+ if (async_req)
+ rc = iscsid_req_by_rec_async(MGMT_IPC_SESSION_LOGIN,
+ rec, &fd);
+ else
+ rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec);
+
+ if (rc) {
+ log_login_msg(rec, rc);
+ if (async_req)
+ free(async_req);
+ /* we raced with another app or instance of iscsiadm */
+ if (rc == MGMT_IPC_ERR_EXISTS)
+ return 0;
+
+ return ENOTCONN;
+ }
+
+ if (async_req) {
+ list_add_tail(&async_req->list, list);
+ async_req->fd = fd;
+ async_req->data = rec;
+ } else
+ log_login_msg(rec, rc);
+
+ return 0;
+}
+
+/**
+ * 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
+ * @rec_list: list of portals to log into
+ * @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.
+ */
+int iscsi_login_portals(void *data, int *nr_found,
+ struct list_head *rec_list,
+ int (* login_fn)(void *, struct list_head *,
+ struct node_rec *))
+{
+ struct node_rec *curr_rec, *tmp;
+ struct list_head login_list;
+ int ret = 0, err;
+
+ *nr_found = 0;
+ INIT_LIST_HEAD(&login_list);
+
+ list_for_each_entry(curr_rec, rec_list, list) {
+ err = login_fn(data, &login_list, curr_rec);
+ if (err > 0 && !ret)
+ ret = err;
+ if (!err)
+ (*nr_found)++;
+ }
+
+ err = iscsid_login_reqs_wait(&login_list);
+ if (err && !ret)
+ ret = err;
+
+ list_for_each_entry_safe(curr_rec, tmp, rec_list, list) {
+ list_del(&curr_rec->list);
+ free(curr_rec);
+ }
+ return ret;
+}
+
+static void log_logout_msg(struct session_info *info, int rc)
+{
+ if (rc) {
+ log_error("Could not logout of [sid: %d, target: %s, "
+ "portal: %s,%d].", info->sid,
+ info->targetname,
+ info->persistent_address, info->port);
+ iscsid_handle_error(rc);
+ } else
+ printf("Logout of [sid: %d, target: %s, "
+ "portal: %s,%d] successful.\n",
+ info->sid, info->targetname,
+ info->persistent_address, info->port);
+}
+
+static int iscsid_logout_reqs_wait(struct list_head *list)
+{
+ struct iscsid_async_req *tmp, *curr;
+ struct session_info *info;
+ int ret = 0;
+
+ list_for_each_entry_safe(curr, tmp, list, list) {
+ int err;
+
+ info = curr->data;
+ err = iscsid_req_wait(MGMT_IPC_SESSION_LOGOUT, curr->fd);
+ log_logout_msg(info, err);
+ if (err)
+ ret = err;
+ list_del(&curr->list);
+ free(curr);
+ }
+ return ret;
+}
+
+/**
+ * iscsi_logout_portal - logou tof portal
+ * @info: session to log out of
+ * @list: if async, this is the list to add the logout req to
+ */
+int iscsi_logout_portal(struct session_info *info, struct list_head *list)
+{
+ struct iscsid_async_req *async_req = NULL;
+ int fd, rc;
+
+ /* TODO: add fn to add session prefix info like dev_printk */
+ printf("Logging out of session [sid: %d, target: %s, portal: %s,%d]\n",
+ info->sid, info->targetname, info->persistent_address,
+ info->port);
+
+ if (list) {
+ async_req = calloc(1, sizeof(*async_req));
+ if (!async_req)
+ log_error("Could not allocate memory for async logout "
+ "handling. Using sequential logout instead.");
+ }
+
+ if (!async_req)
+ rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid);
+ else {
+ INIT_LIST_HEAD(&async_req->list);
+ rc = iscsid_req_by_sid_async(MGMT_IPC_SESSION_LOGOUT,
+ info->sid, &fd);
+ }
+
+ /* we raced with another app or instance of iscsiadm */
+ if (rc) {
+ log_logout_msg(info, rc);
+ if (async_req)
+ free(async_req);
+
+ if (rc == MGMT_IPC_ERR_NOT_FOUND)
+ return 0;
+
+ return EIO;
+ }
+
+ if (async_req) {
+ list_add_tail(&async_req->list, list);
+ async_req->fd = fd;
+ async_req->data = info;
+ } else
+ log_logout_msg(info, rc);
+
+ return 0;
+}
+
+/**
+ * iscsi_logout_portals - logout portals
+ * @data: data to pass to iter logout_fn
+ * @nr_found: number of sessions logged out
+ * @logout_fn: logout iter function
+ *
+ * This will loop over the list of sessions and run the logout fn
+ * on them. It will attempt to logout asynchronously, and then wait for
+ * them to complete.
+ */
+int iscsi_logout_portals(void *data, int *nr_found,
+ int (*logout_fn)(void *, struct list_head *,
+ struct session_info *))
+{
+ struct session_info *curr_info;
+ struct session_link_info link_info;
+ struct list_head session_list, logout_list;
+ int ret = 0, err;
+
+ INIT_LIST_HEAD(&session_list);
+ INIT_LIST_HEAD(&logout_list);
+
+ memset(&link_info, 0, sizeof(link_info));
+ link_info.list = &session_list;
+ link_info.data = NULL;
+ link_info.match_fn = NULL;
+ *nr_found = 0;
+
+ err = iscsi_sysfs_for_each_session(&link_info, nr_found,
+ session_info_create_list);
+ if (err || !*nr_found)
+ return err;
+
+ *nr_found = 0;
+ list_for_each_entry(curr_info, &session_list, list) {
+ err = logout_fn(data, &logout_list, curr_info);
+ if (err > 0 && !ret)
+ ret = err;
+ if (!err)
+ (*nr_found)++;
+ }
+
+ err = iscsid_logout_reqs_wait(&logout_list);
+ if (err)
+ ret = err;
+
+ session_info_free_list(&session_list);
+ return ret;
+}
diff --git a/usr/session_mgmt.h b/usr/session_mgmt.h
new file mode 100644
index 0000000..a101175
--- /dev/null
+++ b/usr/session_mgmt.h
@@ -0,0 +1,19 @@
+#ifndef _SESSION_MGMT_H_
+#define _SESSION_MGMT_H_
+
+struct node_rec;
+struct list_head;
+struct session_info;
+
+extern int iscsi_login_portal(void *data, struct list_head *list,
+ struct node_rec *rec);
+extern int iscsi_login_portals(void *data, int *nr_found,
+ 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 (*logout_fn)(void *, struct list_head *,
+ struct session_info *));
+#endif