Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 25 Nov 2017 05:19:20 +0000 (19:19 -1000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 25 Nov 2017 05:19:20 +0000 (19:19 -1000)
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
  ...

1  2 
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_erl1.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/target_core_alua.h
drivers/target/target_core_configfs.c
drivers/target/target_core_internal.h
drivers/target/target_core_user.c
include/target/target_core_base.h

index 9e67c7678c86d2af0aa4617a40686103efa55fd2,3b7bb589d3018cbd88c6a2c591ff21684203edaf..9eb10d34682cfb23dc65a00092f519d2f46657e4
@@@ -372,8 -372,6 +372,8 @@@ struct iscsi_np *iscsit_add_np
        init_completion(&np->np_restart_comp);
        INIT_LIST_HEAD(&np->np_list);
  
 +      timer_setup(&np->np_login_timer, iscsi_handle_login_thread_timeout, 0);
 +
        ret = iscsi_target_setup_login_socket(np, sockaddr);
        if (ret != 0) {
                kfree(np);
@@@ -502,7 -500,7 +502,7 @@@ void iscsit_aborted_task(struct iscsi_c
  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
@@@ -523,7 -521,7 +523,7 @@@ iscsit_xmit_nondatain_pdu(struct iscsi_
  
                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;
                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;
@@@ -597,7 -594,7 +596,7 @@@ iscsit_xmit_datain_pdu(struct iscsi_con
  
                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;
@@@ -836,6 -833,7 +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",
         * 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);
        }
@@@ -1410,13 -1408,9 +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];
  
@@@ -1462,9 -1456,9 +1458,9 @@@ __iscsit_check_dataout_hdr(struct iscsi
        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);
        }
  
@@@ -1878,10 -1872,9 +1874,9 @@@ static int iscsit_handle_nop_out(struc
                }
  
                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"
@@@ -1962,7 -1955,6 +1957,6 @@@ iscsit_handle_task_mgt_cmd(struct iscsi
        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;
  
        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:"
@@@ -2101,12 -2094,14 +2096,14 @@@ attach
  
        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));
  
         * 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);
@@@ -2287,10 -2278,9 +2280,9 @@@ iscsit_handle_text_cmd(struct iscsi_con
                        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"
@@@ -3978,9 -3968,9 +3970,9 @@@ static void iscsit_get_rx_pdu(struct is
                                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,"
index 76184094a0cf944efc26c0aa32626b71e56b07b8,659efafb43ecc532511a6dce571394617105fa3c..5efa42b939a104052f4fe0ea8ec94d09961cd8c0
@@@ -34,7 -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
@@@ -56,7 -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) {
@@@ -67,8 -67,7 +67,7 @@@
        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;
@@@ -1148,11 -1147,11 +1147,11 @@@ static int iscsit_set_dataout_timeout_v
  /*
   *    NOTE: Called from interrupt (timer) context.
   */
 -static void iscsit_handle_dataout_timeout(unsigned long data)
 +void iscsit_handle_dataout_timeout(struct timer_list *t)
  {
        u32 pdu_length = 0, pdu_offset = 0;
        u32 r2t_length = 0, r2t_offset = 0;
 -      struct iscsi_cmd *cmd = (struct iscsi_cmd *) data;
 +      struct iscsi_cmd *cmd = from_timer(cmd, t, dataout_timer);
        struct iscsi_conn *conn = cmd->conn;
        struct iscsi_session *sess = NULL;
        struct iscsi_node_attrib *na;
@@@ -1264,9 -1263,13 +1263,9 @@@ void iscsit_start_dataout_timer
        pr_debug("Starting DataOUT timer for ITT: 0x%08x on"
                " CID: %hu.\n", cmd->init_task_tag, conn->cid);
  
 -      init_timer(&cmd->dataout_timer);
 -      cmd->dataout_timer.expires = (get_jiffies_64() + na->dataout_timeout * HZ);
 -      cmd->dataout_timer.data = (unsigned long)cmd;
 -      cmd->dataout_timer.function = iscsit_handle_dataout_timeout;
        cmd->dataout_timer_flags &= ~ISCSI_TF_STOP;
        cmd->dataout_timer_flags |= ISCSI_TF_RUNNING;
 -      add_timer(&cmd->dataout_timer);
 +      mod_timer(&cmd->dataout_timer, jiffies + na->dataout_timeout * HZ);
  }
  
  void iscsit_stop_dataout_timer(struct iscsi_cmd *cmd)
index 54f20f184dd6b5c8422f8e72f81e173c70d5efd0,70c6b9bfc04ee86582884fd7ee79e94c953621c4..4435bf374d2d55fd79d9dc75dbd086a7ba6dbc28
@@@ -176,7 -176,6 +176,7 @@@ struct iscsi_cmd *iscsit_allocate_cmd(s
        spin_lock_init(&cmd->istate_lock);
        spin_lock_init(&cmd->error_lock);
        spin_lock_init(&cmd->r2t_lock);
 +      timer_setup(&cmd->dataout_timer, iscsit_handle_dataout_timeout, 0);
  
        return cmd;
  }
@@@ -695,6 -694,8 +695,8 @@@ void iscsit_release_cmd(struct iscsi_cm
        struct iscsi_session *sess;
        struct se_cmd *se_cmd = &cmd->se_cmd;
  
+       WARN_ON(!list_empty(&cmd->i_conn_node));
        if (cmd->conn)
                sess = cmd->conn->sess;
        else
@@@ -717,6 -718,8 +719,8 @@@ void __iscsit_free_cmd(struct iscsi_cm
  {
        struct iscsi_conn *conn = cmd->conn;
  
+       WARN_ON(!list_empty(&cmd->i_conn_node));
        if (cmd->data_direction == DMA_TO_DEVICE) {
                iscsit_stop_dataout_timer(cmd);
                iscsit_free_r2ts_from_list(cmd);
@@@ -881,9 -884,9 +885,9 @@@ static int iscsit_add_nopin(struct iscs
        return 0;
  }
  
 -static void iscsit_handle_nopin_response_timeout(unsigned long data)
 +void iscsit_handle_nopin_response_timeout(struct timer_list *t)
  {
 -      struct iscsi_conn *conn = (struct iscsi_conn *) data;
 +      struct iscsi_conn *conn = from_timer(conn, t, nopin_response_timer);
  
        iscsit_inc_conn_usage_count(conn);
  
@@@ -950,10 -953,14 +954,10 @@@ void iscsit_start_nopin_response_timer(
                return;
        }
  
 -      init_timer(&conn->nopin_response_timer);
 -      conn->nopin_response_timer.expires =
 -              (get_jiffies_64() + na->nopin_response_timeout * HZ);
 -      conn->nopin_response_timer.data = (unsigned long)conn;
 -      conn->nopin_response_timer.function = iscsit_handle_nopin_response_timeout;
        conn->nopin_response_timer_flags &= ~ISCSI_TF_STOP;
        conn->nopin_response_timer_flags |= ISCSI_TF_RUNNING;
 -      add_timer(&conn->nopin_response_timer);
 +      mod_timer(&conn->nopin_response_timer,
 +                jiffies + na->nopin_response_timeout * HZ);
  
        pr_debug("Started NOPIN Response Timer on CID: %d to %u"
                " seconds\n", conn->cid, na->nopin_response_timeout);
@@@ -977,9 -984,9 +981,9 @@@ void iscsit_stop_nopin_response_timer(s
        spin_unlock_bh(&conn->nopin_timer_lock);
  }
  
 -static void iscsit_handle_nopin_timeout(unsigned long data)
 +void iscsit_handle_nopin_timeout(struct timer_list *t)
  {
 -      struct iscsi_conn *conn = (struct iscsi_conn *) data;
 +      struct iscsi_conn *conn = from_timer(conn, t, nopin_timer);
  
        iscsit_inc_conn_usage_count(conn);
  
@@@ -1012,9 -1019,13 +1016,9 @@@ void __iscsit_start_nopin_timer(struct 
        if (conn->nopin_timer_flags & ISCSI_TF_RUNNING)
                return;
  
 -      init_timer(&conn->nopin_timer);
 -      conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ);
 -      conn->nopin_timer.data = (unsigned long)conn;
 -      conn->nopin_timer.function = iscsit_handle_nopin_timeout;
        conn->nopin_timer_flags &= ~ISCSI_TF_STOP;
        conn->nopin_timer_flags |= ISCSI_TF_RUNNING;
 -      add_timer(&conn->nopin_timer);
 +      mod_timer(&conn->nopin_timer, jiffies + na->nopin_timeout * HZ);
  
        pr_debug("Started NOPIN Timer on CID: %d at %u second"
                " interval\n", conn->cid, na->nopin_timeout);
@@@ -1036,9 -1047,13 +1040,9 @@@ void iscsit_start_nopin_timer(struct is
                return;
        }
  
 -      init_timer(&conn->nopin_timer);
 -      conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ);
 -      conn->nopin_timer.data = (unsigned long)conn;
 -      conn->nopin_timer.function = iscsit_handle_nopin_timeout;
        conn->nopin_timer_flags &= ~ISCSI_TF_STOP;
        conn->nopin_timer_flags |= ISCSI_TF_RUNNING;
 -      add_timer(&conn->nopin_timer);
 +      mod_timer(&conn->nopin_timer, jiffies + na->nopin_timeout * HZ);
  
        pr_debug("Started NOPIN Timer on CID: %d at %u second"
                        " interval\n", conn->cid, na->nopin_timeout);
index 1902cb5c3b52c32de28290199012e9c2ae500e4a,90643300cd32a38546a454fb2439df53f7287f3b..fc9637cce82564dfb2d8b83b160cf1cd8c8b5760
@@@ -1,4 -1,3 +1,4 @@@
 +/* SPDX-License-Identifier: GPL-2.0 */
  #ifndef TARGET_CORE_ALUA_H
  #define TARGET_CORE_ALUA_H
  
   */
  #define ALUA_DEFAULT_IMPLICIT_TRANS_SECS                      0
  #define ALUA_MAX_IMPLICIT_TRANS_SECS                  255
- /*
-  * Used by core_alua_update_tpg_primary_metadata() and
-  * core_alua_update_tpg_secondary_metadata()
-  */
- #define ALUA_METADATA_PATH_LEN                                512
- /*
-  * Used by core_alua_update_tpg_secondary_metadata()
-  */
- #define ALUA_SECONDARY_METADATA_WWN_LEN                       256
  
  /* Used by core_alua_update_tpg_(primary,secondary)_metadata */
  #define ALUA_MD_BUF_LEN                                       1024
index bd87cc26c6e500cdb813732c291f4d33bbc46964,3790df42ade403873594771c43610cfc2ad5aaf6..72b1cd1bf9d9fdcfc64084f0177df66230e77450
@@@ -307,7 -307,7 +307,7 @@@ static struct configfs_attribute *targe
  /*
   * Provides Fabrics Groups and Item Attributes for /sys/kernel/config/target/
   */
 -static struct config_item_type target_core_fabrics_item = {
 +static const struct config_item_type target_core_fabrics_item = {
        .ct_group_ops   = &target_core_fabric_group_ops,
        .ct_attrs       = target_core_fabric_item_attrs,
        .ct_owner       = THIS_MODULE,
@@@ -1611,12 -1611,12 +1611,12 @@@ static match_table_t tokens = 
        {Opt_res_type, "res_type=%d"},
        {Opt_res_scope, "res_scope=%d"},
        {Opt_res_all_tg_pt, "res_all_tg_pt=%d"},
-       {Opt_mapped_lun, "mapped_lun=%lld"},
+       {Opt_mapped_lun, "mapped_lun=%u"},
        {Opt_target_fabric, "target_fabric=%s"},
        {Opt_target_node, "target_node=%s"},
        {Opt_tpgt, "tpgt=%d"},
        {Opt_port_rtpi, "port_rtpi=%d"},
-       {Opt_target_lun, "target_lun=%lld"},
+       {Opt_target_lun, "target_lun=%u"},
        {Opt_err, NULL}
  };
  
@@@ -1693,7 -1693,7 +1693,7 @@@ static ssize_t target_pr_res_aptpl_meta
                        }
                        break;
                case Opt_sa_res_key:
-                       ret = kstrtoull(args->from, 0, &tmp_ll);
+                       ret = match_u64(args,  &tmp_ll);
                        if (ret < 0) {
                                pr_err("kstrtoull() failed for sa_res_key=\n");
                                goto out;
                        all_tg_pt = (int)arg;
                        break;
                case Opt_mapped_lun:
-                       ret = match_int(args, &arg);
+                       ret = match_u64(args, &tmp_ll);
                        if (ret)
                                goto out;
-                       mapped_lun = (u64)arg;
+                       mapped_lun = (u64)tmp_ll;
                        break;
                /*
                 * PR APTPL Metadata for Target Port
                                goto out;
                        break;
                case Opt_target_lun:
-                       ret = match_int(args, &arg);
+                       ret = match_u64(args, &tmp_ll);
                        if (ret)
                                goto out;
-                       target_lun = (u64)arg;
+                       target_lun = (u64)tmp_ll;
                        break;
                default:
                        break;
@@@ -2376,7 -2376,7 +2376,7 @@@ static struct configfs_item_operations 
        .release                = target_core_alua_lu_gp_release,
  };
  
 -static struct config_item_type target_core_alua_lu_gp_cit = {
 +static const struct config_item_type target_core_alua_lu_gp_cit = {
        .ct_item_ops            = &target_core_alua_lu_gp_ops,
        .ct_attrs               = target_core_alua_lu_gp_attrs,
        .ct_owner               = THIS_MODULE,
@@@ -2434,7 -2434,7 +2434,7 @@@ static struct configfs_group_operation
        .drop_item              = &target_core_alua_drop_lu_gp,
  };
  
 -static struct config_item_type target_core_alua_lu_gps_cit = {
 +static const struct config_item_type target_core_alua_lu_gps_cit = {
        .ct_item_ops            = NULL,
        .ct_group_ops           = &target_core_alua_lu_gps_group_ops,
        .ct_owner               = THIS_MODULE,
@@@ -2813,7 -2813,7 +2813,7 @@@ static struct configfs_item_operations 
        .release                = target_core_alua_tg_pt_gp_release,
  };
  
 -static struct config_item_type target_core_alua_tg_pt_gp_cit = {
 +static const struct config_item_type target_core_alua_tg_pt_gp_cit = {
        .ct_item_ops            = &target_core_alua_tg_pt_gp_ops,
        .ct_attrs               = target_core_alua_tg_pt_gp_attrs,
        .ct_owner               = THIS_MODULE,
@@@ -2884,7 -2884,7 +2884,7 @@@ TB_CIT_SETUP(dev_alua_tg_pt_gps, NULL, 
   * core/alua/lu_gps and core/alua/tg_pt_gps that are attached to
   * target_core_alua_cit in target_core_init_configfs() below.
   */
 -static struct config_item_type target_core_alua_cit = {
 +static const struct config_item_type target_core_alua_cit = {
        .ct_item_ops            = NULL,
        .ct_attrs               = NULL,
        .ct_owner               = THIS_MODULE,
@@@ -3105,7 -3105,7 +3105,7 @@@ static struct configfs_item_operations 
        .release                = target_core_hba_release,
  };
  
 -static struct config_item_type target_core_hba_cit = {
 +static const struct config_item_type target_core_hba_cit = {
        .ct_item_ops            = &target_core_hba_item_ops,
        .ct_group_ops           = &target_core_hba_group_ops,
        .ct_attrs               = target_core_hba_attrs,
@@@ -3188,7 -3188,7 +3188,7 @@@ static struct configfs_group_operation
        .drop_item      = target_core_call_delhbafromtarget,
  };
  
 -static struct config_item_type target_core_cit = {
 +static const struct config_item_type target_core_cit = {
        .ct_item_ops    = NULL,
        .ct_group_ops   = &target_core_group_ops,
        .ct_attrs       = NULL,
index 18e3eb16e756735f7fe8028715c4f090979dcb2a,2c5004ffb581a84be9febf073bdecc5687f4fa18..9384d19a7326c81274e589a58cd0a56b4f8bb98a
@@@ -1,4 -1,3 +1,4 @@@
 +/* SPDX-License-Identifier: GPL-2.0 */
  #ifndef TARGET_CORE_INTERNAL_H
  #define TARGET_CORE_INTERNAL_H
  
@@@ -89,6 -88,7 +89,7 @@@ int   target_for_each_device(int (*fn)(st
                               void *data);
  
  /* target_core_configfs.c */
+ extern struct configfs_item_operations target_core_dev_item_ops;
  void  target_setup_backend_cits(struct target_backend *);
  
  /* target_core_fabric_configfs.c */
index 9469695f5871aea064bea2e4b4f65e32742c3cb4,bf4fd40dde2bde27324ffbb42ffed1604f8f1154..cc2468a299d3381ab6f1a89bed45f6575f2e5af3
@@@ -150,6 -150,8 +150,8 @@@ struct tcmu_dev 
        wait_queue_head_t nl_cmd_wq;
  
        char dev_config[TCMU_CONFIG_LEN];
+       int nl_reply_supported;
  };
  
  #define TCMU_DEV(_se_dev) container_of(_se_dev, struct tcmu_dev, se_dev)
@@@ -430,7 -432,6 +432,6 @@@ static struct tcmu_cmd *tcmu_alloc_cmd(
        struct se_device *se_dev = se_cmd->se_dev;
        struct tcmu_dev *udev = TCMU_DEV(se_dev);
        struct tcmu_cmd *tcmu_cmd;
-       int cmd_id;
  
        tcmu_cmd = kmem_cache_zalloc(tcmu_cmd_cache, GFP_KERNEL);
        if (!tcmu_cmd)
  
        tcmu_cmd->se_cmd = se_cmd;
        tcmu_cmd->tcmu_dev = udev;
-       if (udev->cmd_time_out)
-               tcmu_cmd->deadline = jiffies +
-                                       msecs_to_jiffies(udev->cmd_time_out);
  
        tcmu_cmd_reset_dbi_cur(tcmu_cmd);
        tcmu_cmd->dbi_cnt = tcmu_cmd_get_block_cnt(tcmu_cmd);
                return NULL;
        }
  
-       idr_preload(GFP_KERNEL);
-       spin_lock_irq(&udev->commands_lock);
-       cmd_id = idr_alloc(&udev->commands, tcmu_cmd, 0,
-               USHRT_MAX, GFP_NOWAIT);
-       spin_unlock_irq(&udev->commands_lock);
-       idr_preload_end();
-       if (cmd_id < 0) {
-               tcmu_free_cmd(tcmu_cmd);
-               return NULL;
-       }
-       tcmu_cmd->cmd_id = cmd_id;
        return tcmu_cmd;
  }
  
@@@ -746,6 -731,30 +731,30 @@@ static inline size_t tcmu_cmd_get_cmd_s
        return command_size;
  }
  
+ static int tcmu_setup_cmd_timer(struct tcmu_cmd *tcmu_cmd)
+ {
+       struct tcmu_dev *udev = tcmu_cmd->tcmu_dev;
+       unsigned long tmo = udev->cmd_time_out;
+       int cmd_id;
+       if (tcmu_cmd->cmd_id)
+               return 0;
+       cmd_id = idr_alloc(&udev->commands, tcmu_cmd, 1, USHRT_MAX, GFP_NOWAIT);
+       if (cmd_id < 0) {
+               pr_err("tcmu: Could not allocate cmd id.\n");
+               return cmd_id;
+       }
+       tcmu_cmd->cmd_id = cmd_id;
+       if (!tmo)
+               return 0;
+       tcmu_cmd->deadline = round_jiffies_up(jiffies + msecs_to_jiffies(tmo));
+       mod_timer(&udev->timeout, tcmu_cmd->deadline);
+       return 0;
+ }
  static sense_reason_t
  tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
  {
        entry = (void *) mb + CMDR_OFF + cmd_head;
        memset(entry, 0, command_size);
        tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_CMD);
-       entry->hdr.cmd_id = tcmu_cmd->cmd_id;
  
        /* Handle allocating space from the data area */
        tcmu_cmd_reset_dbi_cur(tcmu_cmd);
        }
        entry->req.iov_bidi_cnt = iov_cnt;
  
+       ret = tcmu_setup_cmd_timer(tcmu_cmd);
+       if (ret) {
+               tcmu_cmd_free_data(tcmu_cmd, tcmu_cmd->dbi_cnt);
+               mutex_unlock(&udev->cmdr_lock);
+               return TCM_OUT_OF_RESOURCES;
+       }
+       entry->hdr.cmd_id = tcmu_cmd->cmd_id;
        /*
         * Recalaulate the command's base size and size according
         * to the actual needs
  static sense_reason_t
  tcmu_queue_cmd(struct se_cmd *se_cmd)
  {
-       struct se_device *se_dev = se_cmd->se_dev;
-       struct tcmu_dev *udev = TCMU_DEV(se_dev);
        struct tcmu_cmd *tcmu_cmd;
        sense_reason_t ret;
  
        ret = tcmu_queue_cmd_ring(tcmu_cmd);
        if (ret != TCM_NO_SENSE) {
                pr_err("TCMU: Could not queue command\n");
-               spin_lock_irq(&udev->commands_lock);
-               idr_remove(&udev->commands, tcmu_cmd->cmd_id);
-               spin_unlock_irq(&udev->commands_lock);
  
                tcmu_free_cmd(tcmu_cmd);
        }
@@@ -985,7 -996,7 +996,7 @@@ static unsigned int tcmu_handle_complet
        mb = udev->mb_addr;
        tcmu_flush_dcache_range(mb, sizeof(*mb));
  
 -      while (udev->cmdr_last_cleaned != ACCESS_ONCE(mb->cmd_tail)) {
 +      while (udev->cmdr_last_cleaned != READ_ONCE(mb->cmd_tail)) {
  
                struct tcmu_cmd_entry *entry = (void *) mb + CMDR_OFF + udev->cmdr_last_cleaned;
                struct tcmu_cmd *cmd;
@@@ -1112,6 -1123,8 +1123,8 @@@ static struct se_device *tcmu_alloc_dev
        init_waitqueue_head(&udev->nl_cmd_wq);
        spin_lock_init(&udev->nl_cmd_lock);
  
+       INIT_RADIX_TREE(&udev->data_blocks, GFP_KERNEL);
        return &udev->se_dev;
  }
  
@@@ -1280,10 -1293,54 +1293,54 @@@ static void tcmu_dev_call_rcu(struct rc
        kfree(udev);
  }
  
+ static int tcmu_check_and_free_pending_cmd(struct tcmu_cmd *cmd)
+ {
+       if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
+               kmem_cache_free(tcmu_cmd_cache, cmd);
+               return 0;
+       }
+       return -EINVAL;
+ }
+ static void tcmu_blocks_release(struct tcmu_dev *udev)
+ {
+       int i;
+       struct page *page;
+       /* Try to release all block pages */
+       mutex_lock(&udev->cmdr_lock);
+       for (i = 0; i <= udev->dbi_max; i++) {
+               page = radix_tree_delete(&udev->data_blocks, i);
+               if (page) {
+                       __free_page(page);
+                       atomic_dec(&global_db_count);
+               }
+       }
+       mutex_unlock(&udev->cmdr_lock);
+ }
  static void tcmu_dev_kref_release(struct kref *kref)
  {
        struct tcmu_dev *udev = container_of(kref, struct tcmu_dev, kref);
        struct se_device *dev = &udev->se_dev;
+       struct tcmu_cmd *cmd;
+       bool all_expired = true;
+       int i;
+       vfree(udev->mb_addr);
+       udev->mb_addr = NULL;
+       /* Upper layer should drain all requests before calling this */
+       spin_lock_irq(&udev->commands_lock);
+       idr_for_each_entry(&udev->commands, cmd, i) {
+               if (tcmu_check_and_free_pending_cmd(cmd) != 0)
+                       all_expired = false;
+       }
+       idr_destroy(&udev->commands);
+       spin_unlock_irq(&udev->commands_lock);
+       WARN_ON(!all_expired);
+       tcmu_blocks_release(udev);
  
        call_rcu(&dev->rcu_head, tcmu_dev_call_rcu);
  }
@@@ -1306,6 -1363,10 +1363,10 @@@ static void tcmu_init_genl_cmd_reply(st
  
        if (!tcmu_kern_cmd_reply_supported)
                return;
+       if (udev->nl_reply_supported <= 0)
+               return;
  relock:
        spin_lock(&udev->nl_cmd_lock);
  
@@@ -1332,6 -1393,9 +1393,9 @@@ static int tcmu_wait_genl_cmd_reply(str
        if (!tcmu_kern_cmd_reply_supported)
                return 0;
  
+       if (udev->nl_reply_supported <= 0)
+               return 0;
        pr_debug("sleeping for nl reply\n");
        wait_for_completion(&nl_cmd->complete);
  
@@@ -1476,8 -1540,6 +1540,6 @@@ static int tcmu_configure_device(struc
        WARN_ON(udev->data_size % PAGE_SIZE);
        WARN_ON(udev->data_size % DATA_BLOCK_SIZE);
  
-       INIT_RADIX_TREE(&udev->data_blocks, GFP_KERNEL);
        info->version = __stringify(TCMU_MAILBOX_VERSION);
  
        info->mem[0].name = "tcm-user command & data buffer";
                dev->dev_attrib.emulate_write_cache = 0;
        dev->dev_attrib.hw_queue_depth = 128;
  
+       /* If user didn't explicitly disable netlink reply support, use
+        * module scope setting.
+        */
+       if (udev->nl_reply_supported >= 0)
+               udev->nl_reply_supported = tcmu_kern_cmd_reply_supported;
        /*
         * Get a ref incase userspace does a close on the uio device before
         * LIO has initiated tcmu_free_device.
@@@ -1527,6 -1595,7 +1595,7 @@@ err_netlink
        uio_unregister_device(&udev->uio_info);
  err_register:
        vfree(udev->mb_addr);
+       udev->mb_addr = NULL;
  err_vzalloc:
        kfree(info->name);
        info->name = NULL;
        return ret;
  }
  
- static int tcmu_check_and_free_pending_cmd(struct tcmu_cmd *cmd)
- {
-       if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) {
-               kmem_cache_free(tcmu_cmd_cache, cmd);
-               return 0;
-       }
-       return -EINVAL;
- }
  static bool tcmu_dev_configured(struct tcmu_dev *udev)
  {
        return udev->uio_info.uio_dev ? true : false;
  }
  
- static void tcmu_blocks_release(struct tcmu_dev *udev)
- {
-       int i;
-       struct page *page;
-       /* Try to release all block pages */
-       mutex_lock(&udev->cmdr_lock);
-       for (i = 0; i <= udev->dbi_max; i++) {
-               page = radix_tree_delete(&udev->data_blocks, i);
-               if (page) {
-                       __free_page(page);
-                       atomic_dec(&global_db_count);
-               }
-       }
-       mutex_unlock(&udev->cmdr_lock);
- }
  static void tcmu_free_device(struct se_device *dev)
  {
        struct tcmu_dev *udev = TCMU_DEV(dev);
  static void tcmu_destroy_device(struct se_device *dev)
  {
        struct tcmu_dev *udev = TCMU_DEV(dev);
-       struct tcmu_cmd *cmd;
-       bool all_expired = true;
-       int i;
  
        del_timer_sync(&udev->timeout);
  
        list_del(&udev->node);
        mutex_unlock(&root_udev_mutex);
  
-       vfree(udev->mb_addr);
-       /* Upper layer should drain all requests before calling this */
-       spin_lock_irq(&udev->commands_lock);
-       idr_for_each_entry(&udev->commands, cmd, i) {
-               if (tcmu_check_and_free_pending_cmd(cmd) != 0)
-                       all_expired = false;
-       }
-       idr_destroy(&udev->commands);
-       spin_unlock_irq(&udev->commands_lock);
-       WARN_ON(!all_expired);
-       tcmu_blocks_release(udev);
        tcmu_netlink_event(udev, TCMU_CMD_REMOVED_DEVICE, 0, NULL);
  
        uio_unregister_device(&udev->uio_info);
  
  enum {
        Opt_dev_config, Opt_dev_size, Opt_hw_block_size, Opt_hw_max_sectors,
-       Opt_err,
+       Opt_nl_reply_supported, Opt_err,
  };
  
  static match_table_t tokens = {
        {Opt_dev_size, "dev_size=%u"},
        {Opt_hw_block_size, "hw_block_size=%u"},
        {Opt_hw_max_sectors, "hw_max_sectors=%u"},
+       {Opt_nl_reply_supported, "nl_reply_supported=%d"},
        {Opt_err, NULL}
  };
  
@@@ -1692,6 -1719,17 +1719,17 @@@ static ssize_t tcmu_set_configfs_dev_pa
                        ret = tcmu_set_dev_attrib(&args[0],
                                        &(dev->dev_attrib.hw_max_sectors));
                        break;
+               case Opt_nl_reply_supported:
+                       arg_p = match_strdup(&args[0]);
+                       if (!arg_p) {
+                               ret = -ENOMEM;
+                               break;
+                       }
+                       ret = kstrtoint(arg_p, 0, &udev->nl_reply_supported);
+                       kfree(arg_p);
+                       if (ret < 0)
+                               pr_err("kstrtoint() failed for nl_reply_supported=\n");
+                       break;
                default:
                        break;
                }
@@@ -1734,8 -1772,7 +1772,7 @@@ static ssize_t tcmu_cmd_time_out_show(s
  {
        struct se_dev_attrib *da = container_of(to_config_group(item),
                                        struct se_dev_attrib, da_group);
-       struct tcmu_dev *udev = container_of(da->da_dev,
-                                       struct tcmu_dev, se_dev);
+       struct tcmu_dev *udev = TCMU_DEV(da->da_dev);
  
        return snprintf(page, PAGE_SIZE, "%lu\n", udev->cmd_time_out / MSEC_PER_SEC);
  }
@@@ -1842,6 -1879,34 +1879,34 @@@ static ssize_t tcmu_dev_size_store(stru
  }
  CONFIGFS_ATTR(tcmu_, dev_size);
  
+ static ssize_t tcmu_nl_reply_supported_show(struct config_item *item,
+               char *page)
+ {
+       struct se_dev_attrib *da = container_of(to_config_group(item),
+                                               struct se_dev_attrib, da_group);
+       struct tcmu_dev *udev = TCMU_DEV(da->da_dev);
+       return snprintf(page, PAGE_SIZE, "%d\n", udev->nl_reply_supported);
+ }
+ static ssize_t tcmu_nl_reply_supported_store(struct config_item *item,
+               const char *page, size_t count)
+ {
+       struct se_dev_attrib *da = container_of(to_config_group(item),
+                                               struct se_dev_attrib, da_group);
+       struct tcmu_dev *udev = TCMU_DEV(da->da_dev);
+       s8 val;
+       int ret;
+       ret = kstrtos8(page, 0, &val);
+       if (ret < 0)
+               return ret;
+       udev->nl_reply_supported = val;
+       return count;
+ }
+ CONFIGFS_ATTR(tcmu_, nl_reply_supported);
  static ssize_t tcmu_emulate_write_cache_show(struct config_item *item,
                                             char *page)
  {
@@@ -1884,6 -1949,7 +1949,7 @@@ static struct configfs_attribute *tcmu_
        &tcmu_attr_dev_config,
        &tcmu_attr_dev_size,
        &tcmu_attr_emulate_write_cache,
+       &tcmu_attr_nl_reply_supported,
        NULL,
  };
  
index f5db145e68ecae901ed071a70fe95db4045791b8,ccf501b8359cd7a28f991327f313b8370f05f011..2c8d8115469dce4c2fc92bbf2ee91a1e0bccae5f
@@@ -1,4 -1,3 +1,4 @@@
 +/* SPDX-License-Identifier: GPL-2.0 */
  #ifndef TARGET_CORE_BASE_H
  #define TARGET_CORE_BASE_H
  
@@@ -182,6 -181,7 +182,7 @@@ enum tcm_sense_reason_table 
        TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE   = R(0x1a),
        TCM_TOO_MANY_SEGMENT_DESCS              = R(0x1b),
        TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE  = R(0x1c),
+       TCM_INSUFFICIENT_REGISTRATION_RESOURCES = R(0x1d),
  #undef R
  };
  
@@@ -490,6 -490,7 +491,7 @@@ struct se_cmd 
  #define CMD_T_STOP            (1 << 5)
  #define CMD_T_TAS             (1 << 10)
  #define CMD_T_FABRIC_STOP     (1 << 11)
+ #define CMD_T_PRE_EXECUTE     (1 << 12)
        spinlock_t              t_state_lock;
        struct kref             cmd_kref;
        struct completion       t_transport_stop_comp;