mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-18 03:01:26 +00:00
- Now during connection and session reinstatements only SCSI commands are delayed until the corresponding reinstatement finished.
- TEST UNIT READY made HEAD OF QUEUE to let target don't look dead under high load - Docs updated git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@774 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -72,16 +72,17 @@ original IET behavior, when for data transmission:
|
||||
|
||||
- For in-kernel allocated memory (scst_vdisk and pass-through
|
||||
handlers) usage of SGV cache on transmit path (READ-type commands)
|
||||
will be disabled. The performance hit will be not big, but performance
|
||||
will still remain better, than for IET, because SGV cache will remain
|
||||
used on receive path while IET doesn't have such feature.
|
||||
will be disabled, but data will still be sent in zero-copy manner.
|
||||
The performance hit will be not big, but performance will still
|
||||
remain better, than for IET, because SGV cache will remain used on
|
||||
receive path while IET doesn't have such feature.
|
||||
|
||||
- For user space allocated memory (scst_user handler) all transmitted
|
||||
data will be additionally copied into temporary TCP buffers. The
|
||||
performance hit will be quite noticeable.
|
||||
|
||||
Note, that if your network hardware does not support TX offload
|
||||
functions of has them disabled, then TCP zero-copy transmit functions on
|
||||
functions or has them disabled, then TCP zero-copy transmit functions on
|
||||
your system will not be used by Linux networking in any case, so
|
||||
put_page_callback patch will not be able to improve performance for you.
|
||||
You can check your network hardware offload capabilities by command
|
||||
@@ -131,6 +132,9 @@ and the SCST core as it logically should be: the target driver is
|
||||
responsible for handling targets and their parameters, SCST core is
|
||||
responsible for handling backstorage.
|
||||
|
||||
It is recommended to use TEST UNIT READY ("tur") command to check if
|
||||
iSCSI-SCST target is alive.
|
||||
|
||||
IMPORTANT: All LUN information (access control) MUST be configured
|
||||
========= BEFORE iscsi-scstd started!
|
||||
|
||||
|
||||
@@ -32,16 +32,17 @@ original IET behavior, when for data transmission:
|
||||
|
||||
- For in-kernel allocated memory (scst_vdisk and pass-through
|
||||
handlers) usage of SGV cache on transmit path (READ-type commands)
|
||||
will be disabled. The performance hit will be not big, but performance
|
||||
will still remain better, than for IET, because SGV cache will remain
|
||||
used on receive path while IET doesn't have such feature.
|
||||
will be disabled, but data will still be sent in zero-copy manner.
|
||||
The performance hit will be not big, but performance will still
|
||||
remain better, than for IET, because SGV cache will remain used on
|
||||
receive path while IET doesn't have such feature.
|
||||
|
||||
- For user space allocated memory (scst_user handler) all transmitted
|
||||
data will be additionally copied into temporary TCP buffers. The
|
||||
performance hit will be quite noticeable.
|
||||
|
||||
Note, that if your network hardware does not support TX offload
|
||||
functions of has them disabled, then TCP zero-copy transmit functions on
|
||||
functions or has them disabled, then TCP zero-copy transmit functions on
|
||||
your system will not be used by Linux networking in any case, so
|
||||
put_page_callback patch will not be able to improve performance for you.
|
||||
You can check your network hardware offload capabilities by command
|
||||
@@ -66,6 +67,9 @@ and the SCST core as it logically should be: the target driver is
|
||||
responsible for handling targets and their parameters, SCST core is
|
||||
responsible for handling backstorage.
|
||||
|
||||
It is recommended to use TEST UNIT READY ("tur") command to check if
|
||||
iSCSI-SCST target is alive.
|
||||
|
||||
IMPORTANT: All LUN information (access control) MUST be configured
|
||||
========= BEFORE iscsi-scstd started!
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ static void print_conn_state(char *p, size_t size, struct iscsi_conn *conn)
|
||||
break;
|
||||
}
|
||||
|
||||
if (conn->conn_reinstating)
|
||||
if (test_bit(ISCSI_CONN_REINSTATING, &conn->conn_aflags))
|
||||
snprintf(p, size, "%s", "reinstating ");
|
||||
else if (!printed)
|
||||
snprintf(p, size, "%s", "established idle ");
|
||||
@@ -132,8 +132,6 @@ 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,
|
||||
@@ -184,8 +182,7 @@ void __mark_conn_closed(struct iscsi_conn *conn, int flags)
|
||||
conn->deleting = 1;
|
||||
spin_unlock_bh(&iscsi_rd_lock);
|
||||
|
||||
if (!conn->conn_reinstating)
|
||||
iscsi_make_conn_rd_active(conn);
|
||||
iscsi_make_conn_rd_active(conn);
|
||||
}
|
||||
|
||||
void mark_conn_closed(struct iscsi_conn *conn)
|
||||
@@ -274,7 +271,7 @@ static void conn_rsp_timer_fn(unsigned long arg)
|
||||
|
||||
if (!list_empty(&conn->written_list)) {
|
||||
struct iscsi_cmnd *wr_cmd = list_entry(conn->written_list.next,
|
||||
struct iscsi_cmnd, write_list_entry);
|
||||
struct iscsi_cmnd, written_list_entry);
|
||||
|
||||
if (unlikely(time_after_eq(jiffies, wr_cmd->write_timeout))) {
|
||||
if (!conn->closing) {
|
||||
@@ -302,16 +299,34 @@ static void conn_rsp_timer_fn(unsigned long arg)
|
||||
return;
|
||||
}
|
||||
|
||||
void __iscsi_socket_bind(struct iscsi_conn *conn)
|
||||
/* target_mutex supposed to be locked */
|
||||
void conn_reinst_finished(struct iscsi_conn *conn)
|
||||
{
|
||||
struct iscsi_cmnd *cmnd, *t;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
clear_bit(ISCSI_CONN_REINSTATING, &conn->conn_aflags);
|
||||
|
||||
list_for_each_entry_safe(cmnd, t, &conn->reinst_pending_cmd_list,
|
||||
reinst_pending_cmd_list_entry) {
|
||||
TRACE_MGMT_DBG("Restarting reinst pending cmnd %p",
|
||||
cmnd);
|
||||
list_del(&cmnd->reinst_pending_cmd_list_entry);
|
||||
iscsi_restart_cmnd(cmnd);
|
||||
}
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
static void conn_activate(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;
|
||||
@@ -340,7 +355,7 @@ void __iscsi_socket_bind(struct iscsi_conn *conn)
|
||||
* 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, bool reinstating)
|
||||
static int conn_setup_sock(struct iscsi_conn *conn)
|
||||
{
|
||||
int res = 0;
|
||||
int opt = 1;
|
||||
@@ -369,17 +384,6 @@ static int iscsi_socket_bind(struct iscsi_conn *conn, bool reinstating)
|
||||
(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;
|
||||
}
|
||||
@@ -399,9 +403,10 @@ int conn_free(struct iscsi_conn *conn)
|
||||
sBUG_ON(!list_empty(&conn->write_list));
|
||||
sBUG_ON(!list_empty(&conn->written_list));
|
||||
sBUG_ON(conn->conn_reinst_successor != NULL);
|
||||
sBUG_ON(!conn->conn_shutting_down);
|
||||
sBUG_ON(!test_bit(ISCSI_CONN_SHUTTINGDOWN, &conn->conn_aflags));
|
||||
|
||||
if (conn->conn_reinstating) {
|
||||
/* Just in case if new conn gets freed before the old one */
|
||||
if (test_bit(ISCSI_CONN_REINSTATING, &conn->conn_aflags)) {
|
||||
struct iscsi_conn *c;
|
||||
TRACE_MGMT_DBG("Freeing being reinstated conn %p", conn);
|
||||
list_for_each_entry(c, &conn->session->conn_list,
|
||||
@@ -428,14 +433,11 @@ int conn_free(struct iscsi_conn *conn)
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
static int iscsi_conn_alloc(struct iscsi_session *session,
|
||||
struct iscsi_kern_conn_info *info, bool reinstating,
|
||||
struct iscsi_conn **new_conn)
|
||||
struct iscsi_kern_conn_info *info, 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;
|
||||
@@ -454,7 +456,8 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
|
||||
|
||||
atomic_set(&conn->conn_ref_cnt, 0);
|
||||
conn->session = session;
|
||||
conn->conn_reinstating = reinstating;
|
||||
if (session->sess_reinstating)
|
||||
__set_bit(ISCSI_CONN_REINSTATING, &conn->conn_aflags);
|
||||
conn->cid = info->cid;
|
||||
conn->stat_sn = info->stat_sn;
|
||||
conn->exp_stat_sn = info->exp_stat_sn;
|
||||
@@ -475,10 +478,11 @@ static int iscsi_conn_alloc(struct iscsi_session *session,
|
||||
INIT_LIST_HEAD(&conn->written_list);
|
||||
setup_timer(&conn->rsp_timer, conn_rsp_timer_fn, (unsigned long)conn);
|
||||
init_completion(&conn->ready_to_free);
|
||||
INIT_LIST_HEAD(&conn->reinst_pending_cmd_list);
|
||||
|
||||
conn->file = fget(info->fd);
|
||||
|
||||
res = iscsi_socket_bind(conn, reinstating);
|
||||
res = conn_setup_sock(conn);
|
||||
if (res != 0)
|
||||
goto out_err_free2;
|
||||
|
||||
@@ -510,7 +514,8 @@ int conn_add(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
|
||||
bool reinstatement = false;
|
||||
|
||||
conn = conn_lookup(session, info->cid);
|
||||
if ((conn != NULL) && !conn->conn_shutting_down) {
|
||||
if ((conn != NULL) &&
|
||||
!test_bit(ISCSI_CONN_SHUTTINGDOWN, &conn->conn_aflags)) {
|
||||
/* conn reinstatement */
|
||||
reinstatement = true;
|
||||
} else if (!list_empty(&session->conn_list)) {
|
||||
@@ -518,7 +523,7 @@ int conn_add(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = iscsi_conn_alloc(session, info, reinstatement, &new_conn);
|
||||
err = iscsi_conn_alloc(session, info, &new_conn);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
|
||||
@@ -526,10 +531,12 @@ int conn_add(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
|
||||
TRACE_MGMT_DBG("Reinstating conn (old %p, new %p)", conn,
|
||||
new_conn);
|
||||
conn->conn_reinst_successor = new_conn;
|
||||
new_conn->conn_reinstating = 1;
|
||||
__set_bit(ISCSI_CONN_REINSTATING, &new_conn->conn_aflags);
|
||||
__mark_conn_closed(conn, 0);
|
||||
}
|
||||
|
||||
conn_activate(new_conn);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -114,13 +114,45 @@ static inline int cmnd_read_size(struct iscsi_cmnd *cmnd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void iscsi_restart_cmnd(struct iscsi_cmnd *cmnd)
|
||||
void iscsi_restart_cmnd(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
EXTRACHECKS_BUG_ON(cmnd->data_waiting);
|
||||
|
||||
if (unlikely(test_bit(ISCSI_CONN_REINSTATING,
|
||||
&cmnd->conn->conn_aflags))) {
|
||||
struct iscsi_target *target = cmnd->conn->session->target;
|
||||
bool get_out;
|
||||
|
||||
mutex_lock(&target->target_mutex);
|
||||
|
||||
get_out = test_bit(ISCSI_CONN_REINSTATING,
|
||||
&cmnd->conn->conn_aflags);
|
||||
/* Let's don't look dead */
|
||||
if (scst_cmd_get_cdb(cmnd->scst_cmd)[0] == TEST_UNIT_READY)
|
||||
get_out = false;
|
||||
|
||||
if (!get_out)
|
||||
goto unlock_cont;
|
||||
|
||||
TRACE_MGMT_DBG("Pending cmnd %p, because conn %p is "
|
||||
"reinstated", cmnd, cmnd->conn);
|
||||
|
||||
cmnd->scst_state = ISCSI_CMD_STATE_REINST_PENDING;
|
||||
list_add_tail(&cmnd->reinst_pending_cmd_list_entry,
|
||||
&cmnd->conn->reinst_pending_cmd_list);
|
||||
|
||||
unlock_cont:
|
||||
mutex_unlock(&target->target_mutex);
|
||||
|
||||
if (get_out)
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmnd->scst_state = ISCSI_CMD_STATE_RESTARTED;
|
||||
scst_restart_cmd(cmnd->scst_cmd, SCST_PREPROCESS_STATUS_SUCCESS,
|
||||
SCST_CONTEXT_THREAD);
|
||||
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -226,6 +258,7 @@ static void cmnd_free(struct iscsi_cmnd *cmnd)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Might be called unded some lock and on SIRQ */
|
||||
void cmnd_done(struct iscsi_cmnd *cmnd)
|
||||
{
|
||||
TRACE_DBG("%p", cmnd);
|
||||
@@ -243,7 +276,7 @@ void cmnd_done(struct iscsi_cmnd *cmnd)
|
||||
TRACE_DBG("Deleting cmd %p from conn %p written_list", cmnd,
|
||||
conn);
|
||||
spin_lock_bh(&conn->write_list_lock);
|
||||
list_del(&cmnd->write_list_entry);
|
||||
list_del(&cmnd->written_list_entry);
|
||||
cmnd->on_written_list = 0;
|
||||
spin_unlock_bh(&conn->write_list_lock);
|
||||
}
|
||||
@@ -2973,7 +3006,7 @@ static int iscsi_scsi_aen(struct scst_aen *aen)
|
||||
|
||||
found = false;
|
||||
list_for_each_entry_reverse(conn, &sess->conn_list, conn_list_entry) {
|
||||
if (!conn->conn_shutting_down &&
|
||||
if (!test_bit(ISCSI_CONN_SHUTTINGDOWN, &conn->conn_aflags) &&
|
||||
(conn->conn_reinst_successor == NULL)) {
|
||||
found = true;
|
||||
break;
|
||||
|
||||
@@ -147,6 +147,10 @@ struct iscsi_conn {
|
||||
u32 stat_sn;
|
||||
u32 exp_stat_sn;
|
||||
|
||||
#define ISCSI_CONN_REINSTATING 1
|
||||
#define ISCSI_CONN_SHUTTINGDOWN 2
|
||||
unsigned long conn_aflags;
|
||||
|
||||
spinlock_t cmd_list_lock; /* BH lock */
|
||||
|
||||
/* Protected by cmd_list_lock */
|
||||
@@ -227,8 +231,7 @@ struct iscsi_conn {
|
||||
|
||||
/* All protected by target_mutex, where necessary */
|
||||
struct iscsi_conn *conn_reinst_successor;
|
||||
unsigned int conn_reinstating:1;
|
||||
unsigned int conn_shutting_down:1;
|
||||
struct list_head reinst_pending_cmd_list;
|
||||
|
||||
struct completion ready_to_free;
|
||||
|
||||
@@ -257,14 +260,17 @@ typedef void (iscsi_show_info_t)(struct seq_file *seq,
|
||||
/* The command returned from preprocessing_done() */
|
||||
#define ISCSI_CMD_STATE_AFTER_PREPROC 2
|
||||
|
||||
/* The command is waiting for session or connection reinstatement finished */
|
||||
#define ISCSI_CMD_STATE_REINST_PENDING 3
|
||||
|
||||
/* scst_restart_cmd() called and SCST processing it */
|
||||
#define ISCSI_CMD_STATE_RESTARTED 3
|
||||
#define ISCSI_CMD_STATE_RESTARTED 4
|
||||
|
||||
/* SCST done processing */
|
||||
#define ISCSI_CMD_STATE_PROCESSED 4
|
||||
#define ISCSI_CMD_STATE_PROCESSED 5
|
||||
|
||||
/* AEN processing */
|
||||
#define ISCSI_CMD_STATE_AEN 5
|
||||
#define ISCSI_CMD_STATE_AEN 6
|
||||
|
||||
/** Command's reject reasons **/
|
||||
#define ISCSI_REJECT_SCSI_CMD 1
|
||||
@@ -320,7 +326,12 @@ struct iscsi_cmnd {
|
||||
|
||||
union {
|
||||
struct list_head pending_list_entry;
|
||||
struct list_head reinst_pending_cmd_list_entry;
|
||||
};
|
||||
|
||||
union {
|
||||
struct list_head write_list_entry;
|
||||
struct list_head written_list_entry;
|
||||
};
|
||||
|
||||
/* Both modified only from single write thread */
|
||||
@@ -410,10 +421,11 @@ extern void req_cmnd_release_force(struct iscsi_cmnd *req, int flags);
|
||||
extern void rsp_cmnd_release(struct iscsi_cmnd *);
|
||||
extern void cmnd_done(struct iscsi_cmnd *cmnd);
|
||||
extern void conn_abort(struct iscsi_conn *conn);
|
||||
extern void iscsi_restart_cmnd(struct iscsi_cmnd *cmnd);
|
||||
|
||||
/* conn.c */
|
||||
extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
|
||||
extern void __iscsi_socket_bind(struct iscsi_conn *);
|
||||
extern void conn_reinst_finished(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 *);
|
||||
@@ -454,7 +466,7 @@ extern void iscsi_procfs_exit(void);
|
||||
/* session.c */
|
||||
extern const struct file_operations session_seq_fops;
|
||||
extern struct iscsi_session *session_lookup(struct iscsi_target *, u64);
|
||||
extern void sess_enable_reinstated_sess(struct iscsi_session *);
|
||||
extern void sess_reinst_finished(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, bool del);
|
||||
|
||||
@@ -339,11 +339,12 @@ void iscsi_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *scst_mcmd)
|
||||
|
||||
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 */
|
||||
sBUG_ON(!test_bit(ISCSI_CONN_REINSTATING,
|
||||
&conn->conn_reinst_successor->conn_aflags));
|
||||
conn_reinst_finished(conn->conn_reinst_successor);
|
||||
conn->conn_reinst_successor = NULL;
|
||||
} else if (sess->sess_reinst_successor != NULL) {
|
||||
sess_enable_reinstated_sess(sess->sess_reinst_successor);
|
||||
sess_reinst_finished(sess->sess_reinst_successor);
|
||||
sess->sess_reinst_successor = NULL;
|
||||
}
|
||||
mutex_unlock(&sess->target->target_mutex);
|
||||
@@ -394,12 +395,12 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
|
||||
mutex_lock(&session->target->target_mutex);
|
||||
|
||||
conn->conn_shutting_down = 1;
|
||||
set_bit(ISCSI_CONN_SHUTTINGDOWN, &conn->conn_aflags);
|
||||
reinst = (conn->conn_reinst_successor != NULL);
|
||||
|
||||
session->sess_shutting_down = 1;
|
||||
list_for_each_entry(c, &session->conn_list, conn_list_entry) {
|
||||
if (!c->conn_shutting_down) {
|
||||
if (!test_bit(ISCSI_CONN_SHUTTINGDOWN, &c->conn_aflags)) {
|
||||
session->sess_shutting_down = 0;
|
||||
break;
|
||||
}
|
||||
@@ -542,12 +543,8 @@ static void close_conn(struct iscsi_conn *conn)
|
||||
conn);
|
||||
event_send(target->tid, session->sid, conn->cid, E_CONN_CLOSE, 0);
|
||||
|
||||
sBUG_ON(conn->conn_reinstating);
|
||||
sBUG_ON(session->sess_reinstating);
|
||||
|
||||
mutex_lock(&target->target_mutex);
|
||||
|
||||
conn->conn_reinst_successor = NULL;
|
||||
conn_free(conn);
|
||||
|
||||
if (list_empty(&session->conn_list)) {
|
||||
@@ -1098,7 +1095,8 @@ static int write_data(struct iscsi_conn *conn)
|
||||
spin_lock_bh(&conn->write_list_lock);
|
||||
ref_cmd->on_written_list = 1;
|
||||
ref_cmd->write_timeout = jiffies + ISCSI_RSP_TIMEOUT;
|
||||
list_add_tail(&ref_cmd->write_list_entry, &conn->written_list);
|
||||
list_add_tail(&ref_cmd->written_list_entry,
|
||||
&conn->written_list);
|
||||
spin_unlock_bh(&conn->write_list_lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ err:
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
void sess_enable_reinstated_sess(struct iscsi_session *sess)
|
||||
void sess_reinst_finished(struct iscsi_session *sess)
|
||||
{
|
||||
struct iscsi_conn *c;
|
||||
|
||||
@@ -118,7 +118,7 @@ void sess_enable_reinstated_sess(struct iscsi_session *sess)
|
||||
sBUG_ON(!sess->sess_reinstating);
|
||||
|
||||
list_for_each_entry(c, &sess->conn_list, conn_list_entry) {
|
||||
__iscsi_socket_bind(c);
|
||||
conn_reinst_finished(c);
|
||||
}
|
||||
sess->sess_reinstating = 0;
|
||||
|
||||
@@ -239,7 +239,7 @@ int session_free(struct iscsi_session *session, bool del)
|
||||
sBUG_ON(!list_empty(&session->cmnd_hash[i]));
|
||||
|
||||
if (session->sess_reinst_successor != NULL)
|
||||
sess_enable_reinstated_sess(session->sess_reinst_successor);
|
||||
sess_reinst_finished(session->sess_reinst_successor);
|
||||
|
||||
if (session->sess_reinstating) {
|
||||
struct iscsi_session *s;
|
||||
|
||||
@@ -184,6 +184,7 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* target_mutex supposed to be locked */
|
||||
void target_del_session(struct iscsi_target *target,
|
||||
struct iscsi_session *session, int flags)
|
||||
{
|
||||
|
||||
46
scst/README
46
scst/README
@@ -57,20 +57,29 @@ corresponding to that symbol "#if LINUX_VERSION_CODE" statement.
|
||||
At first, make sure that the link "/lib/modules/`you_kernel_version`/build"
|
||||
points to the source code for your currently running kernel.
|
||||
|
||||
Then, since in the mainstream kernels scsi_do_req()/scsi_execute_async()
|
||||
work in LIFO order, instead of expected and required FIFO, SCST needs a
|
||||
new functions scsi_do_req_fifo()/scsi_execute_async_fifo() to be added
|
||||
in the kernel. Patch scst_exec_req_fifo.patch from "kernel" directory
|
||||
does that. If it doesn't apply to your kernel, apply it manually, it
|
||||
only adds one of those functions and nothing more. You may not patch the
|
||||
kernel if you don't need pass-through support or CONFIG_SCST_STRICT_SERIALIZING is
|
||||
defined during the compilation (see description below).
|
||||
Then you should consider to apply necessary kernel patches. SCST has the
|
||||
following patches for the kernel in the "kernel" subdirectory. All of
|
||||
them are optional, so, if you don't need the corresponding
|
||||
functionality, you may not apply them.
|
||||
|
||||
Then, to get the maximum performance you should apply export_alloc_io_context
|
||||
patch. This patch simply makes alloc_io_context() function be available
|
||||
for modules, not only for built-in in kernel code.
|
||||
1. scst_exec_req_fifo-2.6.X.patch. This patch is necessary for
|
||||
pass-through dev handlers, because in the mainstream kernels
|
||||
scsi_do_req()/scsi_execute_async() work in LIFO order, instead of
|
||||
expected and required FIFO. So SCST needs new functions
|
||||
scsi_do_req_fifo() or scsi_execute_async_fifo() to be added in the
|
||||
kernel. This patch does that. You may not patch the kernel if you don't
|
||||
need pass-through support. Alternatively, you can define
|
||||
CONFIG_SCST_STRICT_SERIALIZING compile option during the compilation
|
||||
(see description below).
|
||||
|
||||
To compile SCST type 'make scst'. It will build SCST itself and its
|
||||
2. io_context-2.6.X.patch. This patch exports some IO context management
|
||||
functions from the kernel. For performance reasons SCST queues commands
|
||||
using a pool of IO threads. It is considerably better for performance
|
||||
(>30% increase on sequential reads) if threads in a pool have the same
|
||||
IO context. This patch allows that. If you don't apply this patch, you
|
||||
will loose this performance benefit.
|
||||
|
||||
Then, to compile SCST type 'make scst'. It will build SCST itself and its
|
||||
device handlers. To install them type 'make scst_install'. The driver
|
||||
modules will be installed in '/lib/modules/`you_kernel_version`/extra'.
|
||||
In addition, scst.h, scst_debug.h as well as Module.symvers or
|
||||
@@ -139,6 +148,13 @@ IMPORTANT: In the current version simultaneous access to local SCSI devices
|
||||
To uninstall, type 'make scst_uninstall'.
|
||||
|
||||
|
||||
Usage in failover mode
|
||||
----------------------
|
||||
|
||||
It is recommended to use TEST UNIT READY ("tur") command to check if
|
||||
SCST target is alive.
|
||||
|
||||
|
||||
Device handlers
|
||||
---------------
|
||||
|
||||
@@ -236,9 +252,9 @@ in/out in Makefile:
|
||||
cases. The current SCSI core in Linux doesn't allow to abort all
|
||||
commands reliably if they sent asynchronously to a stateful device.
|
||||
Turned off by default, turn it on if you use stateful device(s) and
|
||||
need as much error recovery reliability as possible. As a side
|
||||
effect, no kernel patching is necessary for pass-through device
|
||||
handlers (scst_disk, etc.).
|
||||
need as much error recovery reliability as possible. As a side effect
|
||||
of CONFIG_SCST_STRICT_SERIALIZING, no kernel patching is necessary
|
||||
for pass-through device handlers (scst_disk, etc.).
|
||||
|
||||
- CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - if defined, it will be
|
||||
allowed to submit pass-through commands to real SCSI devices via the SCSI
|
||||
|
||||
@@ -83,6 +83,14 @@ IMPORTANT: In the current version simultaneous access to local SCSI devices
|
||||
devices READ/WRITE commands using direct disk handler look to
|
||||
be safe.
|
||||
|
||||
|
||||
Usage in failover mode
|
||||
----------------------
|
||||
|
||||
It is recommended to use TEST UNIT READY ("tur") command to check if
|
||||
SCST target is alive.
|
||||
|
||||
|
||||
Device handlers
|
||||
---------------
|
||||
|
||||
@@ -179,9 +187,9 @@ your favorit kernel configuration Makefile target, e.g. "make xconfig":
|
||||
cases. The current SCSI core in Linux doesn't allow to abort all
|
||||
commands reliably if they sent asynchronously to a stateful device.
|
||||
Turned off by default, turn it on if you use stateful device(s) and
|
||||
need as much error recovery reliability as possible. As a side
|
||||
effect, no kernel patching is necessary for pass-through device
|
||||
handlers (scst_disk, etc.)
|
||||
need as much error recovery reliability as possible. As a side effect
|
||||
of CONFIG_SCST_STRICT_SERIALIZING, no kernel patching is necessary
|
||||
for pass-through device handlers (scst_disk, etc.).
|
||||
|
||||
- CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - if defined, it will be
|
||||
allowed to submit pass-through commands to real SCSI devices via the SCSI
|
||||
|
||||
@@ -415,19 +415,21 @@ void scst_process_reset(struct scst_device *dev,
|
||||
|
||||
static inline int scst_is_ua_command(struct scst_cmd *cmd)
|
||||
{
|
||||
return cmd->cdb[0] != INQUIRY
|
||||
&& cmd->cdb[0] != REQUEST_SENSE
|
||||
&& cmd->cdb[0] != REPORT_LUNS;
|
||||
return (cmd->cdb[0] != INQUIRY) &&
|
||||
(cmd->cdb[0] != REQUEST_SENSE) &&
|
||||
(cmd->cdb[0] != REPORT_LUNS);
|
||||
}
|
||||
|
||||
static inline int scst_is_implicit_hq(struct scst_cmd *cmd)
|
||||
{
|
||||
return cmd->cdb[0] == INQUIRY
|
||||
|| cmd->cdb[0] == REPORT_LUNS
|
||||
|| (cmd->dev->type == TYPE_DISK
|
||||
&& (cmd->cdb[0] == READ_CAPACITY
|
||||
|| (cmd->cdb[0] == SERVICE_ACTION_IN
|
||||
&& (cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16)));
|
||||
return (cmd->cdb[0] == INQUIRY) ||
|
||||
(cmd->cdb[0] == REPORT_LUNS) ||
|
||||
((cmd->dev->type == TYPE_DISK) &&
|
||||
((cmd->cdb[0] == READ_CAPACITY) ||
|
||||
((cmd->cdb[0] == SERVICE_ACTION_IN) &&
|
||||
((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16)))) ||
|
||||
/* Let's don't look dead under high load */
|
||||
(cmd->cdb[0] == TEST_UNIT_READY);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user