Commit d5d5c182 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 the target-pending fixes for v4.12-rc7 that have been queued
  up for the last 2 weeks. This includes:

   - Fix a TMR related kref underflow detected by the recent refcount_t
     conversion in upstream.

   - Fix a iscsi-target corner case during explicit connection logout
     timeout failure.

   - Address last fallout in iscsi-target immediate data handling from
     v4.4 target-core now allowing control CDB payload underflow"

* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
  iscsi-target: Reject immediate data underflow larger than SCSI transfer length
  iscsi-target: Fix delayed logout processing greater than SECONDS_FOR_LOGOUT_COMP
  target: Fix kref->refcount underflow in transport_cmd_finish_abort
parents bb9b8fd2 abb85a9b
...@@ -1279,6 +1279,18 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, ...@@ -1279,6 +1279,18 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
*/ */
if (dump_payload) if (dump_payload)
goto after_immediate_data; goto after_immediate_data;
/*
* Check for underflow case where both EDTL and immediate data payload
* exceeds what is presented by CDB's TRANSFER LENGTH, and what has
* already been set in target_cmd_size_check() as se_cmd->data_length.
*
* For this special case, fail the command and dump the immediate data
* payload.
*/
if (cmd->first_burst_len > cmd->se_cmd.data_length) {
cmd->sense_reason = TCM_INVALID_CDB_FIELD;
goto after_immediate_data;
}
immed_ret = iscsit_handle_immediate_data(cmd, hdr, immed_ret = iscsit_handle_immediate_data(cmd, hdr,
cmd->first_burst_len); cmd->first_burst_len);
...@@ -4423,8 +4435,11 @@ static void iscsit_logout_post_handler_closesession( ...@@ -4423,8 +4435,11 @@ static void iscsit_logout_post_handler_closesession(
* always sleep waiting for RX/TX thread shutdown to complete * always sleep waiting for RX/TX thread shutdown to complete
* within iscsit_close_connection(). * within iscsit_close_connection().
*/ */
if (!conn->conn_transport->rdma_shutdown) if (!conn->conn_transport->rdma_shutdown) {
sleep = cmpxchg(&conn->tx_thread_active, true, false); sleep = cmpxchg(&conn->tx_thread_active, true, false);
if (!sleep)
return;
}
atomic_set(&conn->conn_logout_remove, 0); atomic_set(&conn->conn_logout_remove, 0);
complete(&conn->conn_logout_comp); complete(&conn->conn_logout_comp);
...@@ -4440,8 +4455,11 @@ static void iscsit_logout_post_handler_samecid( ...@@ -4440,8 +4455,11 @@ static void iscsit_logout_post_handler_samecid(
{ {
int sleep = 1; int sleep = 1;
if (!conn->conn_transport->rdma_shutdown) if (!conn->conn_transport->rdma_shutdown) {
sleep = cmpxchg(&conn->tx_thread_active, true, false); sleep = cmpxchg(&conn->tx_thread_active, true, false);
if (!sleep)
return;
}
atomic_set(&conn->conn_logout_remove, 0); atomic_set(&conn->conn_logout_remove, 0);
complete(&conn->conn_logout_comp); complete(&conn->conn_logout_comp);
......
...@@ -136,7 +136,7 @@ int init_se_kmem_caches(void); ...@@ -136,7 +136,7 @@ int init_se_kmem_caches(void);
void release_se_kmem_caches(void); void release_se_kmem_caches(void);
u32 scsi_get_new_index(scsi_index_t); u32 scsi_get_new_index(scsi_index_t);
void transport_subsystem_check_init(void); void transport_subsystem_check_init(void);
void transport_cmd_finish_abort(struct se_cmd *, int); int transport_cmd_finish_abort(struct se_cmd *, int);
unsigned char *transport_dump_cmd_direction(struct se_cmd *); unsigned char *transport_dump_cmd_direction(struct se_cmd *);
void transport_dump_dev_state(struct se_device *, char *, int *); void transport_dump_dev_state(struct se_device *, char *, int *);
void transport_dump_dev_info(struct se_device *, struct se_lun *, void transport_dump_dev_info(struct se_device *, struct se_lun *,
......
...@@ -75,7 +75,7 @@ void core_tmr_release_req(struct se_tmr_req *tmr) ...@@ -75,7 +75,7 @@ void core_tmr_release_req(struct se_tmr_req *tmr)
kfree(tmr); kfree(tmr);
} }
static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas) static int core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas)
{ {
unsigned long flags; unsigned long flags;
bool remove = true, send_tas; bool remove = true, send_tas;
...@@ -91,7 +91,7 @@ static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas) ...@@ -91,7 +91,7 @@ static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas)
transport_send_task_abort(cmd); transport_send_task_abort(cmd);
} }
transport_cmd_finish_abort(cmd, remove); return transport_cmd_finish_abort(cmd, remove);
} }
static int target_check_cdb_and_preempt(struct list_head *list, static int target_check_cdb_and_preempt(struct list_head *list,
...@@ -184,7 +184,7 @@ void core_tmr_abort_task( ...@@ -184,7 +184,7 @@ void core_tmr_abort_task(
cancel_work_sync(&se_cmd->work); cancel_work_sync(&se_cmd->work);
transport_wait_for_tasks(se_cmd); transport_wait_for_tasks(se_cmd);
transport_cmd_finish_abort(se_cmd, true); if (!transport_cmd_finish_abort(se_cmd, true))
target_put_sess_cmd(se_cmd); target_put_sess_cmd(se_cmd);
printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for"
...@@ -281,7 +281,7 @@ static void core_tmr_drain_tmr_list( ...@@ -281,7 +281,7 @@ static void core_tmr_drain_tmr_list(
cancel_work_sync(&cmd->work); cancel_work_sync(&cmd->work);
transport_wait_for_tasks(cmd); transport_wait_for_tasks(cmd);
transport_cmd_finish_abort(cmd, 1); if (!transport_cmd_finish_abort(cmd, 1))
target_put_sess_cmd(cmd); target_put_sess_cmd(cmd);
} }
} }
...@@ -380,7 +380,7 @@ static void core_tmr_drain_state_list( ...@@ -380,7 +380,7 @@ static void core_tmr_drain_state_list(
cancel_work_sync(&cmd->work); cancel_work_sync(&cmd->work);
transport_wait_for_tasks(cmd); transport_wait_for_tasks(cmd);
core_tmr_handle_tas_abort(cmd, tas); if (!core_tmr_handle_tas_abort(cmd, tas))
target_put_sess_cmd(cmd); target_put_sess_cmd(cmd);
} }
} }
......
...@@ -651,9 +651,10 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) ...@@ -651,9 +651,10 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
percpu_ref_put(&lun->lun_ref); percpu_ref_put(&lun->lun_ref);
} }
void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) int transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
{ {
bool ack_kref = (cmd->se_cmd_flags & SCF_ACK_KREF); bool ack_kref = (cmd->se_cmd_flags & SCF_ACK_KREF);
int ret = 0;
if (cmd->se_cmd_flags & SCF_SE_LUN_CMD) if (cmd->se_cmd_flags & SCF_SE_LUN_CMD)
transport_lun_remove_cmd(cmd); transport_lun_remove_cmd(cmd);
...@@ -665,9 +666,11 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) ...@@ -665,9 +666,11 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
cmd->se_tfo->aborted_task(cmd); cmd->se_tfo->aborted_task(cmd);
if (transport_cmd_check_stop_to_fabric(cmd)) if (transport_cmd_check_stop_to_fabric(cmd))
return; return 1;
if (remove && ack_kref) if (remove && ack_kref)
transport_put_cmd(cmd); ret = transport_put_cmd(cmd);
return ret;
} }
static void target_complete_failure_work(struct work_struct *work) static void target_complete_failure_work(struct work_struct *work)
......
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