diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-06-25 13:36:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-06-25 13:36:44 -0400 |
commit | d5d5c1825e85a144e67448ad777eff441ddb907f (patch) | |
tree | 56d65b81ace7e253e5709fd90363e90824a407d2 | |
parent | bb9b8fd26b50c9ec822805b9d877bec9d88acff4 (diff) | |
parent | abb85a9b512e8ca7ad04a5a8a6db9664fe644974 (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.c | 22 | ||||
-rw-r--r-- | drivers/target/target_core_internal.h | 2 | ||||
-rw-r--r-- | drivers/target/target_core_tmr.c | 16 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 9 |
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); | |||
136 | void release_se_kmem_caches(void); | 136 | void release_se_kmem_caches(void); |
137 | u32 scsi_get_new_index(scsi_index_t); | 137 | u32 scsi_get_new_index(scsi_index_t); |
138 | void transport_subsystem_check_init(void); | 138 | void transport_subsystem_check_init(void); |
139 | void transport_cmd_finish_abort(struct se_cmd *, int); | 139 | int transport_cmd_finish_abort(struct se_cmd *, int); |
140 | unsigned char *transport_dump_cmd_direction(struct se_cmd *); | 140 | unsigned char *transport_dump_cmd_direction(struct se_cmd *); |
141 | void transport_dump_dev_state(struct se_device *, char *, int *); | 141 | void transport_dump_dev_state(struct se_device *, char *, int *); |
142 | void transport_dump_dev_info(struct se_device *, struct se_lun *, | 142 | void 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 | ||
78 | static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas) | 78 | static 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 | ||
97 | static int target_check_cdb_and_preempt(struct list_head *list, | 97 | static 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 | ||
654 | void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) | 654 | int 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 | ||
673 | static void target_complete_failure_work(struct work_struct *work) | 676 | static void target_complete_failure_work(struct work_struct *work) |