Commit e477f3e0 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:
 "Here are current target-pending fixes for v4.0-rc5 code that have made
  their way into the queue over the last weeks.

  The fixes this round include:

   - Fix long-standing iser-target logout bug related to early
     conn_logout_comp completion, resulting in iscsi_conn use-after-tree
     OOpsen.  (Sagi + nab)

   - Fix long-standing tcm_fc bug in ft_invl_hw_context() failure
     handing for DDP hw offload.  (DanC)

   - Fix incorrect use of unprotected __transport_register_session() in
     tcm_qla2xxx + other single local se_node_acl fabrics.  (Bart)

   - Fix reference leak in target_submit_cmd() -> target_get_sess_cmd()
     for ack_kref=1 failure path.  (Bart)

   - Fix pSCSI backend ->get_device_type() statistics OOPs with
     un-configured device.  (Olaf + nab)

   - Fix virtual LUN=0 target_configure_device failure OOPs at modprobe
     time.  (Claudio + nab)

   - Fix FUA write false positive failure regression in v4.0-rc1 code.
     (Christophe Vu-Brugier + HCH)"

* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
  target: do not reject FUA CDBs when write cache is enabled but emulate_write_cache is 0
  target: Fix virtual LUN=0 target_configure_device failure OOPs
  target/pscsi: Fix NULL pointer dereference in get_device_type
  tcm_fc: missing curly braces in ft_invl_hw_context()
  target: Fix reference leak in target_get_sess_cmd() error path
  loop/usb/vhost-scsi/xen-scsiback: Fix use of __transport_register_session
  tcm_qla2xxx: Fix incorrect use of __transport_register_session
  iscsi-target: Avoid early conn_logout_comp for iser connections
  Revert "iscsi-target: Avoid IN_LOGOUT failure case for iser-target"
  target: Disallow changing of WRITE cache/FUA attrs after export
parents da6b9a20 9bc6548f
...@@ -1596,7 +1596,7 @@ static int tcm_qla2xxx_check_initiator_node_acl( ...@@ -1596,7 +1596,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
/* /*
* Finally register the new FC Nexus with TCM * Finally register the new FC Nexus with TCM
*/ */
__transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess); transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess);
return 0; return 0;
} }
......
...@@ -4256,11 +4256,17 @@ int iscsit_close_connection( ...@@ -4256,11 +4256,17 @@ int iscsit_close_connection(
pr_debug("Closing iSCSI connection CID %hu on SID:" pr_debug("Closing iSCSI connection CID %hu on SID:"
" %u\n", conn->cid, sess->sid); " %u\n", conn->cid, sess->sid);
/* /*
* Always up conn_logout_comp just in case the RX Thread is sleeping * Always up conn_logout_comp for the traditional TCP case just in case
* and the logout response never got sent because the connection * the RX Thread in iscsi_target_rx_opcode() is sleeping and the logout
* failed. * response never got sent because the connection failed.
*
* However for iser-target, isert_wait4logout() is using conn_logout_comp
* to signal logout response TX interrupt completion. Go ahead and skip
* this for iser since isert_rx_opcode() does not wait on logout failure,
* and to avoid iscsi_conn pointer dereference in iser-target code.
*/ */
complete(&conn->conn_logout_comp); if (conn->conn_transport->transport_type == ISCSI_TCP)
complete(&conn->conn_logout_comp);
iscsi_release_thread_set(conn); iscsi_release_thread_set(conn);
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <target/target_core_fabric.h> #include <target/target_core_fabric.h>
#include <target/iscsi/iscsi_target_core.h> #include <target/iscsi/iscsi_target_core.h>
#include <target/iscsi/iscsi_transport.h>
#include "iscsi_target_seq_pdu_list.h" #include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_tq.h" #include "iscsi_target_tq.h"
#include "iscsi_target_erl0.h" #include "iscsi_target_erl0.h"
...@@ -940,8 +939,7 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn) ...@@ -940,8 +939,7 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) { if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
spin_unlock_bh(&conn->state_lock); spin_unlock_bh(&conn->state_lock);
if (conn->conn_transport->transport_type == ISCSI_TCP) iscsit_close_connection(conn);
iscsit_close_connection(conn);
return; return;
} }
......
...@@ -953,11 +953,8 @@ static int tcm_loop_make_nexus( ...@@ -953,11 +953,8 @@ static int tcm_loop_make_nexus(
transport_free_session(tl_nexus->se_sess); transport_free_session(tl_nexus->se_sess);
goto out; goto out;
} }
/* /* Now, register the SAS I_T Nexus as active. */
* Now, register the SAS I_T Nexus as active with the call to transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
* transport_register_session()
*/
__transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
tl_nexus->se_sess, tl_nexus); tl_nexus->se_sess, tl_nexus);
tl_tpg->tl_nexus = tl_nexus; tl_tpg->tl_nexus = tl_nexus;
pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated" pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated"
......
...@@ -650,6 +650,18 @@ static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size) ...@@ -650,6 +650,18 @@ static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
return aligned_max_sectors; return aligned_max_sectors;
} }
bool se_dev_check_wce(struct se_device *dev)
{
bool wce = false;
if (dev->transport->get_write_cache)
wce = dev->transport->get_write_cache(dev);
else if (dev->dev_attrib.emulate_write_cache > 0)
wce = true;
return wce;
}
int se_dev_set_max_unmap_lba_count( int se_dev_set_max_unmap_lba_count(
struct se_device *dev, struct se_device *dev,
u32 max_unmap_lba_count) u32 max_unmap_lba_count)
...@@ -767,6 +779,16 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag) ...@@ -767,6 +779,16 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
pr_err("Illegal value %d\n", flag); pr_err("Illegal value %d\n", flag);
return -EINVAL; return -EINVAL;
} }
if (flag &&
dev->transport->get_write_cache) {
pr_err("emulate_fua_write not supported for this device\n");
return -EINVAL;
}
if (dev->export_count) {
pr_err("emulate_fua_write cannot be changed with active"
" exports: %d\n", dev->export_count);
return -EINVAL;
}
dev->dev_attrib.emulate_fua_write = flag; dev->dev_attrib.emulate_fua_write = flag;
pr_debug("dev[%p]: SE Device Forced Unit Access WRITEs: %d\n", pr_debug("dev[%p]: SE Device Forced Unit Access WRITEs: %d\n",
dev, dev->dev_attrib.emulate_fua_write); dev, dev->dev_attrib.emulate_fua_write);
...@@ -801,7 +823,11 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag) ...@@ -801,7 +823,11 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
pr_err("emulate_write_cache not supported for this device\n"); pr_err("emulate_write_cache not supported for this device\n");
return -EINVAL; return -EINVAL;
} }
if (dev->export_count) {
pr_err("emulate_write_cache cannot be changed with active"
" exports: %d\n", dev->export_count);
return -EINVAL;
}
dev->dev_attrib.emulate_write_cache = flag; dev->dev_attrib.emulate_write_cache = flag;
pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n", pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n",
dev, dev->dev_attrib.emulate_write_cache); dev, dev->dev_attrib.emulate_write_cache);
...@@ -1534,8 +1560,6 @@ int target_configure_device(struct se_device *dev) ...@@ -1534,8 +1560,6 @@ int target_configure_device(struct se_device *dev)
ret = dev->transport->configure_device(dev); ret = dev->transport->configure_device(dev);
if (ret) if (ret)
goto out; goto out;
dev->dev_flags |= DF_CONFIGURED;
/* /*
* XXX: there is not much point to have two different values here.. * XXX: there is not much point to have two different values here..
*/ */
...@@ -1597,6 +1621,8 @@ int target_configure_device(struct se_device *dev) ...@@ -1597,6 +1621,8 @@ int target_configure_device(struct se_device *dev)
list_add_tail(&dev->g_dev_node, &g_device_list); list_add_tail(&dev->g_dev_node, &g_device_list);
mutex_unlock(&g_device_mutex); mutex_unlock(&g_device_mutex);
dev->dev_flags |= DF_CONFIGURED;
return 0; return 0;
out_free_alua: out_free_alua:
......
...@@ -1121,7 +1121,7 @@ static u32 pscsi_get_device_type(struct se_device *dev) ...@@ -1121,7 +1121,7 @@ static u32 pscsi_get_device_type(struct se_device *dev)
struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);
struct scsi_device *sd = pdv->pdv_sd; struct scsi_device *sd = pdv->pdv_sd;
return sd->type; return (sd) ? sd->type : TYPE_NO_LUN;
} }
static sector_t pscsi_get_blocks(struct se_device *dev) static sector_t pscsi_get_blocks(struct se_device *dev)
......
...@@ -708,8 +708,7 @@ sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb) ...@@ -708,8 +708,7 @@ sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
} }
} }
if (cdb[1] & 0x8) { if (cdb[1] & 0x8) {
if (!dev->dev_attrib.emulate_fua_write || if (!dev->dev_attrib.emulate_fua_write || !se_dev_check_wce(dev)) {
!dev->dev_attrib.emulate_write_cache) {
pr_err("Got CDB: 0x%02x with FUA bit set, but device" pr_err("Got CDB: 0x%02x with FUA bit set, but device"
" does not advertise support for FUA write\n", " does not advertise support for FUA write\n",
cdb[0]); cdb[0]);
......
...@@ -454,19 +454,6 @@ spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) ...@@ -454,19 +454,6 @@ spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
} }
EXPORT_SYMBOL(spc_emulate_evpd_83); EXPORT_SYMBOL(spc_emulate_evpd_83);
static bool
spc_check_dev_wce(struct se_device *dev)
{
bool wce = false;
if (dev->transport->get_write_cache)
wce = dev->transport->get_write_cache(dev);
else if (dev->dev_attrib.emulate_write_cache > 0)
wce = true;
return wce;
}
/* Extended INQUIRY Data VPD Page */ /* Extended INQUIRY Data VPD Page */
static sense_reason_t static sense_reason_t
spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
...@@ -490,7 +477,7 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) ...@@ -490,7 +477,7 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
buf[5] = 0x07; buf[5] = 0x07;
/* If WriteCache emulation is enabled, set V_SUP */ /* If WriteCache emulation is enabled, set V_SUP */
if (spc_check_dev_wce(dev)) if (se_dev_check_wce(dev))
buf[6] = 0x01; buf[6] = 0x01;
/* If an LBA map is present set R_SUP */ /* If an LBA map is present set R_SUP */
spin_lock(&cmd->se_dev->t10_alua.lba_map_lock); spin_lock(&cmd->se_dev->t10_alua.lba_map_lock);
...@@ -897,7 +884,7 @@ static int spc_modesense_caching(struct se_cmd *cmd, u8 pc, u8 *p) ...@@ -897,7 +884,7 @@ static int spc_modesense_caching(struct se_cmd *cmd, u8 pc, u8 *p)
if (pc == 1) if (pc == 1)
goto out; goto out;
if (spc_check_dev_wce(dev)) if (se_dev_check_wce(dev))
p[2] = 0x04; /* Write Cache Enable */ p[2] = 0x04; /* Write Cache Enable */
p[12] = 0x20; /* Disabled Read Ahead */ p[12] = 0x20; /* Disabled Read Ahead */
...@@ -1009,7 +996,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) ...@@ -1009,7 +996,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
(cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
spc_modesense_write_protect(&buf[length], type); spc_modesense_write_protect(&buf[length], type);
if ((spc_check_dev_wce(dev)) && if ((se_dev_check_wce(dev)) &&
(dev->dev_attrib.emulate_fua_write > 0)) (dev->dev_attrib.emulate_fua_write > 0))
spc_modesense_dpofua(&buf[length], type); spc_modesense_dpofua(&buf[length], type);
......
...@@ -2389,6 +2389,10 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, ...@@ -2389,6 +2389,10 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
out: out:
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
if (ret && ack_kref)
target_put_sess_cmd(se_sess, se_cmd);
return ret; return ret;
} }
EXPORT_SYMBOL(target_get_sess_cmd); EXPORT_SYMBOL(target_get_sess_cmd);
......
...@@ -359,7 +359,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd) ...@@ -359,7 +359,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
ep = fc_seq_exch(seq); ep = fc_seq_exch(seq);
if (ep) { if (ep) {
lport = ep->lp; lport = ep->lp;
if (lport && (ep->xid <= lport->lro_xid)) if (lport && (ep->xid <= lport->lro_xid)) {
/* /*
* "ddp_done" trigger invalidation of HW * "ddp_done" trigger invalidation of HW
* specific DDP context * specific DDP context
...@@ -374,6 +374,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd) ...@@ -374,6 +374,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
* identified using ep->xid) * identified using ep->xid)
*/ */
cmd->was_ddp_setup = 0; cmd->was_ddp_setup = 0;
}
} }
} }
} }
...@@ -1740,10 +1740,9 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name) ...@@ -1740,10 +1740,9 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
goto err_session; goto err_session;
} }
/* /*
* Now register the TCM vHost virtual I_T Nexus as active with the * Now register the TCM vHost virtual I_T Nexus as active.
* call to __transport_register_session()
*/ */
__transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
tv_nexus->tvn_se_sess, tv_nexus); tv_nexus->tvn_se_sess, tv_nexus);
tpg->tpg_nexus = tv_nexus; tpg->tpg_nexus = tv_nexus;
mutex_unlock(&tpg->tpg_mutex); mutex_unlock(&tpg->tpg_mutex);
......
...@@ -1956,10 +1956,9 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg, ...@@ -1956,10 +1956,9 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
goto out; goto out;
} }
/* /*
* Now register the TCM vhost virtual I_T Nexus as active with the * Now register the TCM vhost virtual I_T Nexus as active.
* call to __transport_register_session()
*/ */
__transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
tv_nexus->tvn_se_sess, tv_nexus); tv_nexus->tvn_se_sess, tv_nexus);
tpg->tpg_nexus = tv_nexus; tpg->tpg_nexus = tv_nexus;
......
...@@ -1659,11 +1659,8 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg, ...@@ -1659,11 +1659,8 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg,
name); name);
goto out; goto out;
} }
/* /* Now register the TCM pvscsi virtual I_T Nexus as active. */
* Now register the TCM pvscsi virtual I_T Nexus as active with the transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
* call to __transport_register_session()
*/
__transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
tv_nexus->tvn_se_sess, tv_nexus); tv_nexus->tvn_se_sess, tv_nexus);
tpg->tpg_nexus = tv_nexus; tpg->tpg_nexus = tv_nexus;
......
...@@ -111,6 +111,7 @@ void array_free(void *array, int n); ...@@ -111,6 +111,7 @@ void array_free(void *array, int n);
void target_core_setup_sub_cits(struct se_subsystem_api *); void target_core_setup_sub_cits(struct se_subsystem_api *);
/* attribute helpers from target_core_device.c for backend drivers */ /* attribute helpers from target_core_device.c for backend drivers */
bool se_dev_check_wce(struct se_device *);
int se_dev_set_max_unmap_lba_count(struct se_device *, u32); int se_dev_set_max_unmap_lba_count(struct se_device *, u32);
int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32); int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);
int se_dev_set_unmap_granularity(struct se_device *, u32); int se_dev_set_unmap_granularity(struct se_device *, u32);
......
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