summaryrefslogtreecommitdiffstats
path: root/sys/cam/cam_xpt.c
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2012-10-13 11:23:16 +0000
committermav <mav@FreeBSD.org>2012-10-13 11:23:16 +0000
commit6d988f09cf43d58ab647f11c85fda8f1ef8137b5 (patch)
tree0a211b5d9da98a345ebf739b41b927e17c01b2fb /sys/cam/cam_xpt.c
parentfd248e3cc6efbfa8fea63db25b19a2696e96fb9e (diff)
downloadFreeBSD-src-6d988f09cf43d58ab647f11c85fda8f1ef8137b5.zip
FreeBSD-src-6d988f09cf43d58ab647f11c85fda8f1ef8137b5.tar.gz
Fix XPT_DEBUG paths operations locking:
- Extend the lock to cover xpt_path_release() for the new path. - While xpt_action() is called while holding right SIM lock for the new bus, the old path release may require different SIM lock. So we have to temporary drop the new lock and get the old one.
Diffstat (limited to 'sys/cam/cam_xpt.c')
-rw-r--r--sys/cam/cam_xpt.c24
1 files changed, 16 insertions, 8 deletions
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 0758979..01d473d 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -533,9 +533,9 @@ xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td
xpt_merge_ccb(&ccb, inccb);
ccb.ccb_h.cbfcnp = xptdone;
xpt_action(&ccb);
- CAM_SIM_UNLOCK(bus->sim);
bcopy(&ccb, inccb, sizeof(union ccb));
xpt_free_path(ccb.ccb_h.path);
+ CAM_SIM_UNLOCK(bus->sim);
break;
}
@@ -2989,34 +2989,42 @@ xpt_action_default(union ccb *start_ccb)
break;
}
case XPT_DEBUG: {
+ struct cam_path *oldpath;
+ struct cam_sim *oldsim;
+
/* Check that all request bits are supported. */
if (start_ccb->cdbg.flags & ~(CAM_DEBUG_COMPILE)) {
start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
break;
}
- cam_dflags = start_ccb->cdbg.flags;
+ cam_dflags = CAM_DEBUG_NONE;
if (cam_dpath != NULL) {
- xpt_free_path(cam_dpath);
+ /* To release the old path we must hold proper lock. */
+ oldpath = cam_dpath;
cam_dpath = NULL;
+ oldsim = xpt_path_sim(oldpath);
+ CAM_SIM_UNLOCK(xpt_path_sim(start_ccb->ccb_h.path));
+ CAM_SIM_LOCK(oldsim);
+ xpt_free_path(oldpath);
+ CAM_SIM_UNLOCK(oldsim);
+ CAM_SIM_LOCK(xpt_path_sim(start_ccb->ccb_h.path));
}
- if (cam_dflags != CAM_DEBUG_NONE) {
+ if (start_ccb->cdbg.flags != CAM_DEBUG_NONE) {
if (xpt_create_path(&cam_dpath, xpt_periph,
start_ccb->ccb_h.path_id,
start_ccb->ccb_h.target_id,
start_ccb->ccb_h.target_lun) !=
CAM_REQ_CMP) {
start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
- cam_dflags = CAM_DEBUG_NONE;
} else {
+ cam_dflags = start_ccb->cdbg.flags;
start_ccb->ccb_h.status = CAM_REQ_CMP;
xpt_print(cam_dpath, "debugging flags now %x\n",
cam_dflags);
}
- } else {
- cam_dpath = NULL;
+ } else
start_ccb->ccb_h.status = CAM_REQ_CMP;
- }
break;
}
case XPT_FREEZE_QUEUE:
OpenPOWER on IntegriCloud