git: 7f8f8202edc4 - stable/13 - iscsi: Allocate a dummy PDU for the internal nexus reset task.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Fri, 29 Apr 2022 23:12:38 UTC
The branch stable/13 has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=7f8f8202edc4ae61a65a766de6ec3420a64d3f7d

commit 7f8f8202edc4ae61a65a766de6ec3420a64d3f7d
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2022-01-28 21:07:04 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-04-29 23:05:55 +0000

    iscsi: Allocate a dummy PDU for the internal nexus reset task.
    
    When an iSCSI target session is terminated, an internal nexus reset
    task is posted to abort existing tasks belonging to the session.
    Previously, the ctl_io for this internal nexus reset stored a pointer
    to the session in the slot that normally holds a pointer to the PDU
    from the initiator that triggered the I/O request.  The completion
    handler then assumed that any nexus reset I/O was due to an internal
    request and fetched the session pointer (instead of the PDU pointer)
    from the ctl_io.  However, it is possible to trigger a nexus reset via
    an on-the-wire task management PDU.  If such a PDU were sent to the
    target, then the completion handler would incorrectly treat this
    request as an internal request and treat the pointer to the received
    PDU as a pointer to the session instead.
    
    To fix, allocate a dummy PDU for the internal reset task and use an
    invalid opcode to differentiate internal nexus resets from resets
    requested by the initiator.
    
    PR:             260449
    Reported by:    Robert Morris <rtm@lcs.mit.edu>
    Reviewed by:    mav
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D34055
    
    (cherry picked from commit 2e8d1a55258d39f7315fa4f2164c0fce96e79802)
---
 sys/cam/ctl/ctl_frontend_iscsi.c | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c
index 6e3505c86199..1d7ed8ef87ef 100644
--- a/sys/cam/ctl/ctl_frontend_iscsi.c
+++ b/sys/cam/ctl/ctl_frontend_iscsi.c
@@ -84,6 +84,9 @@ __FBSDID("$FreeBSD$");
 FEATURE(cfiscsi_kernel_proxy, "iSCSI target built with ICL_KERNEL_PROXY");
 #endif
 
+/* Used for internal nexus reset task. */
+#define ISCSI_BHS_OPCODE_INTERNAL	0x3e
+
 static MALLOC_DEFINE(M_CFISCSI, "cfiscsi", "Memory used for CTL iSCSI frontend");
 static uma_zone_t cfiscsi_data_wait_zone;
 
@@ -1131,14 +1134,17 @@ static void
 cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
 {
 	struct cfiscsi_data_wait *cdw;
+	struct icl_pdu *ip;
 	union ctl_io *io;
 	int error, last, wait;
 
 	if (cs->cs_target == NULL)
 		return;		/* No target yet, so nothing to do. */
+	ip = icl_pdu_new(cs->cs_conn, M_WAITOK);
+	ip->ip_bhs->bhs_opcode = ISCSI_BHS_OPCODE_INTERNAL;
 	io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
 	ctl_zero_io(io);
-	PRIV_REQUEST(io) = cs;
+	PRIV_REQUEST(io) = ip;
 	io->io_hdr.io_type = CTL_IO_TASK;
 	io->io_hdr.nexus.initid = cs->cs_ctl_initid;
 	io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
@@ -1152,6 +1158,7 @@ cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
 		CFISCSI_SESSION_WARN(cs, "ctl_run() failed; error %d", error);
 		refcount_release(&cs->cs_outstanding_ctl_pdus);
 		ctl_free_io(io);
+		icl_pdu_free(ip);
 	}
 
 	CFISCSI_SESSION_LOCK(cs);
@@ -3041,19 +3048,6 @@ cfiscsi_done(union ctl_io *io)
 	KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),
 		("invalid CTL status %#x", io->io_hdr.status));
 
-	if (io->io_hdr.io_type == CTL_IO_TASK &&
-	    io->taskio.task_action == CTL_TASK_I_T_NEXUS_RESET) {
-		/*
-		 * Implicit task termination has just completed; nothing to do.
-		 */
-		cs = PRIV_REQUEST(io);
-		cs->cs_tasks_aborted = true;
-		refcount_release(&cs->cs_outstanding_ctl_pdus);
-		wakeup(__DEVOLATILE(void *, &cs->cs_outstanding_ctl_pdus));
-		ctl_free_io(io);
-		return;
-	}
-
 	request = PRIV_REQUEST(io);
 	cs = PDU_SESSION(request);
 
@@ -3064,6 +3058,16 @@ cfiscsi_done(union ctl_io *io)
 	case ISCSI_BHS_OPCODE_TASK_REQUEST:
 		cfiscsi_task_management_done(io);
 		break;
+	case ISCSI_BHS_OPCODE_INTERNAL:
+		/*
+		 * Implicit task termination has just completed; nothing to do.
+		 */
+		cs->cs_tasks_aborted = true;
+		refcount_release(&cs->cs_outstanding_ctl_pdus);
+		wakeup(__DEVOLATILE(void *, &cs->cs_outstanding_ctl_pdus));
+		ctl_free_io(io);
+		icl_pdu_free(request);
+		return;
 	default:
 		panic("cfiscsi_done called with wrong opcode 0x%x",
 		    request->ip_bhs->bhs_opcode);