|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* iSCSI session management helpers
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Copyright (C) 2010 Mike Christie
|
|
Packit |
eace71 |
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
|
Packit |
eace71 |
* Copyright (C) 2011 Dell Inc.
|
|
Packit |
eace71 |
* maintained by open-iscsi@googlegroups.com
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
eace71 |
* it under the terms of the GNU General Public License as published
|
|
Packit |
eace71 |
* by the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
eace71 |
* (at your option) any later version.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
eace71 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
eace71 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
eace71 |
* General Public License for more details.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* See the file COPYING included with this distribution for more details.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include <stdlib.h>
|
|
Packit |
eace71 |
#include <stdio.h>
|
|
Packit |
eace71 |
#include <errno.h>
|
|
Packit |
eace71 |
#include <unistd.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "idbm.h"
|
|
Packit |
eace71 |
#include "list.h"
|
|
Packit |
eace71 |
#include "iscsi_util.h"
|
|
Packit |
eace71 |
#include "mgmt_ipc.h"
|
|
Packit |
eace71 |
#include "session_info.h"
|
|
Packit |
eace71 |
#include "iscsi_sysfs.h"
|
|
Packit |
eace71 |
#include "log.h"
|
|
Packit |
eace71 |
#include "iscsid_req.h"
|
|
Packit |
eace71 |
#include "iscsi_err.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void log_login_msg(struct node_rec *rec, int rc)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
log_error("Could not login to [iface: %s, target: %s, "
|
|
Packit |
eace71 |
"portal: %s,%d].", rec->iface.name,
|
|
Packit |
eace71 |
rec->name, rec->conn[0].address,
|
|
Packit |
eace71 |
rec->conn[0].port);
|
|
Packit |
eace71 |
iscsi_err_print_msg(rc);
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
log_info("Login to [iface: %s, target: %s, portal: "
|
|
Packit |
eace71 |
"%s,%d] successful.", rec->iface.name,
|
|
Packit |
eace71 |
rec->name, rec->conn[0].address,
|
|
Packit |
eace71 |
rec->conn[0].port);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
struct iscsid_async_req {
|
|
Packit |
eace71 |
struct list_head list;
|
|
Packit |
eace71 |
void *data;
|
|
Packit |
eace71 |
int fd;
|
|
Packit |
eace71 |
};
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* iscsid_reqs_close - close open async requests
|
|
Packit |
eace71 |
* @list: list of async reqs
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This just closes the socket to the daemon.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
static void iscsid_reqs_close(struct list_head *list)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsid_async_req *tmp, *curr;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry_safe(curr, tmp, list, list) {
|
|
Packit |
eace71 |
close(curr->fd);
|
|
Packit |
eace71 |
list_del(&curr->list);
|
|
Packit |
eace71 |
free(curr);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int iscsid_login_reqs_wait(struct list_head *list)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsid_async_req *tmp, *curr;
|
|
Packit |
eace71 |
struct node_rec *rec;
|
|
Packit |
eace71 |
int ret = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry_safe(curr, tmp, list, list) {
|
|
Packit |
eace71 |
int err;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
rec = curr->data;
|
|
Packit |
eace71 |
err = iscsid_req_wait(MGMT_IPC_SESSION_LOGIN, curr->fd);
|
|
Packit |
eace71 |
if (err && !ret)
|
|
Packit |
eace71 |
ret = err;
|
|
Packit |
eace71 |
log_login_msg(rec, err);
|
|
Packit |
eace71 |
list_del(&curr->list);
|
|
Packit |
eace71 |
free(curr);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return ret;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* __iscsi_login_portal - request iscsid to login to portal
|
|
Packit |
eace71 |
* @data: If set, copies the session.multiple value to the portal record
|
|
Packit |
eace71 |
* so it is propagated to iscsid.
|
|
Packit |
eace71 |
* @list: If async, list to add session to
|
|
Packit |
eace71 |
* @rec: portal rec to log into
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
static int
|
|
Packit |
eace71 |
__iscsi_login_portal(void *data, struct list_head *list, struct node_rec *rec)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsid_async_req *async_req = NULL;
|
|
Packit |
eace71 |
int rc = 0, fd;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (data && !rec->session.multiple) {
|
|
Packit |
eace71 |
struct node_rec *pattern_rec = data;
|
|
Packit |
eace71 |
rec->session.multiple = pattern_rec->session.multiple;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
log_info("Logging in to [iface: %s, target: %s, portal: %s,%d]%s",
|
|
Packit |
eace71 |
rec->iface.name, rec->name, rec->conn[0].address,
|
|
Packit |
eace71 |
rec->conn[0].port,
|
|
Packit |
eace71 |
(rec->session.multiple ? " (multiple)" : ""));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (list) {
|
|
Packit |
eace71 |
async_req = calloc(1, sizeof(*async_req));
|
|
Packit |
eace71 |
if (!async_req)
|
|
Packit |
eace71 |
log_info("Could not allocate memory for async login "
|
|
Packit |
eace71 |
"handling. Using sequential login instead.");
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&async_req->list);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (async_req)
|
|
Packit |
eace71 |
rc = iscsid_req_by_rec_async(MGMT_IPC_SESSION_LOGIN,
|
|
Packit |
eace71 |
rec, &fd;;
|
|
Packit |
eace71 |
else
|
|
Packit |
eace71 |
rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
log_login_msg(rec, rc);
|
|
Packit |
eace71 |
if (async_req)
|
|
Packit |
eace71 |
free(async_req);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (async_req) {
|
|
Packit |
eace71 |
list_add_tail(&async_req->list, list);
|
|
Packit |
eace71 |
async_req->fd = fd;
|
|
Packit |
eace71 |
async_req->data = rec;
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
log_login_msg(rec, rc);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* iscsi_login_portal - request iscsid to login to portal multiple
|
|
Packit |
eace71 |
* times, based on the session.nr_sessions in the portal record.
|
|
Packit |
eace71 |
* @data: If set, session.multiple will cause an additional session to
|
|
Packit |
eace71 |
* be created regardless of the value of session.nr_sessions
|
|
Packit |
eace71 |
* @list: If async, list to add session to
|
|
Packit |
eace71 |
* @rec: portal rec to log into
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int iscsi_login_portal(void *data, struct list_head *list, struct node_rec *rec)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct node_rec *pattern_rec = data;
|
|
Packit |
eace71 |
int rc = 0, session_count = 0, i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* If pattern_rec->session.multiple is set, just add a single new
|
|
Packit |
eace71 |
* session by passing things along to __iscsi_login_portal
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (pattern_rec && pattern_rec->session.multiple)
|
|
Packit |
eace71 |
return __iscsi_login_portal(data, list, rec);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Count the current number of sessions, and only create those
|
|
Packit |
eace71 |
* that are missing.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
rc = iscsi_sysfs_for_each_session(rec, &session_count,
|
|
Packit |
eace71 |
iscsi_match_session_count, 0);
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
log_error("Could not count current number of sessions");
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (session_count >= rec->session.nr_sessions) {
|
|
Packit Service |
83beb6 |
log_warning("%s: %d session%s requested, but %d "
|
|
Packit |
eace71 |
"already present.",
|
|
Packit |
eace71 |
rec->iface.name, rec->session.nr_sessions,
|
|
Packit |
eace71 |
rec->session.nr_sessions == 1 ? "" : "s",
|
|
Packit |
eace71 |
session_count);
|
|
Packit Service |
83beb6 |
rc = ISCSI_ERR_SESS_EXISTS;
|
|
Packit |
eace71 |
goto done;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Ensure the record's 'multiple' flag is set so __iscsi_login_portal
|
|
Packit |
eace71 |
* will allow multiple logins, but only if configured for more
|
|
Packit |
eace71 |
* than one
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
if (rec->session.nr_sessions > 1)
|
|
Packit |
eace71 |
rec->session.multiple = 1;
|
|
Packit |
eace71 |
for (i = session_count; i < rec->session.nr_sessions; ++i) {
|
|
Packit |
eace71 |
log_debug(1, "%s: Creating session %d/%d", rec->iface.name,
|
|
Packit |
eace71 |
i + 1, rec->session.nr_sessions);
|
|
Packit |
eace71 |
int err = __iscsi_login_portal(pattern_rec, list, rec);
|
|
Packit |
eace71 |
if (err && !rc)
|
|
Packit |
eace71 |
rc = err;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
done:
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* iscsi_login_portal_nowait - request iscsid to login to portal
|
|
Packit |
eace71 |
* @rec: portal rec to log into
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This sends the login request, but does not wait for the result.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int iscsi_login_portal_nowait(struct node_rec *rec)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct list_head list;
|
|
Packit |
eace71 |
int err;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&list);
|
|
Packit |
eace71 |
err = iscsi_login_portal(NULL, &list, rec);
|
|
Packit |
eace71 |
if (err > 0)
|
|
Packit |
eace71 |
return err;
|
|
Packit |
eace71 |
iscsid_reqs_close(&list);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* __iscsi_login_portals - login into portals on @rec_list,
|
|
Packit |
eace71 |
* @data: data to pass to login_fn
|
|
Packit |
eace71 |
* @nr_found: returned with number of portals logged into
|
|
Packit |
eace71 |
* @wait: bool indicating if the fn should wait for the result
|
|
Packit |
eace71 |
* @rec_list: list of portals to log into
|
|
Packit |
eace71 |
* @clear_list: If set, delete and free rec_list after iterating through.
|
|
Packit |
eace71 |
* @login_fn: list iter function
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This will loop over the list of portals and login. It
|
|
Packit |
eace71 |
* will attempt to login asynchronously, and then wait for
|
|
Packit |
eace71 |
* them to complete if wait is set.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
static
|
|
Packit |
eace71 |
int __iscsi_login_portals(void *data, int *nr_found, int wait,
|
|
Packit |
eace71 |
struct list_head *rec_list, int clear_list,
|
|
Packit |
eace71 |
int (*login_fn)(void *, struct list_head *,
|
|
Packit |
eace71 |
struct node_rec *))
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct node_rec *curr_rec, *tmp;
|
|
Packit |
eace71 |
struct list_head login_list;
|
|
Packit |
eace71 |
int ret = 0, err;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
*nr_found = 0;
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&login_list);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry(curr_rec, rec_list, list) {
|
|
Packit |
eace71 |
err = login_fn(data, &login_list, curr_rec);
|
|
Packit |
eace71 |
if (err > 0 && !ret)
|
|
Packit |
eace71 |
ret = err;
|
|
Packit |
eace71 |
if (!err)
|
|
Packit |
eace71 |
(*nr_found)++;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (wait) {
|
|
Packit |
eace71 |
err = iscsid_login_reqs_wait(&login_list);
|
|
Packit |
eace71 |
if (err && !ret)
|
|
Packit |
eace71 |
ret = err;
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
iscsid_reqs_close(&login_list);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (clear_list) {
|
|
Packit |
eace71 |
list_for_each_entry_safe(curr_rec, tmp, rec_list, list) {
|
|
Packit |
eace71 |
list_del(&curr_rec->list);
|
|
Packit |
eace71 |
free(curr_rec);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return ret;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* iscsi_login_portals - login into portals on @rec_list,
|
|
Packit |
eace71 |
* @data: data to pass to login_fn
|
|
Packit |
eace71 |
* @nr_found: returned with number of portals logged into
|
|
Packit |
eace71 |
* @wait: bool indicating if the fn should wait for the result
|
|
Packit |
eace71 |
* @rec_list: list of portals to log into. This list is deleted after
|
|
Packit |
eace71 |
* iterating through it.
|
|
Packit |
eace71 |
* @login_fn: list iter function
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This will loop over the list of portals and login. It
|
|
Packit |
eace71 |
* will attempt to login asynchronously, and then wait for
|
|
Packit |
eace71 |
* them to complete if wait is set.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int iscsi_login_portals(void *data, int *nr_found, int wait,
|
|
Packit |
eace71 |
struct list_head *rec_list,
|
|
Packit |
eace71 |
int (*login_fn)(void *, struct list_head *,
|
|
Packit |
eace71 |
struct node_rec *))
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
return __iscsi_login_portals(data, nr_found, wait, rec_list,
|
|
Packit |
eace71 |
1, login_fn);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* iscsi_login_portals_safe - login into portals on @rec_list, but do not
|
|
Packit |
eace71 |
* clear out rec_list.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int iscsi_login_portals_safe(void *data, int *nr_found, int wait,
|
|
Packit |
eace71 |
struct list_head *rec_list,
|
|
Packit |
eace71 |
int (*login_fn)(void *, struct list_head *,
|
|
Packit |
eace71 |
struct node_rec *))
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
return __iscsi_login_portals(data, nr_found, wait, rec_list,
|
|
Packit |
eace71 |
0, login_fn);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static void log_logout_msg(struct session_info *info, int rc)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
log_error("Could not logout of [sid: %d, target: %s, "
|
|
Packit |
eace71 |
"portal: %s,%d].", info->sid,
|
|
Packit |
eace71 |
info->targetname,
|
|
Packit |
eace71 |
info->persistent_address, info->port);
|
|
Packit |
eace71 |
iscsi_err_print_msg(rc);
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
log_info("Logout of [sid: %d, target: %s, "
|
|
Packit |
eace71 |
"portal: %s,%d] successful.",
|
|
Packit |
eace71 |
info->sid, info->targetname,
|
|
Packit |
eace71 |
info->persistent_address, info->port);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
static int iscsid_logout_reqs_wait(struct list_head *list)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsid_async_req *tmp, *curr;
|
|
Packit |
eace71 |
struct session_info *info;
|
|
Packit |
eace71 |
int ret = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry_safe(curr, tmp, list, list) {
|
|
Packit |
eace71 |
int err;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
info = curr->data;
|
|
Packit |
eace71 |
err = iscsid_req_wait(MGMT_IPC_SESSION_LOGOUT, curr->fd);
|
|
Packit |
eace71 |
log_logout_msg(info, err);
|
|
Packit |
eace71 |
if (err)
|
|
Packit |
eace71 |
ret = err;
|
|
Packit |
eace71 |
list_del(&curr->list);
|
|
Packit |
eace71 |
free(curr);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
return ret;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* iscsi_logout_portal - logout of portal
|
|
Packit |
eace71 |
* @info: session to log out of
|
|
Packit |
eace71 |
* @list: if async, this is the list to add the logout req to
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int iscsi_logout_portal(struct session_info *info, struct list_head *list)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct iscsid_async_req *async_req = NULL;
|
|
Packit |
eace71 |
int fd, rc;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* TODO: add fn to add session prefix info like dev_printk */
|
|
Packit |
eace71 |
log_info("Logging out of session [sid: %d, target: %s, portal: "
|
|
Packit |
eace71 |
"%s,%d]",
|
|
Packit |
eace71 |
info->sid, info->targetname, info->persistent_address,
|
|
Packit |
eace71 |
info->port);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (list) {
|
|
Packit |
eace71 |
async_req = calloc(1, sizeof(*async_req));
|
|
Packit |
eace71 |
if (!async_req)
|
|
Packit |
eace71 |
log_info("Could not allocate memory for async logout "
|
|
Packit |
eace71 |
"handling. Using sequential logout instead.");
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!async_req)
|
|
Packit |
eace71 |
rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid);
|
|
Packit |
eace71 |
else {
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&async_req->list);
|
|
Packit |
eace71 |
rc = iscsid_req_by_sid_async(MGMT_IPC_SESSION_LOGOUT,
|
|
Packit |
eace71 |
info->sid, &fd;;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* we raced with another app or instance of iscsiadm */
|
|
Packit |
eace71 |
if (rc) {
|
|
Packit |
eace71 |
log_logout_msg(info, rc);
|
|
Packit |
eace71 |
if (async_req)
|
|
Packit |
eace71 |
free(async_req);
|
|
Packit |
eace71 |
return rc;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (async_req) {
|
|
Packit |
eace71 |
list_add_tail(&async_req->list, list);
|
|
Packit |
eace71 |
async_req->fd = fd;
|
|
Packit |
eace71 |
async_req->data = info;
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
log_logout_msg(info, rc);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* iscsi_logout_portals - logout portals
|
|
Packit |
eace71 |
* @data: data to pass to iter logout_fn
|
|
Packit |
eace71 |
* @nr_found: number of sessions logged out
|
|
Packit |
eace71 |
* @wait: bool indicating if the fn should wait for the result
|
|
Packit |
eace71 |
* @logout_fn: logout iter function
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This will loop over the list of sessions and run the logout fn
|
|
Packit |
eace71 |
* on them. It will attempt to logout asynchronously, and then wait for
|
|
Packit |
eace71 |
* them to complete if wait is set.
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
int iscsi_logout_portals(void *data, int *nr_found, int wait,
|
|
Packit |
eace71 |
int (*logout_fn)(void *, struct list_head *,
|
|
Packit |
eace71 |
struct session_info *))
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct session_info *curr_info;
|
|
Packit |
eace71 |
struct session_link_info link_info;
|
|
Packit |
eace71 |
struct list_head session_list, logout_list;
|
|
Packit |
eace71 |
int ret = 0, err;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&session_list);
|
|
Packit |
eace71 |
INIT_LIST_HEAD(&logout_list);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memset(&link_info, 0, sizeof(link_info));
|
|
Packit |
eace71 |
link_info.list = &session_list;
|
|
Packit |
eace71 |
link_info.data = NULL;
|
|
Packit |
eace71 |
link_info.match_fn = NULL;
|
|
Packit |
eace71 |
*nr_found = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
err = iscsi_sysfs_for_each_session(&link_info, nr_found,
|
|
Packit |
eace71 |
session_info_create_list, 0);
|
|
Packit |
eace71 |
if (err && !list_empty(&session_list))
|
|
Packit |
eace71 |
log_error("Could not read in all sessions: %s",
|
|
Packit |
eace71 |
iscsi_err_to_str(err));
|
|
Packit |
eace71 |
else if (err && list_empty(&session_list)) {
|
|
Packit |
eace71 |
log_error("Could not read session info.");
|
|
Packit |
eace71 |
return err;
|
|
Packit |
eace71 |
} else if (list_empty(&session_list))
|
|
Packit |
eace71 |
return ISCSI_ERR_NO_OBJS_FOUND;
|
|
Packit |
eace71 |
ret = err;
|
|
Packit |
eace71 |
*nr_found = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
list_for_each_entry(curr_info, &session_list, list) {
|
|
Packit |
eace71 |
err = logout_fn(data, &logout_list, curr_info);
|
|
Packit |
eace71 |
if (err > 0 && !ret)
|
|
Packit |
eace71 |
ret = err;
|
|
Packit |
eace71 |
if (!err)
|
|
Packit |
eace71 |
(*nr_found)++;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (!*nr_found) {
|
|
Packit |
eace71 |
ret = ISCSI_ERR_NO_OBJS_FOUND;
|
|
Packit |
eace71 |
goto free_list;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (wait) {
|
|
Packit |
eace71 |
err = iscsid_logout_reqs_wait(&logout_list);
|
|
Packit |
eace71 |
if (err && !ret)
|
|
Packit |
eace71 |
ret = err;
|
|
Packit |
eace71 |
} else
|
|
Packit |
eace71 |
iscsid_reqs_close(&logout_list);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
if (ret)
|
|
Packit |
eace71 |
log_error("Could not logout of all requested sessions");
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
free_list:
|
|
Packit |
eace71 |
session_info_free_list(&session_list);
|
|
Packit |
eace71 |
return ret;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* TODO merge with initiator.c implementation */
|
|
Packit |
eace71 |
/* And add locking */
|
|
Packit |
eace71 |
int iscsi_check_for_running_session(struct node_rec *rec)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int nr_found = 0;
|
|
Packit |
eace71 |
if (iscsi_sysfs_for_each_session(rec, &nr_found, iscsi_match_session,
|
|
Packit |
eace71 |
0))
|
|
Packit |
eace71 |
return 1;
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|