- Fixed a major IET-derived iSCSI RFC violation: sessions and connections were not working

- A lot of cleanups and minor fixes, mostly IET-derived



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@685 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2009-03-03 18:13:23 +00:00
parent aaa11b710b
commit bc7c69bfc4
23 changed files with 771 additions and 731 deletions

View File

@@ -262,21 +262,21 @@ Show the configured parameters for a specific target:
# iscsi-scst-adm --op show --tid=1 --sid=0
InitialR2T=No
ImmediateData=
MaxConnections=0
MaxRecvDataSegmentLength=4269849632
MaxXmitDataSegmentLength=10933
MaxBurstLength=4294967295
FirstBurstLength=32767
DefaultTime2Wait=4203042
DefaultTime2Retain=5
MaxOutstandingR2T=0
DataPDUInOrder=No
ImmediateData=Yes
MaxConnections=1
MaxRecvDataSegmentLength=2097152
MaxXmitDataSegmentLength=131072
MaxBurstLength=2097152
FirstBurstLength=262144
DefaultTime2Wait=2
DefaultTime2Retain=0
MaxOutstandingR2T=1
DataPDUInOrder=Yes
DataSequenceInOrder=Yes
ErrorRecoveryLevel=0
HeaderDigest=
DataDigest=CRC32C
OFMarker=
HeaderDigest=None
DataDigest=None
OFMarker=No
IFMarker=No
OFMarkInt=Reject
IFMarkInt=Reject

View File

@@ -34,12 +34,12 @@
#define aligned_u64 uint64_t __attribute__((aligned(8)))
#endif
struct target_info {
struct iscsi_kern_target_info {
u32 tid;
char name[ISCSI_NAME_LEN];
};
struct session_info {
struct iscsi_kern_session_info {
u32 tid;
aligned_u64 sid;
@@ -52,7 +52,7 @@ struct session_info {
#define DIGEST_NONE (1 << 0)
#define DIGEST_CRC32C (1 << 1)
struct conn_info {
struct iscsi_kern_conn_info {
u32 tid;
aligned_u64 sid;
@@ -97,7 +97,7 @@ enum {
key_target,
};
struct iscsi_param_info {
struct iscsi_kern_param_info {
u32 tid;
aligned_u64 sid;
@@ -108,18 +108,18 @@ struct iscsi_param_info {
s32 target_param[target_key_last];
};
enum iscsi_event_state {
enum iscsi_kern_event_state {
E_CONN_CLOSE,
};
struct iscsi_event {
struct iscsi_kern_event {
u32 tid;
aligned_u64 sid;
u32 cid;
u32 state;
};
struct iscsi_register_info {
struct iscsi_kern_register_info {
aligned_u64 version;
};
@@ -130,18 +130,16 @@ struct iscsi_register_info {
#define NETLINK_ISCSI_SCST 25
/* On success returns MAX_DATA_SEG_LEN */
#define REGISTER_USERD _IOW('s', 0, struct iscsi_register_info)
#define REGISTER_USERD _IOW('s', 0, struct iscsi_kern_register_info)
#define ADD_TARGET _IOW('s', 1, struct target_info)
#define DEL_TARGET _IOW('s', 2, struct target_info)
#define ADD_SESSION _IOW('s', 3, struct session_info)
#define DEL_SESSION _IOW('s', 4, struct session_info)
#define GET_SESSION_INFO _IOWR('s', 5, struct session_info)
#define ADD_CONN _IOW('s', 6, struct conn_info)
#define DEL_CONN _IOW('s', 7, struct conn_info)
#define GET_CONN_INFO _IOWR('s', 8, struct conn_info)
#define ISCSI_PARAM_SET _IOW('s', 9, struct iscsi_param_info)
#define ISCSI_PARAM_GET _IOWR('s', 10, struct iscsi_param_info)
#define ADD_TARGET _IOW('s', 1, struct iscsi_kern_target_info)
#define DEL_TARGET _IOW('s', 2, struct iscsi_kern_target_info)
#define ADD_SESSION _IOW('s', 3, struct iscsi_kern_session_info)
#define DEL_SESSION _IOW('s', 4, struct iscsi_kern_session_info)
#define ADD_CONN _IOW('s', 5, struct iscsi_kern_conn_info)
#define DEL_CONN _IOW('s', 6, struct iscsi_kern_conn_info)
#define ISCSI_PARAM_SET _IOW('s', 7, struct iscsi_kern_param_info)
#define ISCSI_PARAM_GET _IOWR('s', 8, struct iscsi_kern_param_info)
static inline int iscsi_is_key_declarative(int key)
{

View File

@@ -229,39 +229,12 @@ err:
goto out;
}
/* target_mutex supposed to be locked */
static int get_conn_info(struct iscsi_target *target, void __user *ptr)
{
int err;
struct iscsi_session *session;
struct conn_info info;
struct iscsi_conn *conn;
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
return err;
session = session_lookup(target, info.sid);
if (!session)
return -ENOENT;
conn = conn_lookup(session, info.cid);
info.cid = conn->cid;
info.stat_sn = conn->stat_sn;
info.exp_stat_sn = conn->exp_stat_sn;
if (copy_to_user(ptr, &info, sizeof(info)))
return -EFAULT;
return 0;
}
/* target_mutex supposed to be locked */
static int add_conn(struct iscsi_target *target, void __user *ptr)
{
int err;
struct iscsi_session *session;
struct conn_info info;
struct iscsi_kern_conn_info info;
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
@@ -279,7 +252,7 @@ static int del_conn(struct iscsi_target *target, void __user *ptr)
{
int err;
struct iscsi_session *session;
struct conn_info info;
struct iscsi_kern_conn_info info;
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
@@ -292,35 +265,11 @@ static int del_conn(struct iscsi_target *target, void __user *ptr)
return conn_del(session, &info);
}
/* target_mutex supposed to be locked */
static int get_session_info(struct iscsi_target *target, void __user *ptr)
{
int err;
struct iscsi_session *session;
struct session_info info;
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
return err;
session = session_lookup(target, info.sid);
if (!session)
return -ENOENT;
info.exp_cmd_sn = session->exp_cmd_sn;
if (copy_to_user(ptr, &info, sizeof(info)))
return -EFAULT;
return 0;
}
/* target_mutex supposed to be locked */
static int add_session(struct iscsi_target *target, void __user *ptr)
{
int err;
struct session_info info;
struct iscsi_kern_session_info info;
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
@@ -336,7 +285,7 @@ static int add_session(struct iscsi_target *target, void __user *ptr)
static int del_session(struct iscsi_target *target, void __user *ptr)
{
int err;
struct session_info info;
struct iscsi_kern_session_info info;
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
@@ -350,7 +299,7 @@ static int iscsi_param_config(struct iscsi_target *target, void __user *ptr,
int set)
{
int err;
struct iscsi_param_info info;
struct iscsi_kern_param_info info;
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
@@ -371,7 +320,7 @@ out:
static int add_target(void __user *ptr)
{
int err;
struct target_info info;
struct iscsi_kern_target_info info;
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
@@ -386,7 +335,7 @@ static int add_target(void __user *ptr)
static int iscsi_check_version(void __user *arg)
{
struct iscsi_register_info reg;
struct iscsi_kern_register_info reg;
char ver[sizeof(ISCSI_SCST_INTERFACE_VERSION)+1];
int res;
@@ -428,12 +377,10 @@ static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case DEL_TARGET:
case ADD_SESSION:
case DEL_SESSION:
case GET_SESSION_INFO:
case ISCSI_PARAM_SET:
case ISCSI_PARAM_GET:
case ADD_CONN:
case DEL_CONN:
case GET_CONN_INFO:
break;
case REGISTER_USERD:
@@ -491,10 +438,6 @@ static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
err = del_session(target, (void __user *) arg);
break;
case GET_SESSION_INFO:
err = get_session_info(target, (void __user *) arg);
break;
case ISCSI_PARAM_SET:
err = iscsi_param_config(target, (void __user *) arg, 1);
break;
@@ -511,10 +454,6 @@ static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
err = del_conn(target, (void __user *) arg);
break;
case GET_CONN_INFO:
err = get_conn_info(target, (void __user *) arg);
break;
default:
sBUG();
break;
@@ -555,9 +494,9 @@ static void iscsi_dump_char(int ch)
text[i] = ' ';
i++;
if ((i % 16) == 0)
printk(LOG_FLAG " | %.16s |\n", text);
printk(" | %.16s |\n", text);
else if ((i % 4) == 0)
printk(LOG_FLAG " |");
printk(" |");
}
i = 0;
return;
@@ -567,10 +506,10 @@ static void iscsi_dump_char(int ch)
printk(LOG_FLAG " %02x", ch);
i++;
if ((i % 16) == 0) {
printk(LOG_FLAG " | %.16s |\n", text);
printk(" | %.16s |\n", text);
i = 0;
} else if ((i % 4) == 0)
printk(LOG_FLAG " |");
printk(" |");
}
void iscsi_dump_pdu(struct iscsi_pdu *pdu)

View File

@@ -107,7 +107,12 @@ struct iscsi_conn *conn_lookup(struct iscsi_session *session, u16 cid)
{
struct iscsi_conn *conn;
list_for_each_entry(conn, &session->conn_list, conn_list_entry) {
/*
* We need to find the latest conn to correctly handle
* multi-reinstatements
*/
list_for_each_entry_reverse(conn, &session->conn_list,
conn_list_entry) {
if (conn->cid == cid)
return conn;
}
@@ -118,6 +123,8 @@ static void iscsi_make_conn_rd_active(struct iscsi_conn *conn)
{
TRACE_ENTRY();
EXTRACHECKS_BUG_ON(conn->conn_reinstating);
spin_lock_bh(&iscsi_rd_lock);
TRACE_DBG("conn %p, rd_state %x, rd_data_ready %d", conn,
@@ -168,7 +175,8 @@ void __mark_conn_closed(struct iscsi_conn *conn, int flags)
conn->deleting = 1;
spin_unlock_bh(&iscsi_rd_lock);
iscsi_make_conn_rd_active(conn);
if (!conn->conn_reinstating)
iscsi_make_conn_rd_active(conn);
}
void mark_conn_closed(struct iscsi_conn *conn)
@@ -184,9 +192,11 @@ static void iscsi_state_change(struct sock *sk)
if (unlikely(sk->sk_state != TCP_ESTABLISHED)) {
if (!conn->closing) {
PRINT_ERROR("Connection with initiator %s (%p) "
PRINT_ERROR("Connection with initiator %s "
"unexpectedly closed!",
conn->session->initiator_name, conn);
conn->session->initiator_name);
TRACE_MGMT_DBG("conn %p, sk state %d", conn,
sk->sk_state);
__mark_conn_closed(conn, 0);
}
} else
@@ -275,13 +285,41 @@ static void conn_rsp_timer_fn(unsigned long arg)
return;
}
void __iscsi_socket_bind(struct iscsi_conn *conn)
{
TRACE_MGMT_DBG("Enabling conn %p", conn);
/* Catch double bind */
sBUG_ON(conn->sock->sk->sk_state_change == iscsi_state_change);
/* Let's reset this flag in one place */
conn->conn_reinstating = 0;
write_lock_bh(&conn->sock->sk->sk_callback_lock);
conn->old_state_change = conn->sock->sk->sk_state_change;
conn->sock->sk->sk_state_change = iscsi_state_change;
conn->old_data_ready = conn->sock->sk->sk_data_ready;
conn->sock->sk->sk_data_ready = iscsi_data_ready;
conn->old_write_space = conn->sock->sk->sk_write_space;
conn->sock->sk->sk_write_space = iscsi_write_space_ready;
write_unlock_bh(&conn->sock->sk->sk_callback_lock);
iscsi_make_conn_rd_active(conn);
return;
}
/*
* Note: the code belows passes a kernel space pointer (&opt) to setsockopt()
* Note: the code below passes a kernel space pointer (&opt) to setsockopt()
* while the declaration of setsockopt specifies that it expects a user space
* pointer. This seems to work fine, and this approach is also used in some
* other parts of the Linux kernel (see e.g. fs/ocfs2/cluster/tcp.c).
*/
static int iscsi_socket_bind(struct iscsi_conn *conn)
static int iscsi_socket_bind(struct iscsi_conn *conn, bool reinstating)
{
int res = 0;
int opt = 1;
@@ -304,25 +342,23 @@ static int iscsi_socket_bind(struct iscsi_conn *conn)
#endif
conn->sock->sk->sk_user_data = conn;
write_lock_bh(&conn->sock->sk->sk_callback_lock);
conn->old_state_change = conn->sock->sk->sk_state_change;
conn->sock->sk->sk_state_change = iscsi_state_change;
conn->old_data_ready = conn->sock->sk->sk_data_ready;
conn->sock->sk->sk_data_ready = iscsi_data_ready;
conn->old_write_space = conn->sock->sk->sk_write_space;
conn->sock->sk->sk_write_space = iscsi_write_space_ready;
write_unlock_bh(&conn->sock->sk->sk_callback_lock);
oldfs = get_fs();
set_fs(get_ds());
conn->sock->ops->setsockopt(conn->sock, SOL_TCP, TCP_NODELAY,
(void __force __user *)&opt, sizeof(opt));
set_fs(oldfs);
if (!reinstating) {
/*
* We will delay full conn serving until all commands in
* replacing connections are done to prevent them from
* spoil our data by writing to them too late.
*/
__iscsi_socket_bind(conn);
} else
TRACE_MGMT_DBG("conn %p is reinstating, delaying enabling it",
conn);
out:
return res;
}
@@ -341,6 +377,19 @@ int conn_free(struct iscsi_conn *conn)
sBUG_ON(!list_empty(&conn->cmd_list));
sBUG_ON(!list_empty(&conn->write_list));
sBUG_ON(!list_empty(&conn->written_list));
sBUG_ON(conn->conn_reinst_successor != NULL);
if (conn->conn_reinstating) {
struct iscsi_conn *c;
TRACE_MGMT_DBG("Freeing being reinstated conn %p", conn);
list_for_each_entry(c, &conn->session->conn_list,
conn_list_entry) {
if (c->conn_reinst_successor == conn) {
c->conn_reinst_successor = NULL;
break;
}
}
}
list_del(&conn->conn_list_entry);
@@ -357,11 +406,14 @@ int conn_free(struct iscsi_conn *conn)
/* target_mutex supposed to be locked */
static int iscsi_conn_alloc(struct iscsi_session *session,
struct conn_info *info)
struct iscsi_kern_conn_info *info, bool reinstating,
struct iscsi_conn **new_conn)
{
struct iscsi_conn *conn;
int res = 0;
reinstating |= session->sess_reinstating;
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
if (!conn) {
res = -ENOMEM;
@@ -380,6 +432,7 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
atomic_set(&conn->conn_ref_cnt, 0);
conn->session = session;
conn->conn_reinstating = reinstating;
conn->cid = info->cid;
conn->stat_sn = info->stat_sn;
conn->exp_stat_sn = info->exp_stat_sn;
@@ -399,14 +452,17 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
INIT_LIST_HEAD(&conn->write_list);
INIT_LIST_HEAD(&conn->written_list);
setup_timer(&conn->rsp_timer, conn_rsp_timer_fn, (unsigned long)conn);
init_completion(&conn->ready_to_free);
conn->file = fget(info->fd);
res = iscsi_socket_bind(conn);
res = iscsi_socket_bind(conn, reinstating);
if (res != 0)
goto out_err_free2;
list_add(&conn->conn_list_entry, &session->conn_list);
list_add_tail(&conn->conn_list_entry, &session->conn_list);
*new_conn = conn;
out:
return res;
@@ -425,20 +481,38 @@ out_err:
}
/* target_mutex supposed to be locked */
int conn_add(struct iscsi_session *session, struct conn_info *info)
int conn_add(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
{
struct iscsi_conn *conn;
int err = -EEXIST;
struct iscsi_conn *conn, *new_conn;
int err;
bool reinstatement = false;
conn = conn_lookup(session, info->cid);
if (conn)
return err;
if (conn != NULL) {
/* conn reinstatement */
reinstatement = true;
} else if (!list_empty(&session->conn_list)) {
err = -EEXIST;
goto out;
}
return iscsi_conn_alloc(session, info);
err = iscsi_conn_alloc(session, info, reinstatement, &new_conn);
if (err != 0)
goto out;
if (reinstatement) {
TRACE_MGMT_DBG("Reinstating conn %p", conn);
conn->conn_reinst_successor = new_conn;
new_conn->conn_reinstating = 1;
__mark_conn_closed(conn, 0);
}
out:
return err;
}
/* target_mutex supposed to be locked */
int conn_del(struct iscsi_session *session, struct conn_info *info)
int conn_del(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
{
struct iscsi_conn *conn;
int err = -EEXIST;

View File

@@ -107,14 +107,14 @@ static int notify(void *data, int len, gfp_t gfp_mask)
int event_send(u32 tid, u64 sid, u32 cid, u32 state, int atomic)
{
int err;
struct iscsi_event event;
struct iscsi_kern_event event;
event.tid = tid;
event.sid = sid;
event.cid = cid;
event.state = state;
err = notify(&event, NLMSG_SPACE(sizeof(struct iscsi_event)), 0);
err = notify(&event, NLMSG_SPACE(sizeof(struct iscsi_kern_event)), 0);
return err;
}

View File

@@ -572,7 +572,7 @@ static void iscsi_cmnd_init_write(struct iscsi_cmnd *rsp, int flags)
list_empty(&rsp->rsp_cmd_list), rsp->hashed);
sBUG();
}
list_add(&rsp->write_list_entry, &head);
list_add_tail(&rsp->write_list_entry, &head);
iscsi_cmnds_init_write(&head, flags);
return;
}
@@ -1638,7 +1638,7 @@ static void __cmnd_abort(struct iscsi_cmnd *cmnd)
return;
}
/* Must be called from the read thread */
/* Must be called from the read or conn close thread */
static int cmnd_abort(struct iscsi_cmnd *req)
{
struct iscsi_session *session = req->conn->session;
@@ -1719,7 +1719,7 @@ out_put:
goto out;
}
/* Must be called from the read thread */
/* Must be called from the read or conn close thread */
static int target_abort(struct iscsi_cmnd *req, int all)
{
struct iscsi_target *target = req->conn->session->target;
@@ -1753,7 +1753,7 @@ static int target_abort(struct iscsi_cmnd *req, int all)
return 0;
}
/* Must be called from the read thread */
/* Must be called from the read or conn close thread */
static void task_set_abort(struct iscsi_cmnd *req)
{
struct iscsi_session *session = req->conn->session;
@@ -1785,7 +1785,7 @@ static void task_set_abort(struct iscsi_cmnd *req)
return;
}
/* Must be called from the read thread */
/* Must be called from the read or conn close thread */
void conn_abort(struct iscsi_conn *conn)
{
struct iscsi_cmnd *cmnd;
@@ -2237,7 +2237,7 @@ void cmnd_tx_end(struct iscsi_cmnd *cmnd)
"initiator's %s request",
cmnd->conn->session->target->tid,
conn->session->initiator_name);
target_del_all_sess(cmnd->conn->session->target, false);
target_del_all_sess(cmnd->conn->session->target, 0);
} else {
PRINT_INFO("Closing connection at initiator's %s "
"request", conn->session->initiator_name);
@@ -2300,6 +2300,8 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
iscsi_cmnd_exec(cmnd);
spin_lock(&session->sn_lock);
if (list_empty(&session->pending_list))
break;
cmnd = list_entry(session->pending_list.next,
@@ -2313,8 +2315,6 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
TRACE_DBG("Processing pending cmd %p (cmd_sn %u)",
cmnd, cmd_sn);
spin_lock(&session->sn_lock);
}
} else {
int drop = 0;
@@ -2377,6 +2377,7 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
PRINT_ERROR("%s", "Unable to create TM clone");
}
spin_lock(&session->sn_lock);
list_for_each(entry, &session->pending_list) {
struct iscsi_cmnd *tmp =
list_entry(entry, struct iscsi_cmnd,
@@ -2384,10 +2385,11 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
if (before(cmd_sn, tmp->pdu.bhs.sn))
break;
}
list_add_tail(&cmnd->pending_list_entry, entry);
cmnd->pending = 1;
}
spin_unlock(&session->sn_lock);
out:
return;
}
@@ -2888,19 +2890,25 @@ static inline int iscsi_get_mgmt_response(int status)
static void iscsi_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd)
{
int fn = scst_mgmt_cmd_get_fn(scst_mcmd);
struct iscsi_cmnd *req = (struct iscsi_cmnd *)
scst_mgmt_cmd_get_tgt_priv(scst_mcmd);
int status =
iscsi_get_mgmt_response(scst_mgmt_cmd_get_status(scst_mcmd));
TRACE_MGMT_DBG("req %p, scst_mcmd %p, fn %d, scst status %d",
req, scst_mcmd, scst_mgmt_cmd_get_fn(scst_mcmd),
scst_mgmt_cmd_get_status(scst_mcmd));
iscsi_send_task_mgmt_resp(req, status);
scst_mgmt_cmd_set_tgt_priv(scst_mcmd, NULL);
req, scst_mcmd, fn, scst_mgmt_cmd_get_status(scst_mcmd));
switch (fn) {
case SCST_NEXUS_LOSS_SESS:
case SCST_ABORT_ALL_TASKS_SESS:
/* They are internal */
break;
default:
iscsi_send_task_mgmt_resp(req, status);
scst_mgmt_cmd_set_tgt_priv(scst_mcmd, NULL);
break;
}
return;
}
@@ -2930,6 +2938,7 @@ struct scst_tgt_template iscsi_template = {
#endif
.preprocessing_done = iscsi_preprocessing_done,
.pre_exec = iscsi_pre_exec,
.task_mgmt_affected_cmds_done = iscsi_task_mgmt_affected_cmds_done,
.task_mgmt_fn_done = iscsi_task_mgmt_fn_done,
};
@@ -2953,7 +2962,7 @@ static __init int iscsi_run_threads(int count, char *name, int (*fn)(void *))
kfree(thr);
goto out;
}
list_add(&thr->threads_list_entry, &iscsi_threads_list);
list_add_tail(&thr->threads_list_entry, &iscsi_threads_list);
}
out:

View File

@@ -88,8 +88,9 @@ struct iscsi_session {
struct iscsi_target *target;
struct scst_session *scst_sess;
/* Both unprotected, since accessed only from a single read thread */
struct list_head pending_list;
struct list_head pending_list; /* protected by sn_lock */
/* Unprotected, since accessed only from a single read thread */
u32 next_ttt;
u32 max_queued_cmnds; /* unprotected, since read-only */
@@ -113,11 +114,12 @@ struct iscsi_session {
struct list_head session_list_entry;
struct completion unreg_compl;
/* All don't need any protection */
struct iscsi_session *sess_reinst_successor;
unsigned int sess_reinstating:1;
/* All don't need any protection */
char *initiator_name;
unsigned int shutting_down:1;
u64 sid;
};
@@ -216,6 +218,12 @@ struct iscsi_conn {
struct list_head conn_list_entry; /* list entry in session conn_list */
/* All don't need any protection */
struct iscsi_conn *conn_reinst_successor;
unsigned int conn_reinstating:1;
struct completion ready_to_free;
/* Doesn't need any protection */
u16 cid;
};
@@ -367,8 +375,9 @@ extern void conn_abort(struct iscsi_conn *conn);
/* conn.c */
extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
extern int conn_add(struct iscsi_session *, struct conn_info *);
extern int conn_del(struct iscsi_session *, struct conn_info *);
extern void __iscsi_socket_bind(struct iscsi_conn *);
extern int conn_add(struct iscsi_session *, struct iscsi_kern_conn_info *);
extern int conn_del(struct iscsi_session *, struct iscsi_kern_conn_info *);
extern int conn_free(struct iscsi_conn *);
#define ISCSI_CONN_ACTIVE_CLOSE 1
@@ -387,12 +396,15 @@ extern void iscsi_put_page_callback(struct page *page);
#endif
extern int istrd(void *arg);
extern int istwr(void *arg);
extern void iscsi_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *scst_mcmd);
/* target.c */
struct iscsi_target *target_lookup_by_id(u32);
extern int target_add(struct target_info *);
extern int target_add(struct iscsi_kern_target_info *);
extern int target_del(u32 id);
extern void target_del_all_sess(struct iscsi_target *target, bool deleting);
extern void target_del_session(struct iscsi_target *target,
struct iscsi_session *session, int flags);
extern void target_del_all_sess(struct iscsi_target *target, int flags);
extern void target_del_all(void);
extern struct seq_operations iscsi_seq_op;
@@ -404,13 +416,14 @@ extern void iscsi_procfs_exit(void);
/* session.c */
extern struct file_operations session_seq_fops;
extern struct iscsi_session *session_lookup(struct iscsi_target *, u64);
extern int session_add(struct iscsi_target *, struct session_info *);
extern void sess_enable_reinstated_sess(struct iscsi_session *);
extern int session_add(struct iscsi_target *, struct iscsi_kern_session_info *);
extern int session_del(struct iscsi_target *, u64);
extern int session_free(struct iscsi_session *session);
/* params.c */
extern int iscsi_param_set(struct iscsi_target *, struct iscsi_param_info *,
int);
extern int iscsi_param_set(struct iscsi_target *,
struct iscsi_kern_param_info *, int);
/* event.c */
extern int event_send(u32, u64, u32, u32, int);

View File

@@ -167,22 +167,6 @@ out:
static inline void iscsi_check_closewait(struct iscsi_conn *conn) {};
#endif
static void iscsi_unreg_cmds_done_fn(struct scst_session *scst_sess)
{
struct iscsi_session *sess =
(struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
TRACE_ENTRY();
TRACE_CONN_CLOSE_DBG("sess %p (scst_sess %p)", sess, scst_sess);
sess->shutting_down = 1;
complete_all(&sess->unreg_compl);
TRACE_EXIT();
return;
}
static void free_pending_commands(struct iscsi_conn *conn)
{
struct iscsi_session *session = conn->session;
@@ -219,6 +203,7 @@ static void free_pending_commands(struct iscsi_conn *conn)
}
} while (req_freed);
spin_unlock(&session->sn_lock);
return;
}
@@ -258,6 +243,7 @@ static void free_orphaned_pending_commands(struct iscsi_conn *conn)
}
} while (req_freed);
spin_unlock(&session->sn_lock);
return;
}
@@ -331,6 +317,42 @@ static void trace_conn_close(struct iscsi_conn *conn)
static void trace_conn_close(struct iscsi_conn *conn) {}
#endif /* CONFIG_SCST_DEBUG */
void iscsi_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *scst_mcmd)
{
int fn = scst_mgmt_cmd_get_fn(scst_mcmd);
void *priv = scst_mgmt_cmd_get_tgt_priv(scst_mcmd);
TRACE_MGMT_DBG("scst_mcmd %p, fn %d, priv %p", scst_mcmd, fn, priv);
switch (fn) {
case SCST_NEXUS_LOSS_SESS:
case SCST_ABORT_ALL_TASKS_SESS:
{
struct iscsi_conn *conn = (struct iscsi_conn *)priv;
struct iscsi_session *sess = conn->session;
mutex_lock(&sess->target->target_mutex);
if (conn->conn_reinst_successor != NULL) {
sBUG_ON(!conn->conn_reinst_successor->conn_reinstating);
__iscsi_socket_bind(conn->conn_reinst_successor);
/* We will check for conn_reinst_successor later */
} else if (sess->sess_reinst_successor != NULL) {
sess_enable_reinstated_sess(sess->sess_reinst_successor);
sess->sess_reinst_successor = NULL;
}
mutex_unlock(&sess->target->target_mutex);
complete_all(&conn->ready_to_free);
break;
}
default:
/* Nothing to do */
break;
}
return;
}
/* No locks */
static void close_conn(struct iscsi_conn *conn)
{
@@ -339,6 +361,7 @@ static void close_conn(struct iscsi_conn *conn)
typeof(jiffies) start_waiting = jiffies;
typeof(jiffies) shut_start_waiting = start_waiting;
bool pending_reported = 0, wait_expired = 0, shut_expired = 0;
bool free_sess;
#define CONN_PENDING_TIMEOUT ((typeof(jiffies))10*HZ)
#define CONN_WAIT_TIMEOUT ((typeof(jiffies))10*HZ)
@@ -362,15 +385,26 @@ static void close_conn(struct iscsi_conn *conn)
RCV_SHUTDOWN|SEND_SHUTDOWN);
}
/*
* We need to call scst_unregister_session() ASAP to make SCST start
* recovering stuck commands.
*
* ToDo: this is incompatible with MC/S
*/
scst_unregister_session_ex(session->scst_sess, 0,
NULL, iscsi_unreg_cmds_done_fn);
session->scst_sess = NULL;
if (conn->conn_reinst_successor != NULL) {
int rc;
int lun = 0;
/* Abort all outstanding commands */
rc = scst_rx_mgmt_fn_lun(session->scst_sess,
SCST_ABORT_ALL_TASKS_SESS, (uint8_t *)&lun, sizeof(lun),
SCST_NON_ATOMIC, conn);
if (rc != 0)
PRINT_ERROR("SCST_ABORT_ALL_TASKS_SESS failed %d", rc);
} else {
int rc;
int lun = 0;
rc = scst_rx_mgmt_fn_lun(session->scst_sess,
SCST_NEXUS_LOSS_SESS, (uint8_t *)&lun, sizeof(lun),
SCST_NON_ATOMIC, conn);
if (rc != 0)
PRINT_ERROR("SCST_NEXUS_LOSS_SESS failed %d", rc);
}
if (conn->read_state != RX_INIT_BHS) {
struct iscsi_cmnd *cmnd = conn->read_cmnd;
@@ -401,18 +435,11 @@ static void close_conn(struct iscsi_conn *conn)
mutex_unlock(&target->target_mutex);
}
/* It's safe to check it without sn_lock */
if (!list_empty(&session->pending_list)) {
TRACE_CONN_CLOSE_DBG("Disposing pending commands on "
"connection %p (conn_ref_cnt=%d)",
conn,
atomic_read(&conn->conn_ref_cnt));
/*
* Such complicated approach currently isn't really
* necessary, but it will be necessary for MC/S, if we
* won't want to reestablish the whole session on a
* connection failure.
*/
"connection %p (conn_ref_cnt=%d)", conn,
atomic_read(&conn->conn_ref_cnt));
free_pending_commands(conn);
@@ -487,18 +514,27 @@ static void close_conn(struct iscsi_conn *conn)
msleep(50);
}
wait_for_completion(&conn->ready_to_free);
TRACE_CONN_CLOSE("Notifying user space about closing connection %p",
conn);
event_send(target->tid, session->sid, conn->cid, E_CONN_CLOSE, 0);
wait_for_completion(&session->unreg_compl);
sBUG_ON(!session->shutting_down);
sBUG_ON(conn->conn_reinstating);
sBUG_ON(session->sess_reinstating);
mutex_lock(&target->target_mutex);
free_sess = (conn->conn_reinst_successor == NULL);
conn_free(conn);
/* ToDo: this is incompatible with MC/S */
session_free(session);
if (free_sess) {
sBUG_ON(session->sess_reinst_successor != NULL);
/* ToDo: this is incompatible with MC/S */
session_free(session);
}
mutex_unlock(&target->target_mutex);
TRACE_EXIT();
@@ -512,6 +548,11 @@ static int close_conn_thr(void *arg)
TRACE_ENTRY();
#ifdef CONFIG_SCST_EXTRACHECKS
/*
* To satisfy iscsi_extracheck_is_rd_thread() in functions called
* on the connection close. It is safe, because at this point conn
* can't be used by any other thread.
*/
conn->rd_task = current;
#endif
close_conn(conn);

View File

@@ -92,7 +92,7 @@ static void log_params(struct iscsi_sess_param *param)
}
/* target_mutex supposed to be locked */
static void sess_param_check(struct iscsi_param_info *info)
static void sess_param_check(struct iscsi_kern_param_info *info)
{
int32_t *iparam = info->session_param;
@@ -114,7 +114,7 @@ static void sess_param_check(struct iscsi_param_info *info)
/* target_mutex supposed to be locked */
static void sess_param_set(struct iscsi_sess_param *param,
struct iscsi_param_info *info)
struct iscsi_kern_param_info *info)
{
int32_t *iparam = info->session_param;
@@ -140,7 +140,7 @@ static void sess_param_set(struct iscsi_sess_param *param,
}
static void sess_param_get(struct iscsi_sess_param *param,
struct iscsi_param_info *info)
struct iscsi_kern_param_info *info)
{
int32_t *iparam = info->session_param;
@@ -166,7 +166,7 @@ static void sess_param_get(struct iscsi_sess_param *param,
}
/* target_mutex supposed to be locked */
static void trgt_param_check(struct iscsi_param_info *info)
static void trgt_param_check(struct iscsi_kern_param_info *info)
{
int32_t *iparam = info->target_param;
@@ -176,7 +176,7 @@ static void trgt_param_check(struct iscsi_param_info *info)
/* target_mutex supposed to be locked */
static void trgt_param_set(struct iscsi_target *target,
struct iscsi_param_info *info)
struct iscsi_kern_param_info *info)
{
struct iscsi_trgt_param *param = &target->trgt_param;
int32_t *iparam = info->target_param;
@@ -186,7 +186,7 @@ static void trgt_param_set(struct iscsi_target *target,
/* target_mutex supposed to be locked */
static void trgt_param_get(struct iscsi_trgt_param *param,
struct iscsi_param_info *info)
struct iscsi_kern_param_info *info)
{
int32_t *iparam = info->target_param;
@@ -195,7 +195,7 @@ static void trgt_param_get(struct iscsi_trgt_param *param,
/* target_mutex supposed to be locked */
static int trgt_param(struct iscsi_target *target,
struct iscsi_param_info *info, int set)
struct iscsi_kern_param_info *info, int set)
{
if (set) {
struct iscsi_trgt_param *prm;
@@ -213,7 +213,7 @@ static int trgt_param(struct iscsi_target *target,
/* target_mutex supposed to be locked */
static int sess_param(struct iscsi_target *target,
struct iscsi_param_info *info, int set)
struct iscsi_kern_param_info *info, int set)
{
struct iscsi_session *session = NULL;
struct iscsi_sess_param *param;
@@ -247,8 +247,8 @@ out:
}
/* target_mutex supposed to be locked */
int iscsi_param_set(struct iscsi_target *target, struct iscsi_param_info *info,
int set)
int iscsi_param_set(struct iscsi_target *target,
struct iscsi_kern_param_info *info, int set)
{
int err;

View File

@@ -23,7 +23,7 @@ struct iscsi_session *session_lookup(struct iscsi_target *target, u64 sid)
list_for_each_entry(session, &target->session_list,
session_list_entry) {
if ((session->sid == sid) && !session->shutting_down)
if (session->sid == sid)
return session;
}
return NULL;
@@ -31,7 +31,7 @@ struct iscsi_session *session_lookup(struct iscsi_target *target, u64 sid)
/* target_mutex supposed to be locked */
static int iscsi_session_alloc(struct iscsi_target *target,
struct session_info *info)
struct iscsi_kern_session_info *info, struct iscsi_session **result)
{
int err;
unsigned int i;
@@ -93,14 +93,15 @@ static int iscsi_session_alloc(struct iscsi_target *target,
kfree(name);
scst_sess_set_tgt_priv(session->scst_sess, session);
init_completion(&session->unreg_compl);
list_add(&session->session_list_entry, &target->session_list);
list_add_tail(&session->session_list_entry, &target->session_list);
TRACE_MGMT_DBG("Session %p created: target %p, tid %u, sid %#Lx",
session, target, target->tid, info->sid);
*result = session;
return 0;
err:
if (session) {
kfree(session->initiator_name);
@@ -111,20 +112,89 @@ err:
}
/* target_mutex supposed to be locked */
int session_add(struct iscsi_target *target, struct session_info *info)
void sess_enable_reinstated_sess(struct iscsi_session *sess)
{
struct iscsi_session *session;
int err = -EEXIST;
struct iscsi_conn *c;
TRACE_ENTRY();
TRACE_MGMT_DBG("Enabling reinstate successor sess %p", sess);
sBUG_ON(!sess->sess_reinstating);
list_for_each_entry(c, &sess->conn_list, conn_list_entry) {
__iscsi_socket_bind(c);
}
sess->sess_reinstating = 0;
TRACE_EXIT();
return;
}
/* target_mutex supposed to be locked */
static void session_reinstate(struct iscsi_session *old_sess,
struct iscsi_session *new_sess)
{
TRACE_ENTRY();
TRACE_MGMT_DBG("Reinstating sess %p with SID %llx (old %p, SID %llx)",
new_sess, new_sess->sid, old_sess, old_sess->sid);
new_sess->sess_reinstating = 1;
old_sess->sess_reinst_successor = new_sess;
scst_set_initial_UA(new_sess->scst_sess,
SCST_LOAD_SENSE(scst_sense_nexus_loss_UA));
target_del_session(old_sess->target, old_sess, 0);
TRACE_EXIT();
return;
}
/* target_mutex supposed to be locked */
int session_add(struct iscsi_target *target,
struct iscsi_kern_session_info *info)
{
struct iscsi_session *session, *old_sess;
int err = 0;
union iscsi_sid sid;
TRACE_MGMT_DBG("Adding session SID %llx", info->sid);
session = session_lookup(target, info->sid);
if (session) {
PRINT_ERROR("Attempt to add session with existing SID %llx",
info->sid);
return err;
err = -EEXIST;
goto out;
}
sid = (union iscsi_sid)info->sid;
sid.id.tsih = 0;
old_sess = NULL;
/*
* We need to find the latest session to correctly handle
* multi-reinstatements
*/
list_for_each_entry_reverse(session, &target->session_list,
session_list_entry) {
union iscsi_sid i = (union iscsi_sid)session->sid;
i.id.tsih = 0;
if ((sid.id64 == i.id64) &&
(strcmp(info->initiator_name, session->initiator_name) == 0)) {
/* session reinstatement */
old_sess = session;
break;
}
}
err = iscsi_session_alloc(target, info);
err = iscsi_session_alloc(target, info, &session);
if ((err == 0) && (old_sess != NULL))
session_reinstate(old_sess, session);
out:
return err;
}
@@ -133,8 +203,8 @@ int session_free(struct iscsi_session *session)
{
unsigned int i;
TRACE_MGMT_DBG("Freeing session %p:%#Lx",
session, (long long unsigned int)session->sid);
TRACE_MGMT_DBG("Freeing session %p (SID %llx)",
session, session->sid);
sBUG_ON(!list_empty(&session->conn_list));
if (unlikely(atomic_read(&session->active_cmds) != 0)) {
@@ -149,6 +219,21 @@ int session_free(struct iscsi_session *session)
if (session->scst_sess != NULL)
scst_unregister_session(session->scst_sess, 1, NULL);
if (session->sess_reinst_successor != NULL)
sess_enable_reinstated_sess(session->sess_reinst_successor);
if (session->sess_reinstating) {
struct iscsi_session *s;
TRACE_MGMT_DBG("Freeing being reinstated sess %p", session);
list_for_each_entry(s, &session->target->session_list,
session_list_entry) {
if (s->sess_reinst_successor == session) {
s->sess_reinst_successor = NULL;
break;
}
}
}
list_del(&session->session_list_entry);
kfree(session->initiator_name);
@@ -183,10 +268,10 @@ static void iscsi_session_info_show(struct seq_file *seq,
list_for_each_entry(session, &target->session_list,
session_list_entry) {
seq_printf(seq, "\tsid:%llx initiator:%s shutting down %d\n",
seq_printf(seq, "\tsid:%llx initiator:%s reinstating %d\n",
(long long unsigned int)session->sid,
session->initiator_name,
session->shutting_down);
session->sess_reinstating);
conn_info_show(seq, session);
}
return;

View File

@@ -28,32 +28,6 @@ static LIST_HEAD(target_list);
static u32 next_target_id;
static u32 nr_targets;
static struct iscsi_sess_param default_session_param = {
.initial_r2t = 1,
.immediate_data = 1,
.max_connections = 1,
.max_recv_data_length = 8192,
.max_xmit_data_length = 8192,
.max_burst_length = 262144,
.first_burst_length = 65536,
.default_wait_time = 2,
.default_retain_time = 20,
.max_outstanding_r2t = 1,
.data_pdu_inorder = 1,
.data_sequence_inorder = 1,
.error_recovery_level = 0,
.header_digest = DIGEST_NONE,
.data_digest = DIGEST_NONE,
.ofmarker = 0,
.ifmarker = 0,
.ofmarkint = 2048,
.ifmarkint = 2048,
};
static struct iscsi_trgt_param default_target_param = {
.queued_cmnds = DEFAULT_NR_QUEUED_CMNDS,
};
/* target_mgmt_mutex supposed to be locked */
struct iscsi_target *target_lookup_by_id(u32 id)
{
@@ -79,7 +53,7 @@ static struct iscsi_target *target_lookup_by_name(char *name)
}
/* target_mgmt_mutex supposed to be locked */
static int iscsi_target_create(struct target_info *info, u32 tid)
static int iscsi_target_create(struct iscsi_kern_target_info *info, u32 tid)
{
int err = -EINVAL, len;
char *name = info->name;
@@ -106,11 +80,6 @@ static int iscsi_target_create(struct target_info *info, u32 tid)
target->tid = info->tid = tid;
memcpy(&target->trgt_sess_param, &default_session_param,
sizeof(default_session_param));
memcpy(&target->trgt_param, &default_target_param,
sizeof(default_target_param));
strncpy(target->name, name, sizeof(target->name) - 1);
mutex_init(&target->target_mutex);
@@ -123,7 +92,7 @@ static int iscsi_target_create(struct target_info *info, u32 tid)
goto out_free;
}
list_add(&target->target_list_entry, &target_list);
list_add_tail(&target->target_list_entry, &target_list);
return 0;
@@ -138,7 +107,7 @@ out:
}
/* target_mgmt_mutex supposed to be locked */
int target_add(struct target_info *info)
int target_add(struct iscsi_kern_target_info *info)
{
int err = -EEXIST;
u32 tid = info->tid;
@@ -215,15 +184,13 @@ out:
return err;
}
static void target_del_session(struct iscsi_target *target,
struct iscsi_session *session, bool deleting)
void target_del_session(struct iscsi_target *target,
struct iscsi_session *session, int flags)
{
int flags = ISCSI_CONN_ACTIVE_CLOSE;
TRACE_ENTRY();
if (deleting)
flags |= ISCSI_CONN_DELETING;
TRACE_MGMT_DBG("Deleting session %p", session);
TRACE_MGMT_DBG("Cleaning up session %p", session);
if (!list_empty(&session->conn_list)) {
struct iscsi_conn *conn, *tc;
list_for_each_entry_safe(conn, tc, &session->conn_list,
@@ -236,10 +203,13 @@ static void target_del_session(struct iscsi_target *target,
session);
session_del(target, session->sid);
}
TRACE_EXIT();
return;
}
/* target_mutex supposed to be locked */
void target_del_all_sess(struct iscsi_target *target, bool deleting)
void target_del_all_sess(struct iscsi_target *target, int flags)
{
struct iscsi_session *session, *ts;
@@ -249,7 +219,7 @@ void target_del_all_sess(struct iscsi_target *target, bool deleting)
TRACE_MGMT_DBG("Deleting all sessions from target %p", target);
list_for_each_entry_safe(session, ts, &target->session_list,
session_list_entry) {
target_del_session(target, session, deleting);
target_del_session(target, session, flags);
}
}
@@ -276,7 +246,9 @@ void target_del_all(void)
target_list_entry) {
mutex_lock(&target->target_mutex);
if (!list_empty(&target->session_list)) {
target_del_all_sess(target, true);
target_del_all_sess(target,
ISCSI_CONN_ACTIVE_CLOSE |
ISCSI_CONN_DELETING);
mutex_unlock(&target->target_mutex);
} else {
TRACE_MGMT_DBG("Deleting target %p", target);

View File

@@ -21,8 +21,11 @@ OBJS_D = $(SRCS_D:.c=.o)
SRCS_ADM = iscsi_adm.c param.c
OBJS_ADM = $(SRCS_ADM:.c=.o)
CFLAGS += -O2 -fno-inline -Wall -Wstrict-prototypes -g -I../include
CFLAGS += -O2 -fno-inline -Wall -Wextra -Wstrict-prototypes -Wno-sign-compare \
-Werror=implicit-function-declaration -Wno-unused-parameter \
-Wno-missing-field-initializers -g -I../include
CFLAGS += -D_GNU_SOURCE # required for glibc >= 2.8
PROGRAMS = iscsi-scstd iscsi-scst-adm
LIBS = -lcrypto

View File

@@ -31,101 +31,46 @@ struct connection *conn_alloc(void)
{
struct connection *conn;
if (!(conn = malloc(sizeof(*conn))))
return NULL;
conn = malloc(sizeof(*conn));
if (conn == NULL)
goto out;
memset(conn, 0, sizeof(*conn));
conn->state = STATE_FREE;
param_set_defaults(conn->session_param, session_keys);
INIT_LIST_HEAD(&conn->rsp_buf_list);
out:
return conn;
}
void conn_free(struct connection *conn)
{
remque(&conn->clist);
free(conn->initiator);
free(conn->user);
free(conn);
return;
}
int conn_test(struct connection *conn)
{
FILE *f;
char buf[8192], *p;
u32 tid, t_tid, cid, t_cid;
u64 sid, t_sid;
int err = -ENOENT, find = 0;
t_tid = conn->tid;
t_sid = conn->session->sid.id64;
t_cid = conn->cid;
if ((f = fopen(PROC_SESSION, "r")) == NULL) {
fprintf(stderr, "Can't open %s\n", PROC_SESSION);
return -errno;
}
while (fgets(buf, sizeof(buf), f)) {
p = buf;
while (isspace((int) *p))
p++;
if (!strncmp(p, "tid:", 4)) {
if (sscanf(p, "tid:%u", &tid) != 1) {
err = -EIO;
goto out;
}
if (tid == t_tid)
find = 1;
else
find = 0;
} else if (!strncmp(p, "sid:", 4)) {
if (!find)
continue;
if (sscanf(p, "sid:%" SCNu64, &sid) != 1) {
err = -EIO;
goto out;
}
if (sid == t_sid)
find = 1;
else
find = 0;
} else if (!strncmp(p, "cid:", 4)) {
if (!find)
continue;
if (sscanf(p, "cid:%u", &cid) != 1) {
err = -EIO;
goto out;
}
if (cid == t_cid) {
err = 0;
goto out;
}
}
}
out:
fclose(f);
return err;
}
void conn_take_fd(struct connection *conn, int fd)
void conn_pass_to_kern(struct connection *conn, int fd)
{
int err;
log_debug(1, "conn_take_fd: %d %u %u %u %" PRIx64,
fd, conn->cid, conn->stat_sn, conn->exp_stat_sn, conn->sid.id64);
conn->session->conn_cnt++;
log_debug(1, "fd %d, cid %u, stat_sn %u, exp_stat_sn %u sid%" PRIx64,
fd, conn->cid, conn->stat_sn, conn->exp_stat_sn, conn->sid.id64);
err = ki->conn_create(conn->tid, conn->session->sid.id64, conn->cid,
err = kernel_conn_create(conn->tid, conn->sess->sid.id64, conn->cid,
conn->stat_sn, conn->exp_stat_sn, fd,
conn->session_param[key_header_digest].val,
conn->session_param[key_data_digest].val);
if (err == 0)
conn->sess->kern_conn_cnt++;
else
log_error("kernel_conn_create() failed: %s", strerror(errno));
/* We don't need to return err, because we are going to close conn anyway */
return;
}
@@ -134,6 +79,7 @@ void conn_read_pdu(struct connection *conn)
conn->iostate = IOSTATE_READ_BHS;
conn->buffer = (void *)&conn->req.bhs;
conn->rwsize = BHS_SIZE;
return;
}
void conn_write_pdu(struct connection *conn)
@@ -142,6 +88,7 @@ void conn_write_pdu(struct connection *conn)
memset(&conn->rsp, 0, sizeof(conn->rsp));
conn->buffer = (void *)&conn->rsp.bhs;
conn->rwsize = BHS_SIZE;
return;
}
void conn_free_rsp_buf_list(struct connection *conn)
@@ -155,6 +102,7 @@ void conn_free_rsp_buf_list(struct connection *conn)
conn->rsp.datasize = 0;
conn->rsp.data = NULL;
return;
}
void conn_free_pdu(struct connection *conn)
@@ -169,4 +117,5 @@ void conn_free_pdu(struct connection *conn)
conn->rsp.ahs = NULL;
}
conn_free_rsp_buf_list(conn);
return;
}

View File

@@ -34,7 +34,7 @@ struct session_file_operations {
int (*connection_op) (int fd, u32 tid, u64 sid, u32 cid, void *arg);
};
static int ctrdev_open(int *max_data_seg_len)
int kernel_open(int *max_data_seg_len)
{
FILE *f;
char devname[256];
@@ -42,7 +42,7 @@ static int ctrdev_open(int *max_data_seg_len)
int devn;
int ctlfd = -1;
int err;
struct iscsi_register_info reg = { 0 };
struct iscsi_kern_register_info reg = { 0 };
if (!(f = fopen("/proc/devices", "r"))) {
perror("Cannot open control path to the driver");
@@ -104,10 +104,10 @@ out_close:
goto out;
}
static int iscsi_target_create(u32 *tid, char *name)
int kernel_target_create(u32 *tid, char *name)
{
int err;
struct target_info info;
struct iscsi_kern_target_info info;
memset(&info, 0, sizeof(info));
@@ -122,9 +122,9 @@ static int iscsi_target_create(u32 *tid, char *name)
return err;
}
static int iscsi_target_destroy(u32 tid)
int kernel_target_destroy(u32 tid)
{
struct target_info info;
struct iscsi_kern_target_info info;
int res;
memset(&info, 0, sizeof(info));
@@ -137,10 +137,10 @@ static int iscsi_target_destroy(u32 tid)
return res;
}
static int iscsi_conn_destroy(u32 tid, u64 sid, u32 cid)
int kernel_conn_destroy(u32 tid, u64 sid, u32 cid)
{
int err;
struct conn_info info;
struct iscsi_kern_conn_info info;
info.tid = tid;
info.sid = sid;
@@ -152,173 +152,14 @@ static int iscsi_conn_destroy(u32 tid, u64 sid, u32 cid)
return err;
}
static int __conn_close(int fd, u32 tid, u64 sid, u32 cid, void *arg)
{
return ki->conn_destroy(tid, sid, cid);
}
static int __target_del(int fd, u32 tid, void *arg)
{
return ki->target_destroy(tid);
}
static int proc_session_parse(int fd, struct session_file_operations *ops,
int op_tid, void *arg)
{
FILE *f;
char buf[8192], *p;
u32 tid, cid;
u64 sid;
int err, skip, done = 0;
if ((f = fopen(PROC_SESSION, "r")) == NULL) {
fprintf(stderr, "Can't open %s\n", PROC_SESSION);
return errno;
}
skip = 0;
while (fgets(buf, sizeof(buf), f)) {
p = buf;
while (isspace((int) *p))
p++;
if (!strncmp(p, "tid:", 4)) {
if (sscanf(p, "tid:%u", &tid) != 1)
break;
if (op_tid != -1) {
if (tid == op_tid)
skip = 0;
else {
skip = 1;
if (done)
break;
else
continue;
}
}
if (ops->target_op)
if ((err = ops->target_op(fd, tid, arg)) < 0)
goto out;
continue;
}
if (skip)
continue;
if (!strncmp(p, "sid:", 4)) {
if (sscanf(p, "sid:%" SCNu64, &sid) != 1) {
log_error("Unknown %s sid syntax: %s\n", PROC_SESSION, p);
break;
}
if (ops->session_op)
if ((err = ops->session_op(fd, tid, sid, arg)) < 0)
goto out;
} else if (!strncmp(p, "cid:", 4)) {
if (sscanf(p, "cid:%u", &cid) != 1) {
log_error("Unknown %s cid syntax: %s\n", PROC_SESSION, p);
break;
}
if (ops->connection_op)
if ((err = ops->connection_op(fd, tid, sid, cid, arg)) < 0)
goto out;
} else
log_error("Unknown %s string: %s\n", PROC_SESSION, p);
done = 1;
}
err = 0;
out:
fclose(f);
return err;
}
static int session_retry (int fd, u32 tid, u64 sid, void *arg)
{
return -EAGAIN;
}
static int conn_retry (int fd, u32 tid, u64 sid, u32 cid, void *arg)
{
return -EAGAIN;
}
static int __sess_cleanup(int fd, u32 tid, void *arg)
{
wait_4_iscsi_event(100);
return 0;
}
static struct session_file_operations conn_close_ops = {
.connection_op = __conn_close,
};
static struct session_file_operations conn_sess_cleanup_ops = {
.target_op = __sess_cleanup,
};
static struct session_file_operations shutdown_wait_ops = {
.session_op = session_retry,
.connection_op = conn_retry,
};
static struct session_file_operations target_del_ops = {
.target_op = __target_del,
};
int target_destroy(u32 tid)
{
int err;
conn_blocked = 1;
proc_session_parse(ctrl_fd, &conn_close_ops, tid, NULL);
while (proc_session_parse(ctrl_fd, &shutdown_wait_ops, tid, NULL) < 0) {
sleep(1);
}
proc_session_parse(ctrl_fd, &conn_sess_cleanup_ops, tid, NULL);
err = proc_session_parse(ctrl_fd, &target_del_ops, tid, NULL);
conn_blocked = 0;
return err;
}
struct session_conn_close_arg {
u64 sid;
};
static int session_conn_close(int fd, u32 tid, u64 sid, u32 cid, void *opaque)
{
struct session_conn_close_arg *arg = (struct session_conn_close_arg *) opaque;
int err;
if (arg->sid == sid)
err = ki->conn_destroy(tid, sid, cid);
return 0;
}
struct session_file_operations session_conns_close_ops = {
.connection_op = session_conn_close,
};
int session_conns_close(u32 tid, u64 sid)
{
int err;
struct session_conn_close_arg arg = {sid};
err = proc_session_parse(ctrl_fd, &session_conns_close_ops, tid, &arg);
return err;
}
static int iscsi_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param)
int kernel_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param)
{
int err, i;
struct iscsi_param_info info;
struct iscsi_kern_param_info info;
memset(&info, 0, sizeof(info));
info.tid = tid;
@@ -341,11 +182,11 @@ static int iscsi_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param
return err;
}
static int iscsi_param_set(u32 tid, u64 sid, int type, u32 partial,
int kernel_param_set(u32 tid, u64 sid, int type, u32 partial,
struct iscsi_param *param)
{
int i, err;
struct iscsi_param_info info;
struct iscsi_kern_param_info info;
memset(&info, 0, sizeof(info));
info.tid = tid;
@@ -369,10 +210,10 @@ static int iscsi_param_set(u32 tid, u64 sid, int type, u32 partial,
return err;
}
static int iscsi_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
int kernel_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
char *name, char *user)
{
struct session_info info;
struct iscsi_kern_session_info info;
int res;
memset(&info, 0, sizeof(info));
@@ -390,9 +231,9 @@ static int iscsi_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
return res;
}
static int iscsi_session_destroy(u32 tid, u64 sid)
int kernel_session_destroy(u32 tid, u64 sid)
{
struct session_info info;
struct iscsi_kern_session_info info;
int res;
memset(&info, 0, sizeof(info));
@@ -410,10 +251,10 @@ static int iscsi_session_destroy(u32 tid, u64 sid)
return res;
}
static int iscsi_conn_create(u32 tid, u64 sid, u32 cid, u32 stat_sn, u32 exp_stat_sn,
int kernel_conn_create(u32 tid, u64 sid, u32 cid, u32 stat_sn, u32 exp_stat_sn,
int fd, u32 hdigest, u32 ddigest)
{
struct conn_info info;
struct iscsi_kern_conn_info info;
int res;
memset(&info, 0, sizeof(info));
@@ -433,17 +274,3 @@ static int iscsi_conn_create(u32 tid, u64 sid, u32 cid, u32 stat_sn, u32 exp_sta
return res;
}
struct iscsi_kernel_interface ioctl_ki = {
.ctldev_open = ctrdev_open,
.param_get = iscsi_param_get,
.param_set = iscsi_param_set,
.target_create = iscsi_target_create,
.target_destroy = iscsi_target_destroy,
.session_create = iscsi_session_create,
.session_destroy = iscsi_session_destroy,
.conn_create = iscsi_conn_create,
.conn_destroy = iscsi_conn_destroy,
};
struct iscsi_kernel_interface *ki = &ioctl_ki;

View File

@@ -80,7 +80,7 @@ static int nl_read(int fd, void *data, int len)
void handle_iscsi_events(int fd)
{
struct session *session;
struct iscsi_event event;
struct iscsi_kern_event event;
int res;
retry:
@@ -103,8 +103,9 @@ retry:
goto retry;
}
if (!--session->conn_cnt)
session_remove(session);
session->kern_conn_cnt--;
if ((session->kern_conn_cnt == 0) && list_empty(&session->conn_list))
session_free(session);
break;
default:
log_warning("%s(%d) %u\n", __FUNCTION__, __LINE__, event.state);

View File

@@ -208,39 +208,75 @@ static void create_listen_socket(struct pollfd *array)
static void accept_connection(int listen)
{
struct sockaddr_storage from;
struct sockaddr_storage from, to;
char portal[50]; /* for full IP6 address + port */
socklen_t namesize;
struct pollfd *pollfd;
struct connection *conn;
int fd, i;
int fd, i, rc;
namesize = sizeof(from);
if ((fd = accept(listen, (struct sockaddr *) &from, &namesize)) < 0) {
if (errno != EINTR && errno != EAGAIN) {
if ((fd = accept(listen, (struct sockaddr *)&from, &namesize)) < 0) {
switch (errno) {
case EINTR:
case EAGAIN:
case ENETDOWN:
case EPROTO:
case ENOPROTOOPT:
case EHOSTDOWN:
case ENONET:
case EHOSTUNREACH:
case EOPNOTSUPP:
case ENETUNREACH:
break;
default:
perror("accept(incoming_socket) failed");
exit(1);
}
return;
goto out;
}
namesize = sizeof(to);
rc = getsockname(fd, (struct sockaddr *)&to, &namesize);
if (rc == 0) {
if (from.ss_family == AF_INET) {
struct sockaddr_in *in = (struct sockaddr_in *)&to;
rc = snprintf(portal, sizeof(portal), "%s:%hu",
inet_ntoa(in->sin_addr), ntohs(in->sin_port));
} else if (from.ss_family == AF_INET6) {
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&to;
rc = snprintf(portal, sizeof(portal), "%x:%x:%x:%x:%x:%x:%x:%x.%hu",
in6->sin6_addr.s6_addr16[7], in6->sin6_addr.s6_addr16[6],
in6->sin6_addr.s6_addr16[5], in6->sin6_addr.s6_addr16[4],
in6->sin6_addr.s6_addr16[3], in6->sin6_addr.s6_addr16[2],
in6->sin6_addr.s6_addr16[1], in6->sin6_addr.s6_addr16[0],
ntohs(in6->sin6_port));
}
if (rc >= sizeof(portal))
log_error("portal too small %zu (needed %d)", sizeof(portal), rc);
} else {
portal[0] = '\0';
perror("getsockname() failed");
goto out_close;
}
if (from.ss_family == AF_INET) {
struct sockaddr_in *in = (struct sockaddr_in *)&from;
log_info("Connect from %s:%hu", inet_ntoa(in->sin_addr),
ntohs(in->sin_port));
log_info("Connect from %s:%hu to %s", inet_ntoa(in->sin_addr),
ntohs(in->sin_port), portal);
} else if (from.ss_family == AF_INET6) {
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&from;
log_info("Connect from %x:%x:%x:%x:%x:%x:%x:%x.%hu",
log_info("Connect from %x:%x:%x:%x:%x:%x:%x:%x.%hu to %s",
in6->sin6_addr.s6_addr16[7], in6->sin6_addr.s6_addr16[6],
in6->sin6_addr.s6_addr16[5], in6->sin6_addr.s6_addr16[4],
in6->sin6_addr.s6_addr16[3], in6->sin6_addr.s6_addr16[2],
in6->sin6_addr.s6_addr16[1], in6->sin6_addr.s6_addr16[0],
ntohs(in6->sin6_port));
ntohs(in6->sin6_port), portal);
}
if (conn_blocked) {
log_warning("A connection refused\n");
close(fd);
return;
log_warning("Connection refused due to blocking\n");
goto out_close;
}
for (i = 0; i < INCOMING_MAX; i++) {
@@ -248,14 +284,15 @@ static void accept_connection(int listen)
break;
}
if (i >= INCOMING_MAX) {
log_error("unable to find incoming slot? %d\n", i);
exit(1);
log_error("Unable to find incoming slot? %d\n", i);
goto out_close;
}
if (!(conn = conn_alloc())) {
log_error("fail to allocate %s", "conn\n");
exit(1);
log_error("Fail to allocate %s", "conn\n");
goto out_close;
}
conn->fd = fd;
incoming[i] = conn;
conn_read_pdu(conn);
@@ -269,6 +306,13 @@ static void accept_connection(int listen)
incoming_cnt++;
if (incoming_cnt >= INCOMING_MAX)
poll_array[POLL_LISTEN].events = 0;
out:
return;
out_close:
close(fd);
goto out;
}
static void __set_fd(int idx, int fd)
@@ -396,7 +440,7 @@ static void event_conn(struct connection *conn, struct pollfd *pollfd)
switch (conn->state) {
case STATE_KERNEL:
conn_take_fd(conn, pollfd->fd);
conn_pass_to_kern(conn, pollfd->fd);
conn->state = STATE_CLOSE;
break;
case STATE_EXIT:
@@ -522,7 +566,7 @@ static void event_loop(int timeout)
event_conn(conn, pollfd);
if (conn->state == STATE_CLOSE) {
log_debug(0, "connection closed");
log_debug(0, "closing conn %p", conn);
conn_free_pdu(conn);
conn_free(conn);
close(pollfd->fd);
@@ -536,33 +580,33 @@ static void event_loop(int timeout)
void init_max_data_seg_len(int max_data_seg_len)
{
if ((session_keys[3].local_def != -1) ||
(session_keys[3].max != -1) ||
(session_keys[4].local_def != -1) ||
(session_keys[4].max != -1) ||
(session_keys[5].local_def != -1) ||
(session_keys[5].max != -1) ||
(session_keys[6].local_def != -1) ||
(session_keys[6].max != -1)) {
if ((session_keys[key_max_recv_data_length].local_def != -1) ||
(session_keys[key_max_recv_data_length].max != -1) ||
(session_keys[key_max_xmit_data_length].local_def != -1) ||
(session_keys[key_max_xmit_data_length].max != -1) ||
(session_keys[key_max_burst_length].local_def != -1) ||
(session_keys[key_max_burst_length].max != -1) ||
(session_keys[key_first_burst_length].local_def != -1) ||
(session_keys[key_first_burst_length].max != -1)) {
log_error("Wrong session_keys initialization");
exit(-1);
}
/* MaxRecvDataSegmentLength */
session_keys[3].local_def = max_data_seg_len;
session_keys[3].max = max_data_seg_len;
session_keys[key_max_recv_data_length].local_def = max_data_seg_len;
session_keys[key_max_recv_data_length].max = max_data_seg_len;
/* MaxXmitDataSegmentLength */
session_keys[4].local_def = max_data_seg_len;
session_keys[4].max = max_data_seg_len;
session_keys[key_max_xmit_data_length].local_def = max_data_seg_len;
session_keys[key_max_xmit_data_length].max = max_data_seg_len;
/* MaxBurstLength */
session_keys[5].local_def = max_data_seg_len;
session_keys[5].max = max_data_seg_len;
session_keys[key_max_burst_length].local_def = max_data_seg_len;
session_keys[key_max_burst_length].max = max_data_seg_len;
/* FirstBurstLength */
session_keys[6].local_def = max_data_seg_len;
session_keys[6].max = max_data_seg_len;
session_keys[key_first_burst_length].local_def = max_data_seg_len;
session_keys[key_first_burst_length].max = max_data_seg_len;
return;
}
@@ -607,6 +651,10 @@ int main(int argc, char **argv)
break;
case 'a':
server_address = strdup(optarg);
if (server_address == NULL) {
perror("strdup failed");
exit(-1);
}
break;
case 'p':
server_port = (uint16_t)strtoul(optarg, NULL, 0);
@@ -629,7 +677,7 @@ int main(int argc, char **argv)
exit(-1);
};
if ((ctrl_fd = ki->ctldev_open(&max_data_seg_len)) < 0)
if ((ctrl_fd = kernel_open(&max_data_seg_len)) < 0)
exit(-1);
init_max_data_seg_len(max_data_seg_len);

View File

@@ -241,44 +241,82 @@ static void text_scan_security(struct connection *conn)
rsp->status_detail = ISCSI_STATUS_AUTH_FAILED;
conn->state = STATE_EXIT;
}
return;
}
static void login_security_done(struct connection *conn)
static int login_check_reinstatement(struct connection *conn)
{
int err;
struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
struct session *session;
int res = 0;
if (!conn->tid)
return;
/*
* We only check here to catch errors earlier. Actual session/connection
* reinstatement, if necessary, will be done in the kernel.
*/
if ((session = session_find_name(conn->tid, conn->initiator, req->sid))) {
if (!req->sid.id.tsih) {
/* do session reinstatement */
session_conns_close(conn->tid, session->sid.id64);
session = NULL;
sBUG_ON(conn->sess != NULL);
session = session_find_name(conn->tid, conn->initiator, req->sid);
if (session != NULL) {
if (req->sid.id.tsih == 0) {
/* Kernel will do session reinstatement */
log_debug(1, "Session sid %#" PRIx64 " reinstatement "
"detected (tid %d, initiator %s)", req->sid.id64,
conn->tid, conn->initiator);
} else if (req->sid.id.tsih != session->sid.id.tsih) {
/* fail the login */
log_error("TSIH for existing session sid %#" PRIx64
") doesn't match (tid %d, initiator %s, sid requested "
"%#" PRIx64, session->sid.id64, conn->tid,
conn->initiator, req->sid.id64);
/* Fail the login */
rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
rsp->status_detail = ISCSI_STATUS_SESSION_NOT_FOUND;
conn->state = STATE_EXIT;
return;
} else if ((err = conn_test(conn)) == -ENOENT) {
/* do connection reinstatement */
res = -1;
goto out;
} else {
struct connection *c = conn_find(session, conn->cid);
if (c != NULL) {
/* Kernel will do connection reinstatement */
log_debug(1, "Conn %x reinstatement "
"detected (tid %d, sid %#" PRIx64
"initiator %s)", conn->cid, conn->tid,
req->sid.id64, conn->initiator);
conn->sess = session;
insque(&conn->clist, &session->conn_list);
} else {
log_error("Only a single connection supported "
"(initiator %s)", conn->initiator);
/* Fail the login */
rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
rsp->status_detail = ISCSI_STATUS_TOO_MANY_CONN;
conn->state = STATE_EXIT;
res = -1;
goto out;
}
}
/* add a new connection to the session */
conn->session = session;
} else {
if (req->sid.id.tsih) {
/* fail the login */
if (req->sid.id.tsih != 0) {
log_error("Requested TSIH not 0 (TSIH %d, tid %d, "
"initiator %s, sid requisted %#" PRIx64 ")",
req->sid.id.tsih, conn->tid, conn->initiator,
req->sid.id64);
/* Fail the login */
rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
rsp->status_detail = ISCSI_STATUS_SESSION_NOT_FOUND;
conn->state = STATE_EXIT;
return;
}
/* instantiate a new session */
res = -1;
goto out;
} else
log_debug(1, "New session sid %#" PRIx64 "(tid %d, "
"initiator %s)", req->sid.id64,
conn->tid, conn->initiator);
}
out:
return res;
}
static void text_scan_login(struct connection *conn)
@@ -429,7 +467,16 @@ static void login_start(struct connection *conn)
conn->state = STATE_EXIT;
return;
}
conn->initiator = strdup(name);
if (conn->initiator == NULL) {
log_error("Unable to dublicate initiator's name %s", name);
rsp->status_class = ISCSI_STATUS_TARGET_ERR;
rsp->status_detail = ISCSI_STATUS_NO_RESOURCES;
conn->state = STATE_EXIT;
return;
}
alias = text_key_find(conn, "InitiatorAlias");
session_type = text_key_find(conn, "SessionType");
target_name = text_key_find(conn, "TargetName");
@@ -465,34 +512,34 @@ static void login_start(struct connection *conn)
return;
}
if (ki->param_get(conn->tid, 0, key_session,
conn->session_param)) {
rsp->status_class = ISCSI_STATUS_TARGET_ERROR;
rsp->status_detail = ISCSI_STATUS_SVC_UNAVAILABLE;
conn->state = STATE_EXIT;
}
if (login_check_reinstatement(conn) != 0)
return;
}
conn->exp_cmd_sn = be32_to_cpu(req->cmd_sn);
log_debug(1, "exp_cmd_sn: %d,%d", conn->exp_cmd_sn, req->cmd_sn);
log_debug(1, "exp_cmd_sn %u, cmd_sn %u", conn->exp_cmd_sn, req->cmd_sn);
text_key_add(conn, "TargetPortalGroupTag", "1");
return;
}
static void login_finish(struct connection *conn)
static int login_finish(struct connection *conn)
{
int res = 0;
switch (conn->session_type) {
case SESSION_NORMAL:
{
if (!conn->session)
session_create(conn);
conn->sid = conn->session->sid;
if (!conn->sess)
res = session_create(conn);
if (res == 0)
conn->sid = conn->sess->sid;
break;
}
case SESSION_DISCOVERY:
/* set a dummy tsih value */
conn->sid.id.tsih = 1;
break;
}
return res;
}
static void cmnd_reject(struct connection *conn, u8 reason)
@@ -649,7 +696,6 @@ static void cmnd_exec_login(struct connection *conn)
case STATE_SECURITY:
case STATE_SECURITY_DONE:
conn->state = STATE_SECURITY_LOGIN;
login_security_done(conn);
break;
default:
goto init_err;
@@ -665,7 +711,6 @@ static void cmnd_exec_login(struct connection *conn)
break;
}
conn->state = STATE_SECURITY_FULL;
login_security_done(conn);
break;
case STATE_LOGIN:
if (stay)
@@ -677,8 +722,14 @@ static void cmnd_exec_login(struct connection *conn)
goto init_err;
}
if (!stay && !nsg_disagree) {
int err;
text_check_param(conn);
login_finish(conn);
err = login_finish(conn);
if (err != 0) {
log_debug(1, "login_finish() failed: %d", err);
/* Make initiator retry later */
goto tgt_no_mem;
}
}
break;
default:
@@ -724,6 +775,13 @@ target_err:
rsp->status_detail = ISCSI_STATUS_TARGET_ERROR;
conn->state = STATE_EXIT;
return;
tgt_no_mem:
rsp->flags = 0;
rsp->status_class = ISCSI_STATUS_TARGET_ERR;
rsp->status_detail = ISCSI_STATUS_NO_RESOURCES;
conn->state = STATE_EXIT;
return;
}
static void text_scan_text(struct connection *conn)

View File

@@ -19,6 +19,7 @@
#include <search.h>
#include <sys/types.h>
#include <assert.h>
#include "types.h"
#include "iscsi_hdr.h"
@@ -27,7 +28,8 @@
#include "config.h"
#include "misc.h"
#define PROC_SESSION "/proc/scsi_tgt/iscsi/session"
#define sBUG() assert(0)
#define sBUG_ON(p) assert(!(p))
struct buf_segment {
struct __qelem entry;
@@ -56,7 +58,8 @@ struct session {
struct target *target;
union iscsi_sid sid;
int conn_cnt;
int kern_conn_cnt;
struct __qelem conn_list;
};
struct connection {
@@ -64,7 +67,7 @@ struct connection {
int iostate;
int fd;
struct session *session;
struct session *sess;
u32 tid;
struct iscsi_param session_param[session_key_last];
@@ -100,6 +103,8 @@ struct connection {
unsigned char *challenge;
} chap;
} auth;
struct __qelem clist;
};
#define IOSTATE_FREE 0
@@ -138,6 +143,11 @@ struct connection {
#define BHS_SIZE 48
/*
* Must be 8192, since it used as MaxRecvDataSegmentLength during Login phase,
* because iSCSI RFC requires: "The default MaxRecvDataSegmentLength is used
* during Login".
*/
#define INCOMING_BUFSIZE 8192
struct target {
@@ -149,9 +159,6 @@ struct target {
char name[ISCSI_NAME_LEN];
char *alias;
int max_nr_sessions;
int nr_sessions;
struct __qelem isns_head;
};
@@ -165,8 +172,7 @@ extern int cmnd_exec_auth_chap(struct connection *conn);
/* conn.c */
extern struct connection *conn_alloc(void);
extern void conn_free(struct connection *conn);
extern int conn_test(struct connection *conn);
extern void conn_take_fd(struct connection *conn, int fd);
extern void conn_pass_to_kern(struct connection *conn, int fd);
extern void conn_read_pdu(struct connection *conn);
extern void conn_write_pdu(struct connection *conn);
extern void conn_free_pdu(struct connection *conn);
@@ -209,8 +215,9 @@ extern void __log_pdu(const char *func, int line, int level, struct PDU *pdu);
/* session.c */
extern struct session *session_find_name(u32 tid, const char *iname, union iscsi_sid sid);
extern struct session *session_find_id(u32 tid, u64 sid);
extern void session_create(struct connection *conn);
extern void session_remove(struct session *session);
extern int session_create(struct connection *conn);
extern void session_free(struct session *session);
extern struct connection *conn_find(struct session *session, u16 cid);
/* target.c */
extern struct __qelem targets_list;
@@ -225,23 +232,18 @@ extern int iscsi_adm_request_listen(void);
extern int iscsi_adm_request_handle(int accept_fd);
/* ctldev.c */
struct iscsi_kernel_interface {
int (*ctldev_open) (int *);
int (*param_get) (u32, u64, int, struct iscsi_param *);
int (*param_set) (u32, u64, int, u32, struct iscsi_param *);
int (*target_create) (u32 *, char *);
int (*target_destroy) (u32);
int (*session_create) (u32, u64, u32, char *, char *);
int (*session_destroy) (u32, u64);
int (*conn_create) (u32, u64, u32, u32, u32, int, u32, u32);
int (*conn_destroy) (u32 tid, u64 sid, u32 cid);
};
extern struct iscsi_kernel_interface *ki;
/* the following functions should be killed */
extern int session_conns_close(u32 tid, u64 sid);
extern int target_destroy(u32 tid);
extern int kernel_open(int *max_data_seg_len);
extern int kernel_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param);
extern int kernel_param_set(u32 tid, u64 sid, int type, u32 partial,
struct iscsi_param *param);
extern int kernel_target_create(u32 *tid, char *name);
extern int kernel_target_destroy(u32 tid);
extern int kernel_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
char *name, char *user);
extern int kernel_session_destroy(u32 tid, u64 sid);
extern int kernel_conn_create(u32 tid, u64 sid, u32 cid, u32 stat_sn, u32 exp_stat_sn,
int fd, u32 hdigest, u32 ddigest);
extern int kernel_conn_destroy(u32 tid, u64 sid, u32 cid);
/* event.c */
extern void handle_iscsi_events(int fd);

View File

@@ -79,7 +79,7 @@ static void iscsi_adm_request_exec(struct iscsi_adm_req *req, struct iscsi_adm_r
req->u.trgt.target_param);
break;
case C_TRGT_SHOW:
err = ki->param_get(req->tid, req->sid, key_target,
err = kernel_param_get(req->tid, req->sid, key_target,
req->u.trgt.target_param);
break;
@@ -88,14 +88,14 @@ static void iscsi_adm_request_exec(struct iscsi_adm_req *req, struct iscsi_adm_r
case C_SESS_UPDATE:
break;
case C_SESS_SHOW:
err = ki->param_get(req->tid, req->sid, key_session,
err = kernel_param_get(req->tid, req->sid, key_session,
req->u.trgt.session_param);
break;
case C_CONN_NEW:
case C_CONN_DEL:
conn_blocked = 1;
err = ki->conn_destroy(req->tid, req->sid, req->cid);
err = kernel_conn_destroy(req->tid, req->sid, req->cid);
conn_blocked = 0;
break;
case C_CONN_UPDATE:

View File

@@ -280,11 +280,19 @@ static struct iscsi_key_ops marker_ops = {
#define SET_KEY_VALUES(x) DEFAULT_NR_##x,DEFAULT_NR_##x,MIN_NR_##x,MAX_NR_##x
/*
* List of local target keys with initial values.
* Must match corresponding key_* enum in iscsi_scst.h!!
*/
struct iscsi_key target_keys[] = {
{"QueuedCommands", SET_KEY_VALUES(QUEUED_CMNDS), &minimum_ops},
{NULL,},
};
/*
* List of iSCSI RFC specified session keys with initial values.
* Must match corresponding key_* enum in iscsi_scst.h!!
*/
struct iscsi_key session_keys[] = {
{"InitialR2T", 1, 0, 0, 1, &or_ops},
{"ImmediateData", 1, 1, 0, 1, &and_ops},

View File

@@ -324,7 +324,7 @@ static int netmask_match_v4(struct sockaddr *sa1, struct sockaddr *sa2, uint32_t
static int netmask_match(struct sockaddr *sa1, struct sockaddr *sa2, char *buf)
{
uint32_t mbit;
int32_t mbit;
uint8_t family = sa1->sa_family;
mbit = strtoul(buf, NULL, 0);
@@ -465,7 +465,6 @@ static int plain_initiator_access(u32 tid, int fd)
static int __plain_target_create(u32 *tid, char *name, int update)
{
int err;
struct iscsi_param params[session_key_last];
if (target_find_by_name(name)) {
log_error("duplicated target %s", name);
@@ -474,13 +473,6 @@ static int __plain_target_create(u32 *tid, char *name, int update)
if ((err = target_add(tid, name)) < 0)
return err;
param_set_defaults(params, session_keys);
if ((err = ki->param_set(*tid, 0, key_session, 0, params)) < 0)
return err;
if (update)
; /* Update the config file here. */
return err;
}
@@ -505,12 +497,9 @@ static int __plain_param_set(u32 tid, u64 sid, int type,
{
int err;
if ((err = ki->param_set(tid, sid, type, partial, param)) < 0)
if ((err = kernel_param_set(tid, sid, type, partial, param)) < 0)
return err;
if (update)
;
return err;
}

View File

@@ -26,22 +26,33 @@
#include "iscsid.h"
static struct session *session_alloc(u32 tid)
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;
}
if (!target)
return NULL;
if (!(session = malloc(sizeof(*session))))
return NULL;
memset(session, 0, sizeof(*session));
session->target = target;
INIT_LIST_HEAD(&session->slist);
insque(&session->slist, &target->sessions_list);
return session;
*psess = session;
out:
return res;
}
struct session *session_find_name(u32 tid, const char *iname, union iscsi_sid sid)
@@ -49,10 +60,13 @@ struct session *session_find_name(u32 tid, const char *iname, union iscsi_sid si
struct session *session;
struct target *target;
if (!(target = target_find_by_id(tid)))
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);
log_debug(1, "session_find_name: %s %#" 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))
@@ -70,7 +84,8 @@ struct session *session_find_id(u32 tid, u64 sid)
if (!(target = target_find_by_id(tid)))
return NULL;
log_debug(1, "session_find_id: %#" PRIx64, sid);
log_debug(1, "Searching for sid %#" PRIx64, sid);
list_for_each_entry(session, &target->sessions_list, slist) {
if (session->sid.id64 == sid)
return session;
@@ -79,105 +94,101 @@ struct session *session_find_id(u32 tid, u64 sid)
return NULL;
}
static int session_test(u32 t_tid, u64 t_sid)
int session_create(struct connection *conn)
{
FILE *f;
char buf[8192], *p;
u32 tid;
u64 sid;
int err = -ENOENT, find = 0;
if ((f = fopen(PROC_SESSION, "r")) == NULL) {
fprintf(stderr, "Can't open %s\n", PROC_SESSION);
return -errno;
}
while (fgets(buf, sizeof(buf), f)) {
p = buf;
while (isspace((int) *p))
p++;
if (!strncmp(p, "tid:", 4)) {
if (sscanf(p, "tid:%u", &tid) != 1) {
err = -EIO;
goto out;
}
if (tid == t_tid)
find = 1;
else
find = 0;
} else if (!strncmp(p, "sid:", 4)) {
if (!find)
continue;
if (sscanf(p, "sid:%" SCNu64, &sid) != 1) {
err = -EIO;
goto out;
}
if (sid == t_sid) {
err = 0;
goto out;
}
}
}
out:
fclose(f);
return err;
}
void session_create(struct connection *conn)
{
struct session *session;
/* We are single threaded, so it desn't need any protection */
static u16 tsih = 1;
struct session *session;
char *user;
int res = 0;
if (!(session = session_alloc(conn->tid)))
return;
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);
insque(&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) {
int err = session_test(conn->tid, session->sid.id64);
struct session *s;
if (err == -ENOENT)
s = session_find_id(conn->tid, session->sid.id64);
if (s != NULL)
break;
else if (err < 0)
return;
log_debug(1, "tsih %x already exists", session->sid.id.tsih);
session->sid.id.tsih++;
}
tsih = session->sid.id.tsih + 1;
conn->session = session;
conn->session->initiator = strdup(conn->initiator);
log_debug(1, "session_create: %#" PRIx64, session->sid.id64);
log_debug(1, "sid %#" PRIx64, session->sid.id64);
if (conn->user != NULL)
user = conn->user;
else
user = "";
ki->session_create(conn->tid, session->sid.id64, conn->exp_cmd_sn,
session->initiator, user);
ki->param_set(conn->tid, session->sid.id64, key_session, 0,
res = kernel_session_create(conn->tid, session->sid.id64, conn->exp_cmd_sn,
session->initiator, user);
if (res != 0) {
log_error("kernel_session_create() failed: %d", res);
goto out_free;
}
res = kernel_param_set(conn->tid, session->sid.id64, key_session, 0,
conn->session_param);
if (res != 0) {
log_error("kernel_param_set() failed: %d", res);
goto out_destroy;
}
out:
return res;
out_destroy:
kernel_session_destroy(conn->tid, session->sid.id64);
out_free:
session_free(session);
conn->sess = NULL;
goto out;
}
void session_remove(struct session *session)
void session_free(struct session *session)
{
log_debug(1, "session_remove: %#" PRIx64, session->sid.id64);
log_debug(1, "Freeing session sid %#"PRIx64, session->sid.id64);
if (!session->sid.id.tsih)
ki->session_destroy(session->target->tid, session->sid.id64);
kernel_session_destroy(session->target->tid, session->sid.id64);
if (session->target) {
if (session->target)
remque(&session->slist);
/* session->target->nr_sessions--; */
}
free(session->initiator);
free(session);
}
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;
}

View File

@@ -82,7 +82,7 @@ static void all_accounts_del(u32 tid, int dir)
int target_del(u32 tid)
{
struct target *target = target_find_by_id(tid);
int err = ki->target_destroy(tid);
int err = kernel_target_destroy(tid);
if (err < 0 && errno != ENOENT)
return -errno;
@@ -114,6 +114,7 @@ int target_add(u32 *tid, char *name)
{
struct target *target;
int err;
struct iscsi_param params[target_key_last];
if (!name)
return -EINVAL;
@@ -124,9 +125,16 @@ int target_add(u32 *tid, char *name)
memset(target, 0, sizeof(*target));
memcpy(target->name, name, sizeof(target->name) - 1);
if ((err = ki->target_create(tid, name)) < 0) {
if ((err = kernel_target_create(tid, name)) < 0) {
log_warning("can't create a target %d %u\n", errno, *tid);
goto out;
goto out_free;
}
param_set_defaults(params, target_keys);
err = kernel_param_set(*tid, 0, key_target, 0, params);
if (err != 0) {
log_error("kernel_param_set() failed: %s", strerror(errno));
goto out_destroy;
}
INIT_LIST_HEAD(&target->tlist);
@@ -137,8 +145,13 @@ int target_add(u32 *tid, char *name)
isns_target_register(name);
return 0;
out:
free(target);
return err;
out_destroy:
kernel_target_destroy(*tid);
out_free:
free(target);
goto out;
}