[PATCH 2/2] scsi: target: iscsi: Complete an aborted WRITE when a new R2T would be sent
From: Laurence Oberman
Date: Wed Oct 14 2026 - 10:40:27 EST
iscsit_check_dataout_payload() hands a command to iscsit_get_dataout() to
request the next burst whenever iscsit_check_post_dataout() returns
DATAOUT_SEND_R2T, without checking CMD_T_ABORTED first.
If a TMR aborted the command while the burst that just finished was in
flight, no further DataOut will arrive: the initiator is about to be told
the command was aborted. The CMD_T_ABORTED handling in
__iscsit_check_dataout_hdr() does not cover this, because it only runs
for DataOut PDUs belonging to R2Ts that were already issued, and
outstanding_r2ts has already been decremented to zero for the burst that
completed. The command is left in TRANSPORT_WRITE_PENDING with nothing to
complete it.
Complete it here instead. Guard on outstanding_r2ts so that with
MaxOutstandingR2T > 1 the completion is still left to the last R2T to
drain in __iscsit_check_dataout_hdr().
Unlike patch 1 of this series, this window was never observed in the
field: instrumented kernels on two hosts recorded no completions at this
site across 300 reset cycles, and the reproducer that triggered the other
one never reached it. It is closed by code inspection, for symmetry with
the other paths that can leave an aborted WRITE_PENDING command stranded.
Assisted-by: Claude LLM
Signed-off-by: Laurence Oberman <loberman@xxxxxxxxxx>
---
drivers/target/iscsi/iscsi_target.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index aab9237a6776..87b215b18034 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1669,6 +1669,25 @@ iscsit_check_dataout_payload(struct iscsit_cmd *cmd, struct iscsi_data *hdr,
if ((rc == DATAOUT_NORMAL) || (rc == DATAOUT_WITHIN_COMMAND_RECOVERY))
return 0;
else if (rc == DATAOUT_SEND_R2T) {
+ /*
+ * A new R2T would never be answered for an aborted command.
+ * The CMD_T_ABORTED handling in __iscsit_check_dataout_hdr()
+ * does not cover this: it only runs for DataOut PDUs
+ * belonging to R2Ts that were already issued, and
+ * iscsit_dataout_update_r2t() has already decremented
+ * outstanding_r2ts for the burst that just finished. Guard
+ * on outstanding_r2ts so that with MaxOutstandingR2T > 1 the
+ * completion is still left to the last R2T to drain.
+ */
+ if (cmd->se_cmd.transport_state & CMD_T_ABORTED) {
+ if (cmd->outstanding_r2ts < 1) {
+ iscsit_stop_dataout_timer(cmd);
+ target_complete_cmd(&cmd->se_cmd,
+ SAM_STAT_TASK_ABORTED);
+ }
+ return 0;
+ }
+
iscsit_set_dataout_sequence_values(cmd);
conn->conn_transport->iscsit_get_dataout(conn, cmd, false);
} else if (rc == DATAOUT_SEND_TO_TRANSPORT) {
--
2.52.0