Merge git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 21 Mar 2015 18:24:38 +0000 (11:24 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 21 Mar 2015 18:24:38 +0000 (11:24 -0700)
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

14 files changed:
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_erl0.c
drivers/target/loopback/tcm_loop.c
drivers/target/target_core_device.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tfc_io.c
drivers/usb/gadget/legacy/tcm_usb_gadget.c
drivers/vhost/scsi.c
drivers/xen/xen-scsiback.c
include/target/target_core_backend.h

index 99f43b7..ab4879e 100644 (file)
@@ -1596,7 +1596,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
        /*
         * 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;
 }
index 50bad55..2accb6e 100644 (file)
@@ -4256,11 +4256,17 @@ int iscsit_close_connection(
        pr_debug("Closing iSCSI connection CID %hu on SID:"
                " %u\n", conn->cid, sess->sid);
        /*
-        * Always up conn_logout_comp just in case the RX Thread is sleeping
-        * and the logout response never got sent because the connection
-        * failed.
+        * Always up conn_logout_comp for the traditional TCP case just in case
+        * the RX Thread in iscsi_target_rx_opcode() is sleeping and the logout
+        * 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);
 
index 1c197ba..bdd8731 100644 (file)
@@ -22,7 +22,6 @@
 #include <target/target_core_fabric.h>
 
 #include <target/iscsi/iscsi_target_core.h>
-#include <target/iscsi/iscsi_transport.h>
 #include "iscsi_target_seq_pdu_list.h"
 #include "iscsi_target_tq.h"
 #include "iscsi_target_erl0.h"
@@ -940,8 +939,7 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
 
        if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
                spin_unlock_bh(&conn->state_lock);
-               if (conn->conn_transport->transport_type == ISCSI_TCP)
-                       iscsit_close_connection(conn);
+               iscsit_close_connection(conn);
                return;
        }
 
index 6b3c329..c36bd7c 100644 (file)
@@ -953,11 +953,8 @@ static int tcm_loop_make_nexus(
                transport_free_session(tl_nexus->se_sess);
                goto out;
        }
-       /*
-        * Now, register the SAS I_T Nexus as active with the call to
-        * transport_register_session()
-        */
-       __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
+       /* Now, register the SAS I_T Nexus as active. */
+       transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl,
                        tl_nexus->se_sess, tl_nexus);
        tl_tpg->tl_nexus = tl_nexus;
        pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated"
index 58f49ff..79b4ec3 100644 (file)
@@ -650,6 +650,18 @@ static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
        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(
        struct se_device *dev,
        u32 max_unmap_lba_count)
@@ -767,6 +779,16 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
                pr_err("Illegal value %d\n", flag);
                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;
        pr_debug("dev[%p]: SE Device Forced Unit Access WRITEs: %d\n",
                        dev, dev->dev_attrib.emulate_fua_write);
@@ -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");
                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;
        pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n",
                        dev, dev->dev_attrib.emulate_write_cache);
@@ -1534,8 +1560,6 @@ int target_configure_device(struct se_device *dev)
        ret = dev->transport->configure_device(dev);
        if (ret)
                goto out;
-       dev->dev_flags |= DF_CONFIGURED;
-
        /*
         * XXX: there is not much point to have two different values here..
         */
@@ -1597,6 +1621,8 @@ int target_configure_device(struct se_device *dev)
        list_add_tail(&dev->g_dev_node, &g_device_list);
        mutex_unlock(&g_device_mutex);
 
+       dev->dev_flags |= DF_CONFIGURED;
+
        return 0;
 
 out_free_alua:
index 1045dcd..f6c954c 100644 (file)
@@ -1121,7 +1121,7 @@ static u32 pscsi_get_device_type(struct se_device *dev)
        struct pscsi_dev_virt *pdv = PSCSI_DEV(dev);
        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)
index 9a2f9d3..3e72974 100644 (file)
@@ -708,8 +708,7 @@ sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
                }
        }
        if (cdb[1] & 0x8) {
-               if (!dev->dev_attrib.emulate_fua_write ||
-                   !dev->dev_attrib.emulate_write_cache) {
+               if (!dev->dev_attrib.emulate_fua_write || !se_dev_check_wce(dev)) {
                        pr_err("Got CDB: 0x%02x with FUA bit set, but device"
                               " does not advertise support for FUA write\n",
                               cdb[0]);
index 460e931..6c8bd6b 100644 (file)
@@ -454,19 +454,6 @@ check_scsi_name:
 }
 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 */
 static sense_reason_t
 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;
 
        /* If WriteCache emulation is enabled, set V_SUP */
-       if (spc_check_dev_wce(dev))
+       if (se_dev_check_wce(dev))
                buf[6] = 0x01;
        /* If an LBA map is present set R_SUP */
        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)
        if (pc == 1)
                goto out;
 
-       if (spc_check_dev_wce(dev))
+       if (se_dev_check_wce(dev))
                p[2] = 0x04; /* Write Cache Enable */
        p[12] = 0x20; /* Disabled Read Ahead */
 
@@ -1009,7 +996,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
             (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
                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))
                spc_modesense_dpofua(&buf[length], type);
 
index 0adc0f6..ac3cbab 100644 (file)
@@ -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);
 out:
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+       if (ret && ack_kref)
+               target_put_sess_cmd(se_sess, se_cmd);
+
        return ret;
 }
 EXPORT_SYMBOL(target_get_sess_cmd);
index 97b486c..583e755 100644 (file)
@@ -359,7 +359,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
                ep = fc_seq_exch(seq);
                if (ep) {
                        lport = ep->lp;
-                       if (lport && (ep->xid <= lport->lro_xid))
+                       if (lport && (ep->xid <= lport->lro_xid)) {
                                /*
                                 * "ddp_done" trigger invalidation of HW
                                 * specific DDP context
@@ -374,6 +374,7 @@ void ft_invl_hw_context(struct ft_cmd *cmd)
                                 * identified using ep->xid)
                                 */
                                cmd->was_ddp_setup = 0;
+                       }
                }
        }
 }
index 3a49416..6e0a019 100644 (file)
@@ -1740,10 +1740,9 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
                goto err_session;
        }
        /*
-        * Now register the TCM vHost virtual I_T Nexus as active with the
-        * call to __transport_register_session()
+        * Now register the TCM vHost virtual I_T Nexus as active.
         */
-       __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);
        tpg->tpg_nexus = tv_nexus;
        mutex_unlock(&tpg->tpg_mutex);
index 8d4f3f1..71df240 100644 (file)
@@ -1956,10 +1956,9 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
                goto out;
        }
        /*
-        * Now register the TCM vhost virtual I_T Nexus as active with the
-        * call to __transport_register_session()
+        * Now register the TCM vhost virtual I_T Nexus as active.
         */
-       __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);
        tpg->tpg_nexus = tv_nexus;
 
index 9faca6a..42bd55a 100644 (file)
@@ -1659,11 +1659,8 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg,
                         name);
                goto out;
        }
-       /*
-        * Now register the TCM pvscsi virtual I_T Nexus as active with the
-        * call to __transport_register_session()
-        */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+       /* Now register the TCM pvscsi virtual I_T Nexus as active. */
+       transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
                        tv_nexus->tvn_se_sess, tv_nexus);
        tpg->tpg_nexus = tv_nexus;
 
index db81c65..d61be72 100644 (file)
@@ -111,6 +111,7 @@ void        array_free(void *array, int n);
 void   target_core_setup_sub_cits(struct se_subsystem_api *);
 
 /* 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_block_desc_count(struct se_device *, u32);
 int    se_dev_set_unmap_granularity(struct se_device *, u32);