mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-14 09:11:27 +00:00
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7396 d57e44dd-8a1f-0410-8b47-8ef2f437770f
203 lines
4.3 KiB
C
203 lines
4.3 KiB
C
/*
|
|
* Copyright (C) 2002 - 2003 Ardis Technologies <roman@ardistech.com>
|
|
* Copyright (C) 2007 - 2018 Vladislav Bolkhovitin
|
|
* Copyright (C) 2007 - 2018 Western Digital Corporation
|
|
*
|
|
* 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, version 2
|
|
* of the License.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <dirent.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
|
|
#include "iscsid.h"
|
|
|
|
static int session_alloc(u32 tid, struct session **psess)
|
|
{
|
|
struct session *session;
|
|
struct target *target = target_find_by_id(tid);
|
|
int res = 0;
|
|
|
|
if (!target) {
|
|
log_error("tid %x not found", tid);
|
|
res = -ENOENT;
|
|
goto out;
|
|
}
|
|
|
|
if (!(session = malloc(sizeof(*session)))) {
|
|
res = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
memset(session, 0, sizeof(*session));
|
|
|
|
session->target = target;
|
|
INIT_LIST_HEAD(&session->slist);
|
|
list_add_tail(&session->slist, &target->sessions_list);
|
|
|
|
*psess = session;
|
|
|
|
out:
|
|
return res;
|
|
}
|
|
|
|
struct session *session_find_name(u32 tid, const char *iname, union iscsi_sid sid)
|
|
{
|
|
struct session *session;
|
|
struct target *target;
|
|
|
|
if (!(target = target_find_by_id(tid))) {
|
|
log_error("Target tid %d not found", tid);
|
|
return NULL;
|
|
}
|
|
|
|
log_debug(1, "Finding session %s, sid %#" PRIx64, iname, sid.id64);
|
|
|
|
list_for_each_entry(session, &target->sessions_list, slist) {
|
|
if (!memcmp(sid.id.isid, session->sid.id.isid, 6) &&
|
|
!strcmp(iname, session->initiator))
|
|
return session;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct session *session_find_id(u32 tid, u64 sid)
|
|
{
|
|
struct session *session;
|
|
struct target *target;
|
|
|
|
if (!(target = target_find_by_id(tid)))
|
|
return NULL;
|
|
|
|
log_debug(1, "Searching for sid %#" PRIx64, sid);
|
|
|
|
list_for_each_entry(session, &target->sessions_list, slist) {
|
|
if (session->sid.id64 == sid)
|
|
return session;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static bool session_id_exists(u32 tid, u64 sid, struct session *exclude)
|
|
{
|
|
struct session *session;
|
|
struct target *target;
|
|
|
|
if (!(target = target_find_by_id(tid)))
|
|
return false;
|
|
|
|
log_debug(1, "Searching for sid %#" PRIx64, sid);
|
|
|
|
list_for_each_entry(session, &target->sessions_list, slist) {
|
|
if ((session->sid.id64 == sid) && (session != exclude))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int session_create(struct connection *conn)
|
|
{
|
|
/* We are single threaded, so it doesn't need any protection */
|
|
static u16 tsih = 1;
|
|
struct session *session;
|
|
int res = 0;
|
|
|
|
res = session_alloc(conn->tid, &session);
|
|
if (res != 0) {
|
|
log_error("session_alloc() failed: %d", res);
|
|
goto out;
|
|
}
|
|
|
|
session->sid = conn->sid;
|
|
session->sid.id.tsih = tsih;
|
|
INIT_LIST_HEAD(&session->conn_list);
|
|
|
|
list_add_tail(&conn->clist, &session->conn_list);
|
|
conn->sess = session;
|
|
|
|
conn->sess->initiator = strdup(conn->initiator);
|
|
if (conn->sess->initiator == NULL) {
|
|
res = -errno;
|
|
log_error("strdup() failed: %d", res);
|
|
goto out_free;
|
|
}
|
|
|
|
while (1) {
|
|
bool e;
|
|
|
|
e = session_id_exists(conn->tid, session->sid.id64, session);
|
|
if (!e)
|
|
break;
|
|
|
|
log_debug(1, "tsih %x already exists", session->sid.id.tsih);
|
|
session->sid.id.tsih++;
|
|
}
|
|
tsih = session->sid.id.tsih + 1;
|
|
|
|
log_debug(1, "sid %#" PRIx64, session->sid.id64);
|
|
|
|
res = kernel_session_create(conn);
|
|
if (res != 0)
|
|
goto out_free;
|
|
|
|
out:
|
|
return res;
|
|
|
|
out_free:
|
|
list_del_init(&conn->clist);
|
|
assert(list_empty(&session->conn_list));
|
|
session_free(session);
|
|
conn->sess = NULL;
|
|
goto out;
|
|
}
|
|
|
|
void session_free(struct session *session)
|
|
{
|
|
log_debug(1, "Freeing session sid %#"PRIx64, session->sid.id64);
|
|
|
|
if (session->target) {
|
|
struct target *target = session->target;
|
|
|
|
kernel_session_destroy(target->tid, session->sid.id64);
|
|
|
|
target->sessions_count--;
|
|
log_debug(1, "target %s, sessions_count %d", target->name,
|
|
target->sessions_count);
|
|
|
|
list_del(&session->slist);
|
|
}
|
|
|
|
free(session->initiator);
|
|
free(session);
|
|
return;
|
|
}
|
|
|
|
struct connection *conn_find(struct session *session, u16 cid)
|
|
{
|
|
struct connection *conn;
|
|
|
|
list_for_each_entry(conn, &session->conn_list, clist) {
|
|
if (conn->cid == cid)
|
|
return conn;
|
|
}
|
|
|
|
return NULL;
|
|
}
|