Skip to content

Commit

Permalink
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/nab/target-pending

Pull SCSI target updates from Nicholas Bellinger:

 "This series is predominantly bug-fixes, with a few small improvements
  that have been outstanding over the last release cycle.

  As usual, the associated bug-fixes have CC' tags for stable.

  Also, things have been particularly quiet wrt new developments the
  last months, with most folks continuing to focus on stability atop 4.x
  stable kernels for their respective production configurations.

  Also at this point, the stable trees have been synced up with
  mainline. This will continue to be a priority, as production users
  tend to run exclusively atop stable kernels, a few releases behind
  mainline.

  The highlights include:

   - Fix PR PREEMPT_AND_ABORT null pointer dereference regression in
     v4.11+ (tangwenji)

   - Fix OOPs during removing TCMU device (Xiubo Li + Zhang Zhuoyu)

   - Add netlink command reply supported option for each device (Kenjiro
     Nakayama)

   - cxgbit: Abort the TCP connection in case of data out timeout (Varun
     Prakash)

   - Fix PR/ALUA file path truncation (David Disseldorp)

   - Fix double se_cmd completion during ->cmd_time_out (Mike Christie)

   - Fix QUEUE_FULL + SCSI task attribute handling in 4.1+ (Bryant Ly +
     nab)

   - Fix quiese during transport_write_pending_qf endless loop (nab)

   - Avoid early CMD_T_PRE_EXECUTE failures during ABORT_TASK in 3.14+
     (Don White + nab)"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (35 commits)
  tcmu: Add a missing unlock on an error path
  tcmu: Fix some memory corruption
  iscsi-target: Fix non-immediate TMR reference leak
  iscsi-target: Make TASK_REASSIGN use proper se_cmd->cmd_kref
  target: Avoid early CMD_T_PRE_EXECUTE failures during ABORT_TASK
  target: Fix quiese during transport_write_pending_qf endless loop
  target: Fix caw_sem leak in transport_generic_request_failure
  target: Fix QUEUE_FULL + SCSI task attribute handling
  iSCSI-target: Use common error handling code in iscsi_decode_text_input()
  target/iscsi: Detect conn_cmd_list corruption early
  target/iscsi: Fix a race condition in iscsit_add_reject_from_cmd()
  target/iscsi: Modify iscsit_do_crypto_hash_buf() prototype
  target/iscsi: Fix endianness in an error message
  target/iscsi: Use min() in iscsit_dump_data_payload() instead of open-coding it
  target/iscsi: Define OFFLOAD_BUF_SIZE once
  target: Inline transport_put_cmd()
  target: Suppress gcc 7 fallthrough warnings
  target: Move a declaration of a global variable into a header file
  tcmu: fix double se_cmd completion
  target: return SAM_STAT_TASK_SET_FULL for TCM_OUT_OF_RESOURCES
  ...
  • Loading branch information
torvalds committed Nov 25, 2017
2 parents 1d3b78b + 97488c7 commit eda5d47
Show file tree
Hide file tree
Showing 22 changed files with 387 additions and 239 deletions.
2 changes: 2 additions & 0 deletions drivers/target/iscsi/cxgbit/cxgbit.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ enum cxgbit_csk_flags {
CSK_LOGIN_PDU_DONE,
CSK_LOGIN_DONE,
CSK_DDP_ENABLE,
CSK_ABORT_RPL_WAIT,
};

struct cxgbit_sock_common {
Expand Down Expand Up @@ -321,6 +322,7 @@ int cxgbit_setup_np(struct iscsi_np *, struct sockaddr_storage *);
int cxgbit_setup_conn_digest(struct cxgbit_sock *);
int cxgbit_accept_np(struct iscsi_np *, struct iscsi_conn *);
void cxgbit_free_np(struct iscsi_np *);
void cxgbit_abort_conn(struct cxgbit_sock *csk);
void cxgbit_free_conn(struct iscsi_conn *);
extern cxgbit_cplhandler_func cxgbit_cplhandlers[NUM_CPL_CMDS];
int cxgbit_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
Expand Down
45 changes: 45 additions & 0 deletions drivers/target/iscsi/cxgbit/cxgbit_cm.c
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,46 @@ static int cxgbit_send_abort_req(struct cxgbit_sock *csk)
return cxgbit_l2t_send(csk->com.cdev, skb, csk->l2t);
}

static void
__cxgbit_abort_conn(struct cxgbit_sock *csk, struct sk_buff *skb)
{
__kfree_skb(skb);

if (csk->com.state != CSK_STATE_ESTABLISHED)
goto no_abort;

set_bit(CSK_ABORT_RPL_WAIT, &csk->com.flags);
csk->com.state = CSK_STATE_ABORTING;

cxgbit_send_abort_req(csk);

return;

no_abort:
cxgbit_wake_up(&csk->com.wr_wait, __func__, CPL_ERR_NONE);
cxgbit_put_csk(csk);
}

void cxgbit_abort_conn(struct cxgbit_sock *csk)
{
struct sk_buff *skb = alloc_skb(0, GFP_KERNEL | __GFP_NOFAIL);

cxgbit_get_csk(csk);
cxgbit_init_wr_wait(&csk->com.wr_wait);

spin_lock_bh(&csk->lock);
if (csk->lock_owner) {
cxgbit_skcb_rx_backlog_fn(skb) = __cxgbit_abort_conn;
__skb_queue_tail(&csk->backlogq, skb);
} else {
__cxgbit_abort_conn(csk, skb);
}
spin_unlock_bh(&csk->lock);

cxgbit_wait_for_reply(csk->com.cdev, &csk->com.wr_wait,
csk->tid, 600, __func__);
}

void cxgbit_free_conn(struct iscsi_conn *conn)
{
struct cxgbit_sock *csk = conn->context;
Expand Down Expand Up @@ -1709,12 +1749,17 @@ static void cxgbit_abort_req_rss(struct cxgbit_sock *csk, struct sk_buff *skb)

static void cxgbit_abort_rpl_rss(struct cxgbit_sock *csk, struct sk_buff *skb)
{
struct cpl_abort_rpl_rss *rpl = cplhdr(skb);

pr_debug("%s: csk %p; tid %u; state %d\n",
__func__, csk, csk->tid, csk->com.state);

switch (csk->com.state) {
case CSK_STATE_ABORTING:
csk->com.state = CSK_STATE_DEAD;
if (test_bit(CSK_ABORT_RPL_WAIT, &csk->com.flags))
cxgbit_wake_up(&csk->com.wr_wait, __func__,
rpl->status);
cxgbit_put_csk(csk);
break;
default:
Expand Down
8 changes: 8 additions & 0 deletions drivers/target/iscsi/cxgbit/cxgbit_ddp.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,14 @@ void cxgbit_release_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
struct cxgbit_device *cdev = csk->com.cdev;
struct cxgbi_ppm *ppm = cdev2ppm(cdev);

/* Abort the TCP conn if DDP is not complete to
* avoid any possibility of DDP after freeing
* the cmd.
*/
if (unlikely(cmd->write_data_done !=
cmd->se_cmd.data_length))
cxgbit_abort_conn(csk);

cxgbi_ppm_ppod_release(ppm, ttinfo->idx);

dma_unmap_sg(&ppm->pdev->dev, ttinfo->sgl,
Expand Down
1 change: 1 addition & 0 deletions drivers/target/iscsi/cxgbit/cxgbit_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ cxgbit_uld_lro_rx_handler(void *hndl, const __be64 *rsp,
case CPL_RX_ISCSI_DDP:
case CPL_FW4_ACK:
lro_flush = false;
/* fall through */
case CPL_ABORT_RPL_RSS:
case CPL_PASS_ESTABLISH:
case CPL_PEER_CLOSE:
Expand Down
80 changes: 36 additions & 44 deletions drivers/target/iscsi/iscsi_target.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
EXPORT_SYMBOL(iscsit_aborted_task);

static void iscsit_do_crypto_hash_buf(struct ahash_request *, const void *,
u32, u32, u8 *, u8 *);
u32, u32, const void *, void *);
static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *);

static int
Expand All @@ -523,7 +523,7 @@ iscsit_xmit_nondatain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,

iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
ISCSI_HDR_LEN, 0, NULL,
(u8 *)header_digest);
header_digest);

iov[0].iov_len += ISCSI_CRC_LEN;
tx_size += ISCSI_CRC_LEN;
Expand All @@ -550,9 +550,8 @@ iscsit_xmit_nondatain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
if (conn->conn_ops->DataDigest) {
iscsit_do_crypto_hash_buf(conn->conn_tx_hash,
data_buf, data_buf_len,
padding,
(u8 *)&cmd->pad_bytes,
(u8 *)&cmd->data_crc);
padding, &cmd->pad_bytes,
&cmd->data_crc);

iov[niov].iov_base = &cmd->data_crc;
iov[niov++].iov_len = ISCSI_CRC_LEN;
Expand Down Expand Up @@ -597,7 +596,7 @@ iscsit_xmit_datain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,

iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->pdu,
ISCSI_HDR_LEN, 0, NULL,
(u8 *)header_digest);
header_digest);

iov[0].iov_len += ISCSI_CRC_LEN;
tx_size += ISCSI_CRC_LEN;
Expand Down Expand Up @@ -836,6 +835,7 @@ static int iscsit_add_reject_from_cmd(
unsigned char *buf)
{
struct iscsi_conn *conn;
const bool do_put = cmd->se_cmd.se_tfo != NULL;

if (!cmd->conn) {
pr_err("cmd->conn is NULL for ITT: 0x%08x\n",
Expand Down Expand Up @@ -866,7 +866,7 @@ static int iscsit_add_reject_from_cmd(
* Perform the kref_put now if se_cmd has already been setup by
* scsit_setup_scsi_cmd()
*/
if (cmd->se_cmd.se_tfo != NULL) {
if (do_put) {
pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n");
target_put_sess_cmd(&cmd->se_cmd);
}
Expand Down Expand Up @@ -1410,13 +1410,9 @@ static u32 iscsit_do_crypto_hash_sg(
return data_crc;
}

static void iscsit_do_crypto_hash_buf(
struct ahash_request *hash,
const void *buf,
u32 payload_length,
u32 padding,
u8 *pad_bytes,
u8 *data_crc)
static void iscsit_do_crypto_hash_buf(struct ahash_request *hash,
const void *buf, u32 payload_length, u32 padding,
const void *pad_bytes, void *data_crc)
{
struct scatterlist sg[2];

Expand Down Expand Up @@ -1462,9 +1458,9 @@ __iscsit_check_dataout_hdr(struct iscsi_conn *conn, void *buf,
iscsit_mod_dataout_timer(cmd);

if ((be32_to_cpu(hdr->offset) + payload_length) > cmd->se_cmd.data_length) {
pr_err("DataOut Offset: %u, Length %u greater than"
" iSCSI Command EDTL %u, protocol error.\n",
hdr->offset, payload_length, cmd->se_cmd.data_length);
pr_err("DataOut Offset: %u, Length %u greater than iSCSI Command EDTL %u, protocol error.\n",
be32_to_cpu(hdr->offset), payload_length,
cmd->se_cmd.data_length);
return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_INVALID, buf);
}

Expand Down Expand Up @@ -1878,10 +1874,9 @@ static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
}

if (conn->conn_ops->DataDigest) {
iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
ping_data, payload_length,
padding, cmd->pad_bytes,
(u8 *)&data_crc);
iscsit_do_crypto_hash_buf(conn->conn_rx_hash, ping_data,
payload_length, padding,
cmd->pad_bytes, &data_crc);

if (checksum != data_crc) {
pr_err("Ping data CRC32C DataDigest"
Expand Down Expand Up @@ -1962,7 +1957,6 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
struct iscsi_tmr_req *tmr_req;
struct iscsi_tm *hdr;
int out_of_order_cmdsn = 0, ret;
bool sess_ref = false;
u8 function, tcm_function = TMR_UNKNOWN;

hdr = (struct iscsi_tm *) buf;
Expand Down Expand Up @@ -1995,22 +1989,23 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,

cmd->data_direction = DMA_NONE;
cmd->tmr_req = kzalloc(sizeof(*cmd->tmr_req), GFP_KERNEL);
if (!cmd->tmr_req)
if (!cmd->tmr_req) {
return iscsit_add_reject_cmd(cmd,
ISCSI_REASON_BOOKMARK_NO_RESOURCES,
buf);
}

transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
conn->sess->se_sess, 0, DMA_NONE,
TCM_SIMPLE_TAG, cmd->sense_buffer + 2);

target_get_sess_cmd(&cmd->se_cmd, true);

/*
* TASK_REASSIGN for ERL=2 / connection stays inside of
* LIO-Target $FABRIC_MOD
*/
if (function != ISCSI_TM_FUNC_TASK_REASSIGN) {
transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
conn->sess->se_sess, 0, DMA_NONE,
TCM_SIMPLE_TAG, cmd->sense_buffer + 2);

target_get_sess_cmd(&cmd->se_cmd, true);
sess_ref = true;
tcm_function = iscsit_convert_tmf(function);
if (tcm_function == TMR_UNKNOWN) {
pr_err("Unknown iSCSI TMR Function:"
Expand Down Expand Up @@ -2101,12 +2096,14 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,

if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP)
if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) {
out_of_order_cmdsn = 1;
else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
} else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
target_put_sess_cmd(&cmd->se_cmd);
return 0;
else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
} else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
return -1;
}
}
iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));

Expand All @@ -2126,12 +2123,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
* For connection recovery, this is also the default action for
* TMR TASK_REASSIGN.
*/
if (sess_ref) {
pr_debug("Handle TMR, using sess_ref=true check\n");
target_put_sess_cmd(&cmd->se_cmd);
}

iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
target_put_sess_cmd(&cmd->se_cmd);
return 0;
}
EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd);
Expand Down Expand Up @@ -2287,10 +2280,9 @@ iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
goto reject;

if (conn->conn_ops->DataDigest) {
iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
text_in, payload_length,
padding, (u8 *)&pad_bytes,
(u8 *)&data_crc);
iscsit_do_crypto_hash_buf(conn->conn_rx_hash, text_in,
payload_length, padding,
&pad_bytes, &data_crc);

if (checksum != data_crc) {
pr_err("Text data CRC32C DataDigest"
Expand Down Expand Up @@ -3978,9 +3970,9 @@ static void iscsit_get_rx_pdu(struct iscsi_conn *conn)
return;
}

iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
buffer, ISCSI_HDR_LEN,
0, NULL, (u8 *)&checksum);
iscsit_do_crypto_hash_buf(conn->conn_rx_hash, buffer,
ISCSI_HDR_LEN, 0, NULL,
&checksum);

if (digest != checksum) {
pr_err("HeaderDigest CRC32C failed,"
Expand Down
3 changes: 2 additions & 1 deletion drivers/target/iscsi/iscsi_target_configfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1123,7 +1123,7 @@ static struct se_portal_group *lio_target_tiqn_addtpg(

ret = core_tpg_register(wwn, &tpg->tpg_se_tpg, SCSI_PROTOCOL_ISCSI);
if (ret < 0)
return NULL;
goto free_out;

ret = iscsit_tpg_add_portal_group(tiqn, tpg);
if (ret != 0)
Expand All @@ -1135,6 +1135,7 @@ static struct se_portal_group *lio_target_tiqn_addtpg(
return &tpg->tpg_se_tpg;
out:
core_tpg_deregister(&tpg->tpg_se_tpg);
free_out:
kfree(tpg);
return NULL;
}
Expand Down
7 changes: 3 additions & 4 deletions drivers/target/iscsi/iscsi_target_erl1.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include "iscsi_target_erl2.h"
#include "iscsi_target.h"

#define OFFLOAD_BUF_SIZE 32768
#define OFFLOAD_BUF_SIZE 32768U

/*
* Used to dump excess datain payload for certain error recovery
Expand All @@ -56,7 +56,7 @@ int iscsit_dump_data_payload(
if (conn->sess->sess_ops->RDMAExtensions)
return 0;

length = (buf_len > OFFLOAD_BUF_SIZE) ? OFFLOAD_BUF_SIZE : buf_len;
length = min(buf_len, OFFLOAD_BUF_SIZE);

buf = kzalloc(length, GFP_ATOMIC);
if (!buf) {
Expand All @@ -67,8 +67,7 @@ int iscsit_dump_data_payload(
memset(&iov, 0, sizeof(struct kvec));

while (offset < buf_len) {
size = ((offset + length) > buf_len) ?
(buf_len - offset) : length;
size = min(buf_len - offset, length);

iov.iov_len = size;
iov.iov_base = buf;
Expand Down
Loading

0 comments on commit eda5d47

Please sign in to comment.