diff --git a/iscsi-scst/README b/iscsi-scst/README index cb43f7b97..bbe0b006b 100644 --- a/iscsi-scst/README +++ b/iscsi-scst/README @@ -294,20 +294,20 @@ Each target subdirectory contains the following entries: - QueuedCommands - defines maximum number of commands queued to any session of this target. Default is 32 commands. - - RspTimeout - defines the maximum time in seconds a command can wait for - response from initiator, otherwise the corresponding connection will - be closed. For performance reasons it is implemented as a timer, - which once in RspTimeout time checks the oldest command waiting for - response and, if it's older than RspTimeout, then it closes the - connection. Hence, a stalled connection will be closed in time - between RspTimeout and 2*RspTimeout. Default is 30 seconds. - - NopInInterval - defines interval between NOP-In requests, which the target will send on idle connections to check if the initiator is still alive. If there is no NOP-Out reply from the initiator in RspTimeout time, the corresponding connection will be closed. Default is 30 seconds. If it's set to 0, then NOP-In requests are disabled. + - NopInTimeout - defines the maximum time in seconds a NOP-In request + can wait for response from initiator, otherwise the corresponding + connection will be closed. Default is 30 seconds. + + - RspTimeout - defines the maximum time in seconds a command can wait for + response from initiator, otherwise the corresponding connection will + be closed. Default is 90 seconds. + - enabled - using this attribute you can enable or disable iSCSI-SCST accept new connections to this target. It allows to finish configuring it before it starts accepting new connections. 0 by diff --git a/iscsi-scst/README_in-tree b/iscsi-scst/README_in-tree index 85ae8cee4..41c4f520f 100644 --- a/iscsi-scst/README_in-tree +++ b/iscsi-scst/README_in-tree @@ -136,20 +136,20 @@ Each target subdirectory contains the following entries: - QueuedCommands - defines maximum number of commands queued to any session of this target. Default is 32 commands. - - RspTimeout - defines the maximum time in seconds a command can wait for - response from initiator, otherwise the corresponding connection will - be closed. For performance reasons it is implemented as a timer, - which once in RspTimeout time checks the oldest command waiting for - response and, if it's older than RspTimeout, then it closes the - connection. Hence, a stalled connection will be closed in time - between RspTimeout and 2*RspTimeout. Default is 30 seconds. - - NopInInterval - defines interval between NOP-In requests, which the target will send on idle connections to check if the initiator is still alive. If there is no NOP-Out reply from the initiator in RspTimeout time, the corresponding connection will be closed. Default is 30 seconds. If it's set to 0, then NOP-In requests are disabled. + - NopInTimeout - defines the maximum time in seconds a NOP-In request + can wait for response from initiator, otherwise the corresponding + connection will be closed. Default is 30 seconds. + + - RspTimeout - defines the maximum time in seconds a command can wait for + response from initiator, otherwise the corresponding connection will + be closed. Default is 90 seconds. + - enabled - using this attribute you can enable or disable iSCSI-SCST accept new connections to this target. It allows to finish configuring it before it starts accepting new connections. 0 by diff --git a/iscsi-scst/include/iscsi_scst.h b/iscsi-scst/include/iscsi_scst.h index 03a0fb9f0..cb806dfab 100644 --- a/iscsi-scst/include/iscsi_scst.h +++ b/iscsi-scst/include/iscsi_scst.h @@ -70,6 +70,7 @@ enum { key_queued_cmnds, key_rsp_timeout, key_nop_in_interval, + key_nop_in_timeout, key_max_sessions, target_key_last, }; @@ -187,7 +188,7 @@ struct iscsi_kern_initiator_info { #define MIN_NR_QUEUED_CMNDS 1 #define MAX_NR_QUEUED_CMNDS 256 -#define DEFAULT_RSP_TIMEOUT 30 +#define DEFAULT_RSP_TIMEOUT 90 #define MIN_RSP_TIMEOUT 2 #define MAX_RSP_TIMEOUT 65535 @@ -195,6 +196,10 @@ struct iscsi_kern_initiator_info { #define MIN_NOP_IN_INTERVAL 0 #define MAX_NOP_IN_INTERVAL 65535 +#define DEFAULT_NOP_IN_TIMEOUT 30 +#define MIN_NOP_IN_TIMEOUT 2 +#define MAX_NOP_IN_TIMEOUT 65535 + #define NETLINK_ISCSI_SCST 25 #define REGISTER_USERD _IOWR('s', 0, struct iscsi_kern_register_info) diff --git a/iscsi-scst/kernel/conn.c b/iscsi-scst/kernel/conn.c index cbd75a7fc..d887d58a8 100644 --- a/iscsi-scst/kernel/conn.c +++ b/iscsi-scst/kernel/conn.c @@ -530,14 +530,14 @@ static void conn_rsp_timer_fn(unsigned long arg) cmnd = list_entry(conn->write_timeout_list.next, struct iscsi_cmnd, write_timeout_list_entry); - timeout_time = j + conn->rsp_timeout + ISCSI_ADD_SCHED_TIME; + timeout_time = j + iscsi_get_timeout(cmnd) + ISCSI_ADD_SCHED_TIME; - if (unlikely(time_after_eq(j, cmnd->write_start + - conn->rsp_timeout))) { + if (unlikely(time_after_eq(j, iscsi_get_timeout_time(cmnd)))) { if (!conn->closing) { - PRINT_ERROR("Timeout sending data/waiting " + PRINT_ERROR("Timeout %ld sec sending data/waiting " "for reply to/from initiator " "%s (SID %llx), closing connection", + iscsi_get_timeout(cmnd)/HZ, conn->session->initiator_name, (long long unsigned int) conn->session->sid); @@ -883,8 +883,9 @@ static int iscsi_conn_alloc(struct iscsi_session *session, conn); #endif conn->last_rcv_time = jiffies; - conn->rsp_timeout = session->tgt_params.rsp_timeout * HZ; + conn->data_rsp_timeout = session->tgt_params.rsp_timeout * HZ; conn->nop_in_interval = session->tgt_params.nop_in_interval * HZ; + conn->nop_in_timeout = session->tgt_params.nop_in_timeout * HZ; if (conn->nop_in_interval > 0) { TRACE_DBG("Schedule Nop-In work for conn %p", conn); schedule_delayed_work(&conn->nop_in_delayed_work, diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index 1ac4021f6..ea1527049 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -63,6 +63,7 @@ struct iscsi_tgt_params { int queued_cmnds; unsigned int rsp_timeout; unsigned int nop_in_interval; + unsigned int nop_in_timeout; }; struct iscsi_thread { @@ -213,7 +214,7 @@ struct iscsi_conn { /* Protected by write_list_lock */ struct timer_list rsp_timer; - unsigned int rsp_timeout; /* in jiffies */ + unsigned int data_rsp_timeout; /* in jiffies */ /* * All 2 protected by wr_lock. Modified independently to the @@ -303,6 +304,7 @@ struct iscsi_conn { struct work_struct nop_in_delayed_work; #endif unsigned int nop_in_interval; /* in jiffies */ + unsigned int nop_in_timeout; /* in jiffies */ struct list_head nop_req_list; spinlock_t nop_req_list_lock; u32 nop_in_ttt; @@ -750,6 +752,17 @@ static inline void cmd_del_from_rx_ddigest_list(struct iscsi_cmnd *cmnd) #endif } +static inline unsigned long iscsi_get_timeout(struct iscsi_cmnd *req) +{ + return (cmnd_opcode(req) == ISCSI_OP_NOP_OUT) ? + req->conn->nop_in_timeout : req->conn->data_rsp_timeout; +} + +static inline unsigned long iscsi_get_timeout_time(struct iscsi_cmnd *req) +{ + return req->write_start + iscsi_get_timeout(req); +} + static inline int test_write_ready(struct iscsi_conn *conn) { /* diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index 95a399a7f..fdb2d397e 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -1217,8 +1217,32 @@ void req_add_to_write_timeout_list(struct iscsi_cmnd *req) req->on_write_timeout_list = 1; req->write_start = jiffies; - list_add_tail(&req->write_timeout_list_entry, - &conn->write_timeout_list); + if (unlikely(cmnd_opcode(req) == ISCSI_OP_NOP_OUT)) { + unsigned long req_tt = iscsi_get_timeout_time(req); + struct iscsi_cmnd *r; + bool inserted = false; + list_for_each_entry(r, &conn->write_timeout_list, + write_timeout_list_entry) { + unsigned long tt = iscsi_get_timeout_time(r); + if (time_after(tt, req_tt)) { + TRACE_DBG("Add NOP IN req %p (tt %ld) before " + "req %p (tt %ld)", req, req_tt, r, tt); + list_add_tail(&req->write_timeout_list_entry, + &r->write_timeout_list_entry); + inserted = true; + break; + } else + TRACE_DBG("Skipping op %x req %p (tt %ld)", + cmnd_opcode(r), r, tt); + } + if (!inserted) { + TRACE_DBG("Add NOP IN req %p in the tail", req); + list_add_tail(&req->write_timeout_list_entry, + &conn->write_timeout_list); + } + } else + list_add_tail(&req->write_timeout_list_entry, + &conn->write_timeout_list); if (!timer_pending(&conn->rsp_timer)) { unsigned long timeout_time; @@ -1227,11 +1251,11 @@ void req_add_to_write_timeout_list(struct iscsi_cmnd *req) &req->prelim_compl_flags))) { set_conn_tm_active = true; timeout_time = req->write_start + - ISCSI_TM_DATA_WAIT_TIMEOUT + - ISCSI_ADD_SCHED_TIME; + ISCSI_TM_DATA_WAIT_TIMEOUT; } else - timeout_time = req->write_start + - conn->rsp_timeout + ISCSI_ADD_SCHED_TIME; + timeout_time = iscsi_get_timeout_time(req); + + timeout_time += ISCSI_ADD_SCHED_TIME; TRACE_DBG("Starting timer on %ld (con %p, write_start %ld)", timeout_time, conn, req->write_start); diff --git a/iscsi-scst/kernel/param.c b/iscsi-scst/kernel/param.c index 62fc5516d..65dce7be8 100644 --- a/iscsi-scst/kernel/param.c +++ b/iscsi-scst/kernel/param.c @@ -204,6 +204,8 @@ static void tgt_params_check(struct iscsi_session *session, MAX_RSP_TIMEOUT); CHECK_PARAM(info, iparams, nop_in_interval, MIN_NOP_IN_INTERVAL, MAX_NOP_IN_INTERVAL); + CHECK_PARAM(info, iparams, nop_in_timeout, MIN_NOP_IN_TIMEOUT, + MAX_NOP_IN_TIMEOUT); return; } @@ -222,16 +224,19 @@ static int iscsi_tgt_params_set(struct iscsi_session *session, SET_PARAM(params, info, iparams, queued_cmnds); SET_PARAM(params, info, iparams, rsp_timeout); SET_PARAM(params, info, iparams, nop_in_interval); + SET_PARAM(params, info, iparams, nop_in_timeout); PRINT_INFO("Target parameters set for session %llx: " "QueuedCommands %d, Response timeout %d, Nop-In " - "interval %d", session->sid, params->queued_cmnds, - params->rsp_timeout, params->nop_in_interval); + "interval %d, Nop-In timeout %d", session->sid, + params->queued_cmnds, params->rsp_timeout, + params->nop_in_interval, params->nop_in_timeout); list_for_each_entry(conn, &session->conn_list, conn_list_entry) { - conn->rsp_timeout = session->tgt_params.rsp_timeout * HZ; + conn->data_rsp_timeout = session->tgt_params.rsp_timeout * HZ; conn->nop_in_interval = session->tgt_params.nop_in_interval * HZ; + conn->nop_in_timeout = session->tgt_params.nop_in_timeout * HZ; spin_lock_bh(&conn->conn_thr_pool->rd_lock); if (!conn->closing && (conn->nop_in_interval > 0)) { TRACE_DBG("Schedule Nop-In work for conn %p", conn); @@ -244,6 +249,7 @@ static int iscsi_tgt_params_set(struct iscsi_session *session, GET_PARAM(params, info, iparams, queued_cmnds); GET_PARAM(params, info, iparams, rsp_timeout); GET_PARAM(params, info, iparams, nop_in_interval); + GET_PARAM(params, info, iparams, nop_in_timeout); } return 0; diff --git a/iscsi-scst/usr/param.c b/iscsi-scst/usr/param.c index ec42dcfb8..597af0b1b 100644 --- a/iscsi-scst/usr/param.c +++ b/iscsi-scst/usr/param.c @@ -350,6 +350,7 @@ struct iscsi_key target_keys[] = { {"QueuedCommands", SET_KEY_VALUES(NR_QUEUED_CMNDS), 1, &minimum_ops}, {"RspTimeout", SET_KEY_VALUES(RSP_TIMEOUT), 1, &minimum_ops}, {"NopInInterval", SET_KEY_VALUES(NOP_IN_INTERVAL), 1, &minimum_ops}, + {"NopInTimeout", SET_KEY_VALUES(NOP_IN_TIMEOUT), 1, &minimum_ops}, {"MaxSessions", 0, 0, 0, 65535, 1, &minimum_ops}, {NULL,}, };