summaryrefslogtreecommitdiff
path: root/drivers/target/iscsi/iscsi_target_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/target/iscsi/iscsi_target_util.c')
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c509
1 files changed, 236 insertions, 273 deletions
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 1e36f83b5961..5e6cf34929b5 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*******************************************************************************
* This file contains the iSCSI Target specific utility functions.
*
@@ -5,19 +6,10 @@
*
* Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
******************************************************************************/
#include <linux/list.h>
-#include <linux/percpu_ida.h>
+#include <linux/sched/signal.h>
#include <net/ipv6.h> /* ipv6_addr_equal() */
#include <scsi/scsi_tcq.h>
#include <scsi/iscsi_proto.h>
@@ -36,31 +28,11 @@
#include "iscsi_target_util.h"
#include "iscsi_target.h"
-#define PRINT_BUFF(buff, len) \
-{ \
- int zzz; \
- \
- pr_debug("%d:\n", __LINE__); \
- for (zzz = 0; zzz < len; zzz++) { \
- if (zzz % 16 == 0) { \
- if (zzz) \
- pr_debug("\n"); \
- pr_debug("%4i: ", zzz); \
- } \
- pr_debug("%02x ", (unsigned char) (buff)[zzz]); \
- } \
- if ((len + 1) % 16) \
- pr_debug("\n"); \
-}
-
extern struct list_head g_tiqn_list;
extern spinlock_t tiqn_lock;
-/*
- * Called with cmd->r2t_lock held.
- */
int iscsit_add_r2t_to_list(
- struct iscsi_cmd *cmd,
+ struct iscsit_cmd *cmd,
u32 offset,
u32 xfer_len,
int recovery,
@@ -68,6 +40,10 @@ int iscsit_add_r2t_to_list(
{
struct iscsi_r2t *r2t;
+ lockdep_assert_held(&cmd->r2t_lock);
+
+ WARN_ON_ONCE((s32)xfer_len < 0);
+
r2t = kmem_cache_zalloc(lio_r2t_cache, GFP_ATOMIC);
if (!r2t) {
pr_err("Unable to allocate memory for struct iscsi_r2t.\n");
@@ -89,7 +65,7 @@ int iscsit_add_r2t_to_list(
}
struct iscsi_r2t *iscsit_get_r2t_for_eos(
- struct iscsi_cmd *cmd,
+ struct iscsit_cmd *cmd,
u32 offset,
u32 length)
{
@@ -110,7 +86,7 @@ struct iscsi_r2t *iscsit_get_r2t_for_eos(
return NULL;
}
-struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *cmd)
+struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsit_cmd *cmd)
{
struct iscsi_r2t *r2t;
@@ -128,16 +104,15 @@ struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *cmd)
return NULL;
}
-/*
- * Called with cmd->r2t_lock held.
- */
-void iscsit_free_r2t(struct iscsi_r2t *r2t, struct iscsi_cmd *cmd)
+void iscsit_free_r2t(struct iscsi_r2t *r2t, struct iscsit_cmd *cmd)
{
+ lockdep_assert_held(&cmd->r2t_lock);
+
list_del(&r2t->r2t_list);
kmem_cache_free(lio_r2t_cache, r2t);
}
-void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
+void iscsit_free_r2ts_from_list(struct iscsit_cmd *cmd)
{
struct iscsi_r2t *r2t, *r2t_tmp;
@@ -147,25 +122,54 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
spin_unlock_bh(&cmd->r2t_lock);
}
+static int iscsit_wait_for_tag(struct se_session *se_sess, int state, int *cpup)
+{
+ int tag = -1;
+ DEFINE_SBQ_WAIT(wait);
+ struct sbq_wait_state *ws;
+ struct sbitmap_queue *sbq;
+
+ if (state == TASK_RUNNING)
+ return tag;
+
+ sbq = &se_sess->sess_tag_pool;
+ ws = &sbq->ws[0];
+ for (;;) {
+ sbitmap_prepare_to_wait(sbq, ws, &wait, state);
+ if (signal_pending_state(state, current))
+ break;
+ tag = sbitmap_queue_get(sbq, cpup);
+ if (tag >= 0)
+ break;
+ schedule();
+ }
+
+ sbitmap_finish_wait(sbq, ws, &wait);
+ return tag;
+}
+
/*
* May be called from software interrupt (timer) context for allocating
* iSCSI NopINs.
*/
-struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state)
+struct iscsit_cmd *iscsit_allocate_cmd(struct iscsit_conn *conn, int state)
{
- struct iscsi_cmd *cmd;
+ struct iscsit_cmd *cmd;
struct se_session *se_sess = conn->sess->se_sess;
- int size, tag;
+ int size, tag, cpu;
- tag = percpu_ida_alloc(&se_sess->sess_tag_pool, state);
+ tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
+ if (tag < 0)
+ tag = iscsit_wait_for_tag(se_sess, state, &cpu);
if (tag < 0)
return NULL;
- size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size;
- cmd = (struct iscsi_cmd *)(se_sess->sess_cmd_map + (tag * size));
+ size = sizeof(struct iscsit_cmd) + conn->conn_transport->priv_size;
+ cmd = (struct iscsit_cmd *)(se_sess->sess_cmd_map + (tag * size));
memset(cmd, 0, size);
cmd->se_cmd.map_tag = tag;
+ cmd->se_cmd.map_cpu = cpu;
cmd->conn = conn;
cmd->data_direction = DMA_NONE;
INIT_LIST_HEAD(&cmd->i_conn_node);
@@ -176,13 +180,14 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state)
spin_lock_init(&cmd->istate_lock);
spin_lock_init(&cmd->error_lock);
spin_lock_init(&cmd->r2t_lock);
+ timer_setup(&cmd->dataout_timer, iscsit_handle_dataout_timeout, 0);
return cmd;
}
EXPORT_SYMBOL(iscsit_allocate_cmd);
struct iscsi_seq *iscsit_get_seq_holder_for_datain(
- struct iscsi_cmd *cmd,
+ struct iscsit_cmd *cmd,
u32 seq_send_order)
{
u32 i;
@@ -194,12 +199,12 @@ struct iscsi_seq *iscsit_get_seq_holder_for_datain(
return NULL;
}
-struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *cmd)
+struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsit_cmd *cmd)
{
u32 i;
if (!cmd->seq_list) {
- pr_err("struct iscsi_cmd->seq_list is NULL!\n");
+ pr_err("struct iscsit_cmd->seq_list is NULL!\n");
return NULL;
}
@@ -216,7 +221,7 @@ struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *cmd)
}
struct iscsi_r2t *iscsit_get_holder_for_r2tsn(
- struct iscsi_cmd *cmd,
+ struct iscsit_cmd *cmd,
u32 r2t_sn)
{
struct iscsi_r2t *r2t;
@@ -233,7 +238,7 @@ struct iscsi_r2t *iscsit_get_holder_for_r2tsn(
return NULL;
}
-static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cmdsn)
+static inline int iscsit_check_received_cmdsn(struct iscsit_session *sess, u32 cmdsn)
{
u32 max_cmdsn;
int ret;
@@ -277,7 +282,7 @@ static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cm
* Commands may be received out of order if MC/S is in use.
* Ensure they are executed in CmdSN order.
*/
-int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+int iscsit_sequence_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
unsigned char *buf, __be32 cmdsn)
{
int ret, cmdsn_ret;
@@ -328,55 +333,11 @@ int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
}
EXPORT_SYMBOL(iscsit_sequence_cmd);
-int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf)
-{
- struct iscsi_conn *conn = cmd->conn;
- struct se_cmd *se_cmd = &cmd->se_cmd;
- struct iscsi_data *hdr = (struct iscsi_data *) buf;
- u32 payload_length = ntoh24(hdr->dlength);
-
- if (conn->sess->sess_ops->InitialR2T) {
- pr_err("Received unexpected unsolicited data"
- " while InitialR2T=Yes, protocol error.\n");
- transport_send_check_condition_and_sense(se_cmd,
- TCM_UNEXPECTED_UNSOLICITED_DATA, 0);
- return -1;
- }
-
- if ((cmd->first_burst_len + payload_length) >
- conn->sess->sess_ops->FirstBurstLength) {
- pr_err("Total %u bytes exceeds FirstBurstLength: %u"
- " for this Unsolicited DataOut Burst.\n",
- (cmd->first_burst_len + payload_length),
- conn->sess->sess_ops->FirstBurstLength);
- transport_send_check_condition_and_sense(se_cmd,
- TCM_INCORRECT_AMOUNT_OF_DATA, 0);
- return -1;
- }
-
- if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL))
- return 0;
-
- if (((cmd->first_burst_len + payload_length) != cmd->se_cmd.data_length) &&
- ((cmd->first_burst_len + payload_length) !=
- conn->sess->sess_ops->FirstBurstLength)) {
- pr_err("Unsolicited non-immediate data received %u"
- " does not equal FirstBurstLength: %u, and does"
- " not equal ExpXferLen %u.\n",
- (cmd->first_burst_len + payload_length),
- conn->sess->sess_ops->FirstBurstLength, cmd->se_cmd.data_length);
- transport_send_check_condition_and_sense(se_cmd,
- TCM_INCORRECT_AMOUNT_OF_DATA, 0);
- return -1;
- }
- return 0;
-}
-
-struct iscsi_cmd *iscsit_find_cmd_from_itt(
- struct iscsi_conn *conn,
+struct iscsit_cmd *iscsit_find_cmd_from_itt(
+ struct iscsit_conn *conn,
itt_t init_task_tag)
{
- struct iscsi_cmd *cmd;
+ struct iscsit_cmd *cmd;
spin_lock_bh(&conn->cmd_lock);
list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
@@ -393,12 +354,12 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt(
}
EXPORT_SYMBOL(iscsit_find_cmd_from_itt);
-struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(
- struct iscsi_conn *conn,
+struct iscsit_cmd *iscsit_find_cmd_from_itt_or_dump(
+ struct iscsit_conn *conn,
itt_t init_task_tag,
u32 length)
{
- struct iscsi_cmd *cmd;
+ struct iscsit_cmd *cmd;
spin_lock_bh(&conn->cmd_lock);
list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
@@ -420,11 +381,11 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(
}
EXPORT_SYMBOL(iscsit_find_cmd_from_itt_or_dump);
-struct iscsi_cmd *iscsit_find_cmd_from_ttt(
- struct iscsi_conn *conn,
+struct iscsit_cmd *iscsit_find_cmd_from_ttt(
+ struct iscsit_conn *conn,
u32 targ_xfer_tag)
{
- struct iscsi_cmd *cmd = NULL;
+ struct iscsit_cmd *cmd = NULL;
spin_lock_bh(&conn->cmd_lock);
list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
@@ -441,12 +402,12 @@ struct iscsi_cmd *iscsit_find_cmd_from_ttt(
}
int iscsit_find_cmd_for_recovery(
- struct iscsi_session *sess,
- struct iscsi_cmd **cmd_ptr,
+ struct iscsit_session *sess,
+ struct iscsit_cmd **cmd_ptr,
struct iscsi_conn_recovery **cr_ptr,
itt_t init_task_tag)
{
- struct iscsi_cmd *cmd = NULL;
+ struct iscsit_cmd *cmd = NULL;
struct iscsi_conn_recovery *cr;
/*
* Scan through the inactive connection recovery list's command list.
@@ -493,8 +454,8 @@ int iscsit_find_cmd_for_recovery(
}
void iscsit_add_cmd_to_immediate_queue(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn,
+ struct iscsit_cmd *cmd,
+ struct iscsit_conn *conn,
u8 state)
{
struct iscsi_queue_req *qr;
@@ -519,7 +480,7 @@ void iscsit_add_cmd_to_immediate_queue(
}
EXPORT_SYMBOL(iscsit_add_cmd_to_immediate_queue);
-struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn)
+struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsit_conn *conn)
{
struct iscsi_queue_req *qr;
@@ -540,8 +501,8 @@ struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *c
}
static void iscsit_remove_cmd_from_immediate_queue(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+ struct iscsit_cmd *cmd,
+ struct iscsit_conn *conn)
{
struct iscsi_queue_req *qr, *qr_tmp;
@@ -569,8 +530,8 @@ static void iscsit_remove_cmd_from_immediate_queue(
}
int iscsit_add_cmd_to_response_queue(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn,
+ struct iscsit_cmd *cmd,
+ struct iscsit_conn *conn,
u8 state)
{
struct iscsi_queue_req *qr;
@@ -594,7 +555,7 @@ int iscsit_add_cmd_to_response_queue(
return 0;
}
-struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn)
+struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsit_conn *conn)
{
struct iscsi_queue_req *qr;
@@ -616,8 +577,8 @@ struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *co
}
static void iscsit_remove_cmd_from_response_queue(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+ struct iscsit_cmd *cmd,
+ struct iscsit_conn *conn)
{
struct iscsi_queue_req *qr, *qr_tmp;
@@ -645,7 +606,7 @@ static void iscsit_remove_cmd_from_response_queue(
}
}
-bool iscsit_conn_all_queues_empty(struct iscsi_conn *conn)
+bool iscsit_conn_all_queues_empty(struct iscsit_conn *conn)
{
bool empty;
@@ -663,7 +624,7 @@ bool iscsit_conn_all_queues_empty(struct iscsi_conn *conn)
return empty;
}
-void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
+void iscsit_free_queue_reqs_for_conn(struct iscsit_conn *conn)
{
struct iscsi_queue_req *qr, *qr_tmp;
@@ -689,11 +650,13 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
spin_unlock_bh(&conn->response_queue_lock);
}
-void iscsit_release_cmd(struct iscsi_cmd *cmd)
+void iscsit_release_cmd(struct iscsit_cmd *cmd)
{
- struct iscsi_session *sess;
+ struct iscsit_session *sess;
struct se_cmd *se_cmd = &cmd->se_cmd;
+ WARN_ON(!list_empty(&cmd->i_conn_node));
+
if (cmd->conn)
sess = cmd->conn->sess;
else
@@ -705,16 +668,19 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
kfree(cmd->pdu_list);
kfree(cmd->seq_list);
kfree(cmd->tmr_req);
+ kfree(cmd->overflow_buf);
kfree(cmd->iov_data);
kfree(cmd->text_in_ptr);
- percpu_ida_free(&sess->se_sess->sess_tag_pool, se_cmd->map_tag);
+ target_free_tag(sess->se_sess, se_cmd);
}
EXPORT_SYMBOL(iscsit_release_cmd);
-void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool check_queues)
+void __iscsit_free_cmd(struct iscsit_cmd *cmd, bool check_queues)
{
- struct iscsi_conn *conn = cmd->conn;
+ struct iscsit_conn *conn = cmd->conn;
+
+ WARN_ON(!list_empty(&cmd->i_conn_node));
if (cmd->data_direction == DMA_TO_DEVICE) {
iscsit_stop_dataout_timer(cmd);
@@ -728,15 +694,17 @@ void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool check_queues)
iscsit_remove_cmd_from_response_queue(cmd, conn);
}
- if (conn && conn->conn_transport->iscsit_release_cmd)
- conn->conn_transport->iscsit_release_cmd(conn, cmd);
+ if (conn && conn->conn_transport->iscsit_unmap_cmd)
+ conn->conn_transport->iscsit_unmap_cmd(conn, cmd);
}
-void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
+void iscsit_free_cmd(struct iscsit_cmd *cmd, bool shutdown)
{
struct se_cmd *se_cmd = cmd->se_cmd.se_tfo ? &cmd->se_cmd : NULL;
int rc;
+ WARN_ON(!list_empty(&cmd->i_conn_node));
+
__iscsit_free_cmd(cmd, shutdown);
if (se_cmd) {
rc = transport_generic_free_cmd(se_cmd, shutdown);
@@ -750,24 +718,25 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
}
EXPORT_SYMBOL(iscsit_free_cmd);
-int iscsit_check_session_usage_count(struct iscsi_session *sess)
+bool iscsit_check_session_usage_count(struct iscsit_session *sess,
+ bool can_sleep)
{
spin_lock_bh(&sess->session_usage_lock);
if (sess->session_usage_count != 0) {
sess->session_waiting_on_uc = 1;
spin_unlock_bh(&sess->session_usage_lock);
- if (in_interrupt())
- return 2;
+ if (!can_sleep)
+ return true;
wait_for_completion(&sess->session_waiting_on_uc_comp);
- return 1;
+ return false;
}
spin_unlock_bh(&sess->session_usage_lock);
- return 0;
+ return false;
}
-void iscsit_dec_session_usage_count(struct iscsi_session *sess)
+void iscsit_dec_session_usage_count(struct iscsit_session *sess)
{
spin_lock_bh(&sess->session_usage_lock);
sess->session_usage_count--;
@@ -778,16 +747,16 @@ void iscsit_dec_session_usage_count(struct iscsi_session *sess)
spin_unlock_bh(&sess->session_usage_lock);
}
-void iscsit_inc_session_usage_count(struct iscsi_session *sess)
+void iscsit_inc_session_usage_count(struct iscsit_session *sess)
{
spin_lock_bh(&sess->session_usage_lock);
sess->session_usage_count++;
spin_unlock_bh(&sess->session_usage_lock);
}
-struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *sess, u16 cid)
+struct iscsit_conn *iscsit_get_conn_from_cid(struct iscsit_session *sess, u16 cid)
{
- struct iscsi_conn *conn;
+ struct iscsit_conn *conn;
spin_lock_bh(&sess->conn_lock);
list_for_each_entry(conn, &sess->sess_conn_list, conn_list) {
@@ -803,9 +772,9 @@ struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *sess, u16 cid)
return NULL;
}
-struct iscsi_conn *iscsit_get_conn_from_cid_rcfr(struct iscsi_session *sess, u16 cid)
+struct iscsit_conn *iscsit_get_conn_from_cid_rcfr(struct iscsit_session *sess, u16 cid)
{
- struct iscsi_conn *conn;
+ struct iscsit_conn *conn;
spin_lock_bh(&sess->conn_lock);
list_for_each_entry(conn, &sess->sess_conn_list, conn_list) {
@@ -823,7 +792,7 @@ struct iscsi_conn *iscsit_get_conn_from_cid_rcfr(struct iscsi_session *sess, u16
return NULL;
}
-void iscsit_check_conn_usage_count(struct iscsi_conn *conn)
+void iscsit_check_conn_usage_count(struct iscsit_conn *conn)
{
spin_lock_bh(&conn->conn_usage_lock);
if (conn->conn_usage_count != 0) {
@@ -836,7 +805,7 @@ void iscsit_check_conn_usage_count(struct iscsi_conn *conn)
spin_unlock_bh(&conn->conn_usage_lock);
}
-void iscsit_dec_conn_usage_count(struct iscsi_conn *conn)
+void iscsit_dec_conn_usage_count(struct iscsit_conn *conn)
{
spin_lock_bh(&conn->conn_usage_lock);
conn->conn_usage_count--;
@@ -847,17 +816,17 @@ void iscsit_dec_conn_usage_count(struct iscsi_conn *conn)
spin_unlock_bh(&conn->conn_usage_lock);
}
-void iscsit_inc_conn_usage_count(struct iscsi_conn *conn)
+void iscsit_inc_conn_usage_count(struct iscsit_conn *conn)
{
spin_lock_bh(&conn->conn_usage_lock);
conn->conn_usage_count++;
spin_unlock_bh(&conn->conn_usage_lock);
}
-static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response)
+static int iscsit_add_nopin(struct iscsit_conn *conn, int want_response)
{
u8 state;
- struct iscsi_cmd *cmd;
+ struct iscsit_cmd *cmd;
cmd = iscsit_allocate_cmd(conn, TASK_RUNNING);
if (!cmd)
@@ -880,9 +849,11 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response)
return 0;
}
-static void iscsit_handle_nopin_response_timeout(unsigned long data)
+void iscsit_handle_nopin_response_timeout(struct timer_list *t)
{
- struct iscsi_conn *conn = (struct iscsi_conn *) data;
+ struct iscsit_conn *conn = timer_container_of(conn, t,
+ nopin_response_timer);
+ struct iscsit_session *sess = conn->sess;
iscsit_inc_conn_usage_count(conn);
@@ -893,35 +864,21 @@ static void iscsit_handle_nopin_response_timeout(unsigned long data)
return;
}
- pr_debug("Did not receive response to NOPIN on CID: %hu on"
- " SID: %u, failing connection.\n", conn->cid,
- conn->sess->sid);
+ pr_err("Did not receive response to NOPIN on CID: %hu, failing"
+ " connection for I_T Nexus %s,i,0x%6phN,%s,t,0x%02x\n",
+ conn->cid, sess->sess_ops->InitiatorName, sess->isid,
+ sess->tpg->tpg_tiqn->tiqn, (u32)sess->tpg->tpgt);
conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING;
spin_unlock_bh(&conn->nopin_timer_lock);
- {
- struct iscsi_portal_group *tpg = conn->sess->tpg;
- struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
-
- if (tiqn) {
- spin_lock_bh(&tiqn->sess_err_stats.lock);
- strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name,
- conn->sess->sess_ops->InitiatorName);
- tiqn->sess_err_stats.last_sess_failure_type =
- ISCSI_SESS_ERR_CXN_TIMEOUT;
- tiqn->sess_err_stats.cxn_timeout_errors++;
- atomic_long_inc(&conn->sess->conn_timeout_errors);
- spin_unlock_bh(&tiqn->sess_err_stats.lock);
- }
- }
-
+ iscsit_fill_cxn_timeout_err_stats(sess);
iscsit_cause_connection_reinstatement(conn, 0);
iscsit_dec_conn_usage_count(conn);
}
-void iscsit_mod_nopin_response_timer(struct iscsi_conn *conn)
+void iscsit_mod_nopin_response_timer(struct iscsit_conn *conn)
{
- struct iscsi_session *sess = conn->sess;
+ struct iscsit_session *sess = conn->sess;
struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
spin_lock_bh(&conn->nopin_timer_lock);
@@ -935,12 +892,9 @@ void iscsit_mod_nopin_response_timer(struct iscsi_conn *conn)
spin_unlock_bh(&conn->nopin_timer_lock);
}
-/*
- * Called with conn->nopin_timer_lock held.
- */
-void iscsit_start_nopin_response_timer(struct iscsi_conn *conn)
+void iscsit_start_nopin_response_timer(struct iscsit_conn *conn)
{
- struct iscsi_session *sess = conn->sess;
+ struct iscsit_session *sess = conn->sess;
struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
spin_lock_bh(&conn->nopin_timer_lock);
@@ -949,21 +903,17 @@ void iscsit_start_nopin_response_timer(struct iscsi_conn *conn)
return;
}
- init_timer(&conn->nopin_response_timer);
- conn->nopin_response_timer.expires =
- (get_jiffies_64() + na->nopin_response_timeout * HZ);
- conn->nopin_response_timer.data = (unsigned long)conn;
- conn->nopin_response_timer.function = iscsit_handle_nopin_response_timeout;
conn->nopin_response_timer_flags &= ~ISCSI_TF_STOP;
conn->nopin_response_timer_flags |= ISCSI_TF_RUNNING;
- add_timer(&conn->nopin_response_timer);
+ mod_timer(&conn->nopin_response_timer,
+ jiffies + na->nopin_response_timeout * HZ);
pr_debug("Started NOPIN Response Timer on CID: %d to %u"
" seconds\n", conn->cid, na->nopin_response_timeout);
spin_unlock_bh(&conn->nopin_timer_lock);
}
-void iscsit_stop_nopin_response_timer(struct iscsi_conn *conn)
+void iscsit_stop_nopin_response_timer(struct iscsit_conn *conn)
{
spin_lock_bh(&conn->nopin_timer_lock);
if (!(conn->nopin_response_timer_flags & ISCSI_TF_RUNNING)) {
@@ -973,16 +923,16 @@ void iscsit_stop_nopin_response_timer(struct iscsi_conn *conn)
conn->nopin_response_timer_flags |= ISCSI_TF_STOP;
spin_unlock_bh(&conn->nopin_timer_lock);
- del_timer_sync(&conn->nopin_response_timer);
+ timer_delete_sync(&conn->nopin_response_timer);
spin_lock_bh(&conn->nopin_timer_lock);
conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING;
spin_unlock_bh(&conn->nopin_timer_lock);
}
-static void iscsit_handle_nopin_timeout(unsigned long data)
+void iscsit_handle_nopin_timeout(struct timer_list *t)
{
- struct iscsi_conn *conn = (struct iscsi_conn *) data;
+ struct iscsit_conn *conn = timer_container_of(conn, t, nopin_timer);
iscsit_inc_conn_usage_count(conn);
@@ -999,13 +949,13 @@ static void iscsit_handle_nopin_timeout(unsigned long data)
iscsit_dec_conn_usage_count(conn);
}
-/*
- * Called with conn->nopin_timer_lock held.
- */
-void __iscsit_start_nopin_timer(struct iscsi_conn *conn)
+void __iscsit_start_nopin_timer(struct iscsit_conn *conn)
{
- struct iscsi_session *sess = conn->sess;
+ struct iscsit_session *sess = conn->sess;
struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
+
+ lockdep_assert_held(&conn->nopin_timer_lock);
+
/*
* NOPIN timeout is disabled.
*/
@@ -1015,48 +965,22 @@ void __iscsit_start_nopin_timer(struct iscsi_conn *conn)
if (conn->nopin_timer_flags & ISCSI_TF_RUNNING)
return;
- init_timer(&conn->nopin_timer);
- conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ);
- conn->nopin_timer.data = (unsigned long)conn;
- conn->nopin_timer.function = iscsit_handle_nopin_timeout;
conn->nopin_timer_flags &= ~ISCSI_TF_STOP;
conn->nopin_timer_flags |= ISCSI_TF_RUNNING;
- add_timer(&conn->nopin_timer);
+ mod_timer(&conn->nopin_timer, jiffies + na->nopin_timeout * HZ);
pr_debug("Started NOPIN Timer on CID: %d at %u second"
" interval\n", conn->cid, na->nopin_timeout);
}
-void iscsit_start_nopin_timer(struct iscsi_conn *conn)
+void iscsit_start_nopin_timer(struct iscsit_conn *conn)
{
- struct iscsi_session *sess = conn->sess;
- struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
- /*
- * NOPIN timeout is disabled..
- */
- if (!na->nopin_timeout)
- return;
-
spin_lock_bh(&conn->nopin_timer_lock);
- if (conn->nopin_timer_flags & ISCSI_TF_RUNNING) {
- spin_unlock_bh(&conn->nopin_timer_lock);
- return;
- }
-
- init_timer(&conn->nopin_timer);
- conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ);
- conn->nopin_timer.data = (unsigned long)conn;
- conn->nopin_timer.function = iscsit_handle_nopin_timeout;
- conn->nopin_timer_flags &= ~ISCSI_TF_STOP;
- conn->nopin_timer_flags |= ISCSI_TF_RUNNING;
- add_timer(&conn->nopin_timer);
-
- pr_debug("Started NOPIN Timer on CID: %d at %u second"
- " interval\n", conn->cid, na->nopin_timeout);
+ __iscsit_start_nopin_timer(conn);
spin_unlock_bh(&conn->nopin_timer_lock);
}
-void iscsit_stop_nopin_timer(struct iscsi_conn *conn)
+void iscsit_stop_nopin_timer(struct iscsit_conn *conn)
{
spin_lock_bh(&conn->nopin_timer_lock);
if (!(conn->nopin_timer_flags & ISCSI_TF_RUNNING)) {
@@ -1066,16 +990,67 @@ void iscsit_stop_nopin_timer(struct iscsi_conn *conn)
conn->nopin_timer_flags |= ISCSI_TF_STOP;
spin_unlock_bh(&conn->nopin_timer_lock);
- del_timer_sync(&conn->nopin_timer);
+ timer_delete_sync(&conn->nopin_timer);
spin_lock_bh(&conn->nopin_timer_lock);
conn->nopin_timer_flags &= ~ISCSI_TF_RUNNING;
spin_unlock_bh(&conn->nopin_timer_lock);
}
+void iscsit_login_timeout(struct timer_list *t)
+{
+ struct iscsit_conn *conn = timer_container_of(conn, t, login_timer);
+ struct iscsi_login *login = conn->login;
+
+ pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n");
+
+ spin_lock_bh(&conn->login_timer_lock);
+ login->login_failed = 1;
+
+ if (conn->login_kworker) {
+ pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n",
+ conn->login_kworker->comm, conn->login_kworker->pid);
+ send_sig(SIGINT, conn->login_kworker, 1);
+ } else {
+ schedule_delayed_work(&conn->login_work, 0);
+ }
+ spin_unlock_bh(&conn->login_timer_lock);
+}
+
+void iscsit_start_login_timer(struct iscsit_conn *conn, struct task_struct *kthr)
+{
+ pr_debug("Login timer started\n");
+
+ conn->login_kworker = kthr;
+ mod_timer(&conn->login_timer, jiffies + TA_LOGIN_TIMEOUT * HZ);
+}
+
+int iscsit_set_login_timer_kworker(struct iscsit_conn *conn, struct task_struct *kthr)
+{
+ struct iscsi_login *login = conn->login;
+ int ret = 0;
+
+ spin_lock_bh(&conn->login_timer_lock);
+ if (login->login_failed) {
+ /* The timer has already expired */
+ ret = -1;
+ } else {
+ conn->login_kworker = kthr;
+ }
+ spin_unlock_bh(&conn->login_timer_lock);
+
+ return ret;
+}
+
+void iscsit_stop_login_timer(struct iscsit_conn *conn)
+{
+ pr_debug("Login timer stopped\n");
+ timer_delete_sync(&conn->login_timer);
+}
+
int iscsit_send_tx_data(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn,
+ struct iscsit_cmd *cmd,
+ struct iscsit_conn *conn,
int use_misc)
{
int tx_sent, tx_size;
@@ -1107,10 +1082,12 @@ send_data:
}
int iscsit_fe_sendpage_sg(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+ struct iscsit_cmd *cmd,
+ struct iscsit_conn *conn)
{
struct scatterlist *sg = cmd->first_data_sg;
+ struct bio_vec bvec;
+ struct msghdr msghdr = { .msg_flags = MSG_SPLICE_PAGES, };
struct kvec iov;
u32 tx_hdr_size, data_len;
u32 offset = cmd->first_data_sg_off;
@@ -1154,17 +1131,18 @@ send_hdr:
u32 space = (sg->length - offset);
u32 sub_len = min_t(u32, data_len, space);
send_pg:
- tx_sent = conn->sock->ops->sendpage(conn->sock,
- sg_page(sg), sg->offset + offset, sub_len, 0);
+ bvec_set_page(&bvec, sg_page(sg), sub_len, sg->offset + offset);
+ iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, sub_len);
+
+ tx_sent = conn->sock->ops->sendmsg(conn->sock, &msghdr,
+ sub_len);
if (tx_sent != sub_len) {
if (tx_sent == -EAGAIN) {
- pr_err("tcp_sendpage() returned"
- " -EAGAIN\n");
+ pr_err("sendmsg/splice returned -EAGAIN\n");
goto send_pg;
}
- pr_err("tcp_sendpage() failure: %d\n",
- tx_sent);
+ pr_err("sendmsg/splice failure: %d\n", tx_sent);
return -1;
}
@@ -1212,7 +1190,7 @@ send_datacrc:
* Parameters: iSCSI Connection, Status Class, Status Detail.
* Returns: 0 on success, -1 on error.
*/
-int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_detail)
+int iscsit_tx_login_rsp(struct iscsit_conn *conn, u8 status_class, u8 status_detail)
{
struct iscsi_login_rsp *hdr;
struct iscsi_login *login = conn->conn_login;
@@ -1231,33 +1209,20 @@ int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_deta
return conn->conn_transport->iscsit_put_login_tx(conn, login, 0);
}
-void iscsit_print_session_params(struct iscsi_session *sess)
-{
- struct iscsi_conn *conn;
-
- pr_debug("-----------------------------[Session Params for"
- " SID: %u]-----------------------------\n", sess->sid);
- spin_lock_bh(&sess->conn_lock);
- list_for_each_entry(conn, &sess->sess_conn_list, conn_list)
- iscsi_dump_conn_ops(conn->conn_ops);
- spin_unlock_bh(&sess->conn_lock);
-
- iscsi_dump_sess_ops(sess->sess_ops);
-}
-
-static int iscsit_do_rx_data(
- struct iscsi_conn *conn,
- struct iscsi_data_count *count)
+int rx_data(
+ struct iscsit_conn *conn,
+ struct kvec *iov,
+ int iov_count,
+ int data)
{
- int data = count->data_length, rx_loop = 0, total_rx = 0;
+ int rx_loop = 0, total_rx = 0;
struct msghdr msg;
if (!conn || !conn->sock || !conn->conn_ops)
return -1;
memset(&msg, 0, sizeof(struct msghdr));
- iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC,
- count->iov, count->iov_count, data);
+ iov_iter_kvec(&msg.msg_iter, ITER_DEST, iov, iov_count, data);
while (msg_data_left(&msg)) {
rx_loop = sock_recvmsg(conn->sock, &msg, MSG_WAITALL);
@@ -1274,28 +1239,8 @@ static int iscsit_do_rx_data(
return total_rx;
}
-int rx_data(
- struct iscsi_conn *conn,
- struct kvec *iov,
- int iov_count,
- int data)
-{
- struct iscsi_data_count c;
-
- if (!conn || !conn->sock || !conn->conn_ops)
- return -1;
-
- memset(&c, 0, sizeof(struct iscsi_data_count));
- c.iov = iov;
- c.iov_count = iov_count;
- c.data_length = data;
- c.type = ISCSI_RX_DATA;
-
- return iscsit_do_rx_data(conn, &c);
-}
-
int tx_data(
- struct iscsi_conn *conn,
+ struct iscsit_conn *conn,
struct kvec *iov,
int iov_count,
int data)
@@ -1313,8 +1258,7 @@ int tx_data(
memset(&msg, 0, sizeof(struct msghdr));
- iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC,
- iov, iov_count, data);
+ iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, iov_count, data);
while (msg_data_left(&msg)) {
int tx_loop = sock_sendmsg(conn->sock, &msg);
@@ -1332,7 +1276,7 @@ int tx_data(
}
void iscsit_collect_login_stats(
- struct iscsi_conn *conn,
+ struct iscsit_conn *conn,
u8 status_class,
u8 status_detail)
{
@@ -1374,7 +1318,7 @@ void iscsit_collect_login_stats(
if (conn->param_list)
intrname = iscsi_find_param_from_key(INITIATORNAME,
conn->param_list);
- strlcpy(ls->last_intr_fail_name,
+ strscpy(ls->last_intr_fail_name,
(intrname ? intrname->value : "Unknown"),
sizeof(ls->last_intr_fail_name));
@@ -1387,7 +1331,7 @@ void iscsit_collect_login_stats(
spin_unlock(&ls->lock);
}
-struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *conn)
+struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsit_conn *conn)
{
struct iscsi_portal_group *tpg;
@@ -1403,3 +1347,22 @@ struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *conn)
return tpg->tpg_tiqn;
}
+
+void iscsit_fill_cxn_timeout_err_stats(struct iscsit_session *sess)
+{
+ struct iscsi_portal_group *tpg = sess->tpg;
+ struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
+
+ if (!tiqn)
+ return;
+
+ spin_lock_bh(&tiqn->sess_err_stats.lock);
+ strscpy(tiqn->sess_err_stats.last_sess_fail_rem_name,
+ sess->sess_ops->InitiatorName,
+ sizeof(tiqn->sess_err_stats.last_sess_fail_rem_name));
+ tiqn->sess_err_stats.last_sess_failure_type =
+ ISCSI_SESS_ERR_CXN_TIMEOUT;
+ tiqn->sess_err_stats.cxn_timeout_errors++;
+ atomic_long_inc(&sess->conn_timeout_errors);
+ spin_unlock_bh(&tiqn->sess_err_stats.lock);
+}