If the SIM freezes the queue at exactly the wrong moment, after

another thread has started to send in a CCB and already checked
the queue wasn't frozen, we would end up with iscsi_action()
being called despite the queue is now frozen.

Add a check to make sure this doesn't happen . Perhaps this should
be fixed at the CAM level instead, but given how the send queue and
SIM are governed by two separate mutexes, it is somewhat hard to do.

Reviewed by:	imp, mav
MFC after:	2 weeks
Sponsored by:	NetApp, Inc.
Sponsored by:	Klara, Inc.
Differential Revision:	https://reviews.freebsd.org/D26750
This commit is contained in:
Edward Tomasz Napierala 2020-10-18 16:30:49 +00:00
parent d22ff249d9
commit 186bcdaac7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=366812

View File

@ -367,8 +367,8 @@ iscsi_session_cleanup(struct iscsi_session *is, bool destroy_sim)
xpt_async(AC_LOST_DEVICE, is->is_path, NULL);
if (is->is_simq_frozen) {
xpt_release_simq(is->is_sim, 1);
is->is_simq_frozen = false;
xpt_release_simq(is->is_sim, 1);
}
xpt_free_path(is->is_path);
@ -1479,8 +1479,8 @@ iscsi_ioctl_daemon_handoff(struct iscsi_softc *sc,
KASSERT(is->is_simq_frozen, ("reconnect without frozen simq"));
ISCSI_SESSION_LOCK(is);
ISCSI_SESSION_DEBUG(is, "releasing");
xpt_release_simq(is->is_sim, 1);
is->is_simq_frozen = false;
xpt_release_simq(is->is_sim, 1);
ISCSI_SESSION_UNLOCK(is);
} else {
@ -2355,6 +2355,17 @@ iscsi_action(struct cam_sim *sim, union ccb *ccb)
return;
}
/*
* Make sure CAM doesn't sneak in a CCB just after freezing the queue.
*/
if (is->is_simq_frozen == true) {
ccb->ccb_h.status &= ~(CAM_SIM_QUEUED | CAM_STATUS_MASK);
ccb->ccb_h.status |= CAM_REQUEUE_REQ;
/* Don't freeze the devq - the SIM queue is already frozen. */
xpt_done(ccb);
return;
}
switch (ccb->ccb_h.func_code) {
case XPT_PATH_INQ:
{