Commit 3243f50b authored by Linus Torvalds's avatar Linus Torvalds

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

Pull SCSI target fixes from Nicholas Bellinger:
 "This contains a v4.2-rc specific RCU module unload regression bug-fix,
  a long-standing iscsi-target bug-fix for duplicate target_xfer_tags
  during NOP processing from Alexei, and two more small REPORT_LUNs
  emulation related patches to make Solaris FC host LUN scanning happy
  from Roland.

  There is also one patch not included that allows target-core to limit
  the number of fabric driver SGLs per I/O request using residuals, that
  is currently required as a work-around for FC hosts which don't honor
  EVPD block-limits settings.  At this point, it will most likely become
  for-next material"

* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
  target: Fix handling of small allocation lengths in REPORT LUNS
  target: REPORT LUNS should return LUN 0 even for dynamic ACLs
  target/iscsi: Fix double free of a TUR followed by a solicited NOPOUT
  target: Perform RCU callback barrier before backend/fabric unload
parents 3bd8f7d8 0f69a387
......@@ -968,9 +968,9 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
cmd->cmd_flags |= ICF_NON_IMMEDIATE_UNSOLICITED_DATA;
conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
if (hdr->flags & ISCSI_FLAG_CMD_READ) {
if (hdr->flags & ISCSI_FLAG_CMD_READ)
cmd->targ_xfer_tag = session_get_next_ttt(conn->sess);
} else if (hdr->flags & ISCSI_FLAG_CMD_WRITE)
else
cmd->targ_xfer_tag = 0xFFFFFFFF;
cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
......
......@@ -457,8 +457,15 @@ void target_unregister_template(const struct target_core_fabric_ops *fo)
if (!strcmp(t->tf_ops->name, fo->name)) {
BUG_ON(atomic_read(&t->tf_access_cnt));
list_del(&t->tf_list);
mutex_unlock(&g_tf_lock);
/*
* Wait for any outstanding fabric se_deve_entry->rcu_head
* callbacks to complete post kfree_rcu(), before allowing
* fabric driver unload of TFO->module to proceed.
*/
rcu_barrier();
kfree(t);
break;
return;
}
}
mutex_unlock(&g_tf_lock);
......
......@@ -84,8 +84,16 @@ void target_backend_unregister(const struct target_backend_ops *ops)
list_for_each_entry(tb, &backend_list, list) {
if (tb->ops == ops) {
list_del(&tb->list);
mutex_unlock(&backend_mutex);
/*
* Wait for any outstanding backend driver ->rcu_head
* callbacks to complete post TBO->free_device() ->
* call_rcu(), before allowing backend driver module
* unload of target_backend_ops->owner to proceed.
*/
rcu_barrier();
kfree(tb);
break;
return;
}
}
mutex_unlock(&backend_mutex);
......
......@@ -1203,17 +1203,13 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
struct se_dev_entry *deve;
struct se_session *sess = cmd->se_sess;
struct se_node_acl *nacl;
struct scsi_lun slun;
unsigned char *buf;
u32 lun_count = 0, offset = 8;
if (cmd->data_length < 16) {
pr_warn("REPORT LUNS allocation length %u too small\n",
cmd->data_length);
return TCM_INVALID_CDB_FIELD;
}
__be32 len;
buf = transport_kmap_data_sg(cmd);
if (!buf)
if (cmd->data_length && !buf)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
/*
......@@ -1221,11 +1217,9 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
* coming via a target_core_mod PASSTHROUGH op, and not through
* a $FABRIC_MOD. In that case, report LUN=0 only.
*/
if (!sess) {
int_to_scsilun(0, (struct scsi_lun *)&buf[offset]);
lun_count = 1;
if (!sess)
goto done;
}
nacl = sess->se_node_acl;
rcu_read_lock();
......@@ -1236,10 +1230,12 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
* See SPC2-R20 7.19.
*/
lun_count++;
if ((offset + 8) > cmd->data_length)
if (offset >= cmd->data_length)
continue;
int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]);
int_to_scsilun(deve->mapped_lun, &slun);
memcpy(buf + offset, &slun,
min(8u, cmd->data_length - offset));
offset += 8;
}
rcu_read_unlock();
......@@ -1248,12 +1244,22 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
* See SPC3 r07, page 159.
*/
done:
lun_count *= 8;
buf[0] = ((lun_count >> 24) & 0xff);
buf[1] = ((lun_count >> 16) & 0xff);
buf[2] = ((lun_count >> 8) & 0xff);
buf[3] = (lun_count & 0xff);
transport_kunmap_data_sg(cmd);
/*
* If no LUNs are accessible, report virtual LUN 0.
*/
if (lun_count == 0) {
int_to_scsilun(0, &slun);
if (cmd->data_length > 8)
memcpy(buf + offset, &slun,
min(8u, cmd->data_length - offset));
lun_count = 1;
}
if (buf) {
len = cpu_to_be32(lun_count * 8);
memcpy(buf, &len, min_t(int, sizeof len, cmd->data_length));
transport_kunmap_data_sg(cmd);
}
target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8);
return 0;
......
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