aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-06-25 13:36:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-06-25 13:36:44 -0400
commitd5d5c1825e85a144e67448ad777eff441ddb907f (patch)
tree56d65b81ace7e253e5709fd90363e90824a407d2
parentbb9b8fd26b50c9ec822805b9d877bec9d88acff4 (diff)
parentabb85a9b512e8ca7ad04a5a8a6db9664fe644974 (diff)
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
-rw-r--r--drivers/target/iscsi/iscsi_target.c22
-rw-r--r--drivers/target/target_core_internal.h2
-rw-r--r--drivers/target/target_core_tmr.c16
-rw-r--r--drivers/target/target_core_transport.c9
4 files changed, 35 insertions, 14 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 0d8f81591bed..3fdca2cdd8da 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1279,6 +1279,18 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
1279 */ 1279 */
1280 if (dump_payload) 1280 if (dump_payload)
1281 goto after_immediate_data; 1281 goto after_immediate_data;
1282 /*
1283 * Check for underflow case where both EDTL and immediate data payload
1284 * exceeds what is presented by CDB's TRANSFER LENGTH, and what has
1285 * already been set in target_cmd_size_check() as se_cmd->data_length.
1286 *
1287 * For this special case, fail the command and dump the immediate data
1288 * payload.
1289 */
1290 if (cmd->first_burst_len > cmd->se_cmd.data_length) {
1291 cmd->sense_reason = TCM_INVALID_CDB_FIELD;
1292 goto after_immediate_data;
1293 }
1282 1294
1283 immed_ret = iscsit_handle_immediate_data(cmd, hdr, 1295 immed_ret = iscsit_handle_immediate_data(cmd, hdr,
1284 cmd->first_burst_len); 1296 cmd->first_burst_len);
@@ -4423,8 +4435,11 @@ static void iscsit_logout_post_handler_closesession(
4423 * always sleep waiting for RX/TX thread shutdown to complete 4435 * always sleep waiting for RX/TX thread shutdown to complete
4424 * within iscsit_close_connection(). 4436 * within iscsit_close_connection().
4425 */ 4437 */
4426 if (!conn->conn_transport->rdma_shutdown) 4438 if (!conn->conn_transport->rdma_shutdown) {
4427 sleep = cmpxchg(&conn->tx_thread_active, true, false); 4439 sleep = cmpxchg(&conn->tx_thread_active, true, false);
4440 if (!sleep)
4441 return;
4442 }
4428 4443
4429 atomic_set(&conn->conn_logout_remove, 0); 4444 atomic_set(&conn->conn_logout_remove, 0);
4430 complete(&conn->conn_logout_comp); 4445 complete(&conn->conn_logout_comp);
@@ -4440,8 +4455,11 @@ static void iscsit_logout_post_handler_samecid(
4440{ 4455{
4441 int sleep = 1; 4456 int sleep = 1;
4442 4457
4443 if (!conn->conn_transport->rdma_shutdown) 4458 if (!conn->conn_transport->rdma_shutdown) {
4444 sleep = cmpxchg(&conn->tx_thread_active, true, false); 4459 sleep = cmpxchg(&conn->tx_thread_active, true, false);
4460 if (!sleep)
4461 return;
4462 }
4445 4463
4446 atomic_set(&conn->conn_logout_remove, 0); 4464 atomic_set(&conn->conn_logout_remove, 0);
4447 complete(&conn->conn_logout_comp); 4465 complete(&conn->conn_logout_comp);
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index 9ab7090f7c83..0912de7c0cf8 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -136,7 +136,7 @@ int init_se_kmem_caches(void);
136void release_se_kmem_caches(void); 136void release_se_kmem_caches(void);
137u32 scsi_get_new_index(scsi_index_t); 137u32 scsi_get_new_index(scsi_index_t);
138void transport_subsystem_check_init(void); 138void transport_subsystem_check_init(void);
139void transport_cmd_finish_abort(struct se_cmd *, int); 139int transport_cmd_finish_abort(struct se_cmd *, int);
140unsigned char *transport_dump_cmd_direction(struct se_cmd *); 140unsigned char *transport_dump_cmd_direction(struct se_cmd *);
141void transport_dump_dev_state(struct se_device *, char *, int *); 141void transport_dump_dev_state(struct se_device *, char *, int *);
142void transport_dump_dev_info(struct se_device *, struct se_lun *, 142void transport_dump_dev_info(struct se_device *, struct se_lun *,
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index dce1e1b47316..13f47bf4d16b 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -75,7 +75,7 @@ void core_tmr_release_req(struct se_tmr_req *tmr)
75 kfree(tmr); 75 kfree(tmr);
76} 76}
77 77
78static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas) 78static int core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas)
79{ 79{
80 unsigned long flags; 80 unsigned long flags;
81 bool remove = true, send_tas; 81 bool remove = true, send_tas;
@@ -91,7 +91,7 @@ static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas)
91 transport_send_task_abort(cmd); 91 transport_send_task_abort(cmd);
92 } 92 }
93 93
94 transport_cmd_finish_abort(cmd, remove); 94 return transport_cmd_finish_abort(cmd, remove);
95} 95}
96 96
97static int target_check_cdb_and_preempt(struct list_head *list, 97static int target_check_cdb_and_preempt(struct list_head *list,
@@ -184,8 +184,8 @@ void core_tmr_abort_task(
184 cancel_work_sync(&se_cmd->work); 184 cancel_work_sync(&se_cmd->work);
185 transport_wait_for_tasks(se_cmd); 185 transport_wait_for_tasks(se_cmd);
186 186
187 transport_cmd_finish_abort(se_cmd, true); 187 if (!transport_cmd_finish_abort(se_cmd, true))
188 target_put_sess_cmd(se_cmd); 188 target_put_sess_cmd(se_cmd);
189 189
190 printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" 190 printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for"
191 " ref_tag: %llu\n", ref_tag); 191 " ref_tag: %llu\n", ref_tag);
@@ -281,8 +281,8 @@ static void core_tmr_drain_tmr_list(
281 cancel_work_sync(&cmd->work); 281 cancel_work_sync(&cmd->work);
282 transport_wait_for_tasks(cmd); 282 transport_wait_for_tasks(cmd);
283 283
284 transport_cmd_finish_abort(cmd, 1); 284 if (!transport_cmd_finish_abort(cmd, 1))
285 target_put_sess_cmd(cmd); 285 target_put_sess_cmd(cmd);
286 } 286 }
287} 287}
288 288
@@ -380,8 +380,8 @@ static void core_tmr_drain_state_list(
380 cancel_work_sync(&cmd->work); 380 cancel_work_sync(&cmd->work);
381 transport_wait_for_tasks(cmd); 381 transport_wait_for_tasks(cmd);
382 382
383 core_tmr_handle_tas_abort(cmd, tas); 383 if (!core_tmr_handle_tas_abort(cmd, tas))
384 target_put_sess_cmd(cmd); 384 target_put_sess_cmd(cmd);
385 } 385 }
386} 386}
387 387
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 6025935036c9..f1b3a46bdcaf 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -651,9 +651,10 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
651 percpu_ref_put(&lun->lun_ref); 651 percpu_ref_put(&lun->lun_ref);
652} 652}
653 653
654void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) 654int transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
655{ 655{
656 bool ack_kref = (cmd->se_cmd_flags & SCF_ACK_KREF); 656 bool ack_kref = (cmd->se_cmd_flags & SCF_ACK_KREF);
657 int ret = 0;
657 658
658 if (cmd->se_cmd_flags & SCF_SE_LUN_CMD) 659 if (cmd->se_cmd_flags & SCF_SE_LUN_CMD)
659 transport_lun_remove_cmd(cmd); 660 transport_lun_remove_cmd(cmd);
@@ -665,9 +666,11 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
665 cmd->se_tfo->aborted_task(cmd); 666 cmd->se_tfo->aborted_task(cmd);
666 667
667 if (transport_cmd_check_stop_to_fabric(cmd)) 668 if (transport_cmd_check_stop_to_fabric(cmd))
668 return; 669 return 1;
669 if (remove && ack_kref) 670 if (remove && ack_kref)
670 transport_put_cmd(cmd); 671 ret = transport_put_cmd(cmd);
672
673 return ret;
671} 674}
672 675
673static void target_complete_failure_work(struct work_struct *work) 676static void target_complete_failure_work(struct work_struct *work)