Commit 13caa8ed authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending

Pull SCSI target fixes from Nicholas Bellinger:
 "Here are the outstanding target fixes queued up for v3.12-rc4 code.

  The highlights include:

   - Make vhost/scsi tag percpu_ida_alloc() use GFP_ATOMIC
   - Allow sess_cmd_map allocation failure fallback to use vzalloc
   - Fix COMPARE_AND_WRITE se_cmd->data_length bug with FILEIO backends
   - Fixes for COMPARE_AND_WRITE callback recursive failure OOPs + non
     zero scsi_status bug
   - Make iscsi-target do acknowledgement tag release from RX context
   - Setup iscsi-target with extra (cmdsn_depth / 2) percpu_ida tags

  Also included is a iscsi-target patch CC'ed for v3.10+ that avoids
  legacy wait_for_task=true release during fast-past StatSN
  acknowledgement, and two other SRP target related patches that address
  long-standing issues that are CC'ed for v3.3+.

  Extra thanks to Thomas Glanzmann for his testing feedback with
  COMPARE_AND_WRITE + EXTENDED_COPY VAAI logic"

* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
  iscsi-target; Allow an extra tag_num / 2 number of percpu_ida tags
  iscsi-target: Perform release of acknowledged tags from RX context
  iscsi-target: Only perform wait_for_tasks when performing shutdown
  target: Fail on non zero scsi_status in compare_and_write_callback
  target: Fix recursive COMPARE_AND_WRITE callback failure
  target: Reset data_length for COMPARE_AND_WRITE to NoLB * block_size
  ib_srpt: always set response for task management
  target: Fall back to vzalloc upon ->sess_cmd_map kzalloc failure
  vhost/scsi: Use GFP_ATOMIC with percpu_ida_alloc for obtaining tag
  ib_srpt: Destroy cm_id before destroying QP.
  target: Fix xop->dbl assignment in target_xcopy_parse_segdesc_02
parents 831ae3c1 9e20ae33
......@@ -1588,7 +1588,7 @@ static int srpt_build_tskmgmt_rsp(struct srpt_rdma_ch *ch,
int resp_data_len;
int resp_len;
resp_data_len = (rsp_code == SRP_TSK_MGMT_SUCCESS) ? 0 : 4;
resp_data_len = 4;
resp_len = sizeof(*srp_rsp) + resp_data_len;
srp_rsp = ioctx->ioctx.buf;
......@@ -1600,11 +1600,9 @@ static int srpt_build_tskmgmt_rsp(struct srpt_rdma_ch *ch,
+ atomic_xchg(&ch->req_lim_delta, 0));
srp_rsp->tag = tag;
if (rsp_code != SRP_TSK_MGMT_SUCCESS) {
srp_rsp->flags |= SRP_RSP_FLAG_RSPVALID;
srp_rsp->resp_data_len = cpu_to_be32(resp_data_len);
srp_rsp->data[3] = rsp_code;
}
srp_rsp->flags |= SRP_RSP_FLAG_RSPVALID;
srp_rsp->resp_data_len = cpu_to_be32(resp_data_len);
srp_rsp->data[3] = rsp_code;
return resp_len;
}
......@@ -2358,6 +2356,8 @@ static void srpt_release_channel_work(struct work_struct *w)
transport_deregister_session(se_sess);
ch->sess = NULL;
ib_destroy_cm_id(ch->cm_id);
srpt_destroy_ch_ib(ch);
srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring,
......@@ -2368,8 +2368,6 @@ static void srpt_release_channel_work(struct work_struct *w)
list_del(&ch->list);
spin_unlock_irq(&sdev->spinlock);
ib_destroy_cm_id(ch->cm_id);
if (ch->release_done)
complete(ch->release_done);
......
......@@ -753,7 +753,8 @@ static void iscsit_unmap_iovec(struct iscsi_cmd *cmd)
static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
{
struct iscsi_cmd *cmd;
LIST_HEAD(ack_list);
struct iscsi_cmd *cmd, *cmd_p;
conn->exp_statsn = exp_statsn;
......@@ -761,19 +762,23 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
return;
spin_lock_bh(&conn->cmd_lock);
list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
list_for_each_entry_safe(cmd, cmd_p, &conn->conn_cmd_list, i_conn_node) {
spin_lock(&cmd->istate_lock);
if ((cmd->i_state == ISTATE_SENT_STATUS) &&
iscsi_sna_lt(cmd->stat_sn, exp_statsn)) {
cmd->i_state = ISTATE_REMOVE;
spin_unlock(&cmd->istate_lock);
iscsit_add_cmd_to_immediate_queue(cmd, conn,
cmd->i_state);
list_move_tail(&cmd->i_conn_node, &ack_list);
continue;
}
spin_unlock(&cmd->istate_lock);
}
spin_unlock_bh(&conn->cmd_lock);
list_for_each_entry_safe(cmd, cmd_p, &ack_list, i_conn_node) {
list_del(&cmd->i_conn_node);
iscsit_free_cmd(cmd, false);
}
}
static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
......
......@@ -1192,7 +1192,7 @@ int iscsi_target_locate_portal(
*/
alloc_tags:
tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth);
tag_num += ISCSIT_EXTRA_TAGS;
tag_num += (tag_num / 2) + ISCSIT_EXTRA_TAGS;
tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size;
ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size);
......
......@@ -736,7 +736,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
* Fallthrough
*/
case ISCSI_OP_SCSI_TMFUNC:
rc = transport_generic_free_cmd(&cmd->se_cmd, 1);
rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
if (!rc && shutdown && se_cmd && se_cmd->se_sess) {
__iscsit_free_cmd(cmd, true, shutdown);
target_put_sess_cmd(se_cmd->se_sess, se_cmd);
......@@ -752,7 +752,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
se_cmd = &cmd->se_cmd;
__iscsit_free_cmd(cmd, true, shutdown);
rc = transport_generic_free_cmd(&cmd->se_cmd, 1);
rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
if (!rc && shutdown && se_cmd->se_sess) {
__iscsit_free_cmd(cmd, true, shutdown);
target_put_sess_cmd(se_cmd->se_sess, se_cmd);
......
......@@ -349,7 +349,16 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
/*
* Only set SCF_COMPARE_AND_WRITE_POST to force a response fall-through
* within target_complete_ok_work() if the command was successfully
* sent to the backend driver.
*/
spin_lock_irq(&cmd->t_state_lock);
if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status)
cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
spin_unlock_irq(&cmd->t_state_lock);
/*
* Unlock ->caw_sem originally obtained during sbc_compare_and_write()
* before the original READ I/O submission.
......@@ -363,7 +372,7 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
struct scatterlist *write_sg = NULL, *sg;
unsigned char *buf, *addr;
unsigned char *buf = NULL, *addr;
struct sg_mapping_iter m;
unsigned int offset = 0, len;
unsigned int nlbas = cmd->t_task_nolb;
......@@ -378,6 +387,15 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
*/
if (!cmd->t_data_sg || !cmd->t_bidi_data_sg)
return TCM_NO_SENSE;
/*
* Immediately exit + release dev->caw_sem if command has already
* been failed with a non-zero SCSI status.
*/
if (cmd->scsi_status) {
pr_err("compare_and_write_callback: non zero scsi_status:"
" 0x%02x\n", cmd->scsi_status);
goto out;
}
buf = kzalloc(cmd->data_length, GFP_KERNEL);
if (!buf) {
......@@ -508,6 +526,12 @@ sbc_compare_and_write(struct se_cmd *cmd)
cmd->transport_complete_callback = NULL;
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
/*
* Reset cmd->data_length to individual block_size in order to not
* confuse backend drivers that depend on this value matching the
* size of the I/O being submitted.
*/
cmd->data_length = cmd->t_task_nolb * dev->dev_attrib.block_size;
ret = cmd->execute_rw(cmd, cmd->t_bidi_data_sg, cmd->t_bidi_data_nents,
DMA_FROM_DEVICE);
......
......@@ -236,17 +236,24 @@ int transport_alloc_session_tags(struct se_session *se_sess,
{
int rc;
se_sess->sess_cmd_map = kzalloc(tag_num * tag_size, GFP_KERNEL);
se_sess->sess_cmd_map = kzalloc(tag_num * tag_size,
GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
if (!se_sess->sess_cmd_map) {
pr_err("Unable to allocate se_sess->sess_cmd_map\n");
return -ENOMEM;
se_sess->sess_cmd_map = vzalloc(tag_num * tag_size);
if (!se_sess->sess_cmd_map) {
pr_err("Unable to allocate se_sess->sess_cmd_map\n");
return -ENOMEM;
}
}
rc = percpu_ida_init(&se_sess->sess_tag_pool, tag_num);
if (rc < 0) {
pr_err("Unable to init se_sess->sess_tag_pool,"
" tag_num: %u\n", tag_num);
kfree(se_sess->sess_cmd_map);
if (is_vmalloc_addr(se_sess->sess_cmd_map))
vfree(se_sess->sess_cmd_map);
else
kfree(se_sess->sess_cmd_map);
se_sess->sess_cmd_map = NULL;
return -ENOMEM;
}
......@@ -412,7 +419,10 @@ void transport_free_session(struct se_session *se_sess)
{
if (se_sess->sess_cmd_map) {
percpu_ida_destroy(&se_sess->sess_tag_pool);
kfree(se_sess->sess_cmd_map);
if (is_vmalloc_addr(se_sess->sess_cmd_map))
vfree(se_sess->sess_cmd_map);
else
kfree(se_sess->sess_cmd_map);
}
kmem_cache_free(se_sess_cache, se_sess);
}
......
......@@ -298,8 +298,8 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op
(unsigned long long)xop->dst_lba);
if (dc != 0) {
xop->dbl = (desc[29] << 16) & 0xff;
xop->dbl |= (desc[30] << 8) & 0xff;
xop->dbl = (desc[29] & 0xff) << 16;
xop->dbl |= (desc[30] & 0xff) << 8;
xop->dbl |= desc[31] & 0xff;
pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl);
......
......@@ -728,7 +728,12 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq,
}
se_sess = tv_nexus->tvn_se_sess;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_KERNEL);
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
if (tag < 0) {
pr_err("Unable to obtain tag for tcm_vhost_cmd\n");
return ERR_PTR(-ENOMEM);
}
cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag];
sg = cmd->tvc_sgl;
pages = cmd->tvc_upages;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment