svn commit: r306529 - head/sys/cam
Mark Johnston
markj at FreeBSD.org
Fri Sep 30 21:00:11 UTC 2016
Author: markj
Date: Fri Sep 30 21:00:09 2016
New Revision: 306529
URL: https://svnweb.freebsd.org/changeset/base/306529
Log:
cam_periph_ccbwait could return while ccb in progress
In cam_periph_runccb, cam_periph_ccbwait was using the value of the ccb
pinfo.index and status fields to determine whether the ccb was done,
but these fields are updated without a contending lock and could glitch
into states that would be erroneously interpreted as done. Instead,
have cam_periph_ccbwait look for the explicit result of the function
cam_periph_done.
Submitted by: Ryan Libby <rlibby at gmail.com>
Reviewed by: mav
MFC after: 3 weeks
Sponsored by: Dell EMC Isilon
Differential Revision: https://reviews.freebsd.org/D8020
Modified:
head/sys/cam/cam_periph.c
head/sys/cam/cam_periph.h
Modified: head/sys/cam/cam_periph.c
==============================================================================
--- head/sys/cam/cam_periph.c Fri Sep 30 20:35:12 2016 (r306528)
+++ head/sys/cam/cam_periph.c Fri Sep 30 21:00:09 2016 (r306529)
@@ -975,16 +975,6 @@ cam_periph_unmapmem(union ccb *ccb, stru
PRELE(curproc);
}
-void
-cam_periph_ccbwait(union ccb *ccb)
-{
-
- if ((ccb->ccb_h.pinfo.index != CAM_UNQUEUED_INDEX)
- || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG))
- xpt_path_sleep(ccb->ccb_h.path, &ccb->ccb_h.cbfcnp, PRIBIO,
- "cbwait", 0);
-}
-
int
cam_periph_ioctl(struct cam_periph *periph, u_long cmd, caddr_t addr,
int (*error_routine)(union ccb *ccb,
@@ -1048,13 +1038,38 @@ cam_periph_ioctl(struct cam_periph *peri
}
static void
+cam_periph_done_panic(struct cam_periph *periph, union ccb *done_ccb)
+{
+
+ panic("%s: already done with ccb %p", __func__, done_ccb);
+}
+
+static void
cam_periph_done(struct cam_periph *periph, union ccb *done_ccb)
{
/* Caller will release the CCB */
+ xpt_path_assert(done_ccb->ccb_h.path, MA_OWNED);
+ done_ccb->ccb_h.cbfcnp = cam_periph_done_panic;
wakeup(&done_ccb->ccb_h.cbfcnp);
}
+static void
+cam_periph_ccbwait(union ccb *ccb)
+{
+
+ if ((ccb->ccb_h.func_code & XPT_FC_QUEUED) != 0) {
+ while (ccb->ccb_h.cbfcnp != cam_periph_done_panic)
+ xpt_path_sleep(ccb->ccb_h.path, &ccb->ccb_h.cbfcnp,
+ PRIBIO, "cbwait", 0);
+ }
+ KASSERT(ccb->ccb_h.pinfo.index == CAM_UNQUEUED_INDEX &&
+ (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG,
+ ("%s: proceeding with incomplete ccb: ccb=%p, func_code=%#x, "
+ "status=%#x, index=%d", __func__, ccb, ccb->ccb_h.func_code,
+ ccb->ccb_h.status, ccb->ccb_h.pinfo.index));
+}
+
int
cam_periph_runccb(union ccb *ccb,
int (*error_routine)(union ccb *ccb,
@@ -1069,6 +1084,9 @@ cam_periph_runccb(union ccb *ccb,
starttime = NULL;
xpt_path_assert(ccb->ccb_h.path, MA_OWNED);
+ KASSERT((ccb->ccb_h.flags & CAM_UNLOCKED) == 0,
+ ("%s: ccb=%p, func_code=%#x, flags=%#x", __func__, ccb,
+ ccb->ccb_h.func_code, ccb->ccb_h.flags));
/*
* If the user has supplied a stats structure, and if we understand
@@ -1088,9 +1106,10 @@ cam_periph_runccb(union ccb *ccb,
cam_periph_ccbwait(ccb);
if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
error = 0;
- else if (error_routine != NULL)
+ else if (error_routine != NULL) {
+ ccb->ccb_h.cbfcnp = cam_periph_done;
error = (*error_routine)(ccb, camflags, sense_flags);
- else
+ } else
error = 0;
} while (error == ERESTART);
Modified: head/sys/cam/cam_periph.h
==============================================================================
--- head/sys/cam/cam_periph.h Fri Sep 30 20:35:12 2016 (r306528)
+++ head/sys/cam/cam_periph.h Fri Sep 30 21:00:09 2016 (r306529)
@@ -166,7 +166,6 @@ void cam_periph_unmapmem(union ccb *ccb
struct cam_periph_map_info *mapinfo);
union ccb *cam_periph_getccb(struct cam_periph *periph,
u_int32_t priority);
-void cam_periph_ccbwait(union ccb *ccb);
int cam_periph_runccb(union ccb *ccb,
int (*error_routine)(union ccb *ccb,
cam_flags camflags,
More information about the svn-src-all
mailing list