summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2014-01-14 12:01:36 +0000
committermav <mav@FreeBSD.org>2014-01-14 12:01:36 +0000
commit204096a62c437bf225d1c682cef7cc4acdbf565b (patch)
treead87a260284e40088353372385994534ac0abab7 /sys/cam
parenta7224392fd4991684fae0ef226fb2367cb016c43 (diff)
downloadFreeBSD-src-204096a62c437bf225d1c682cef7cc4acdbf565b.zip
FreeBSD-src-204096a62c437bf225d1c682cef7cc4acdbf565b.tar.gz
MFC r260541, r260547:
Take additional reference on SCSI probe periph to cover its freeze count. Otherwise periph may be invalidated and freed before single-stepping freeze is dropped, causing use after free panic.
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/cam_periph.c11
-rw-r--r--sys/cam/cam_periph.h1
-rw-r--r--sys/cam/cam_xpt.c4
-rw-r--r--sys/cam/scsi/scsi_xpt.c42
4 files changed, 31 insertions, 27 deletions
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index 1c636cb..ef67c79 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -376,6 +376,17 @@ cam_periph_acquire(struct cam_periph *periph)
}
void
+cam_periph_doacquire(struct cam_periph *periph)
+{
+
+ xpt_lock_buses();
+ KASSERT(periph->refcount >= 1,
+ ("cam_periph_doacquire() with refcount == %d", periph->refcount));
+ periph->refcount++;
+ xpt_unlock_buses();
+}
+
+void
cam_periph_release_locked_buses(struct cam_periph *periph)
{
diff --git a/sys/cam/cam_periph.h b/sys/cam/cam_periph.h
index b9a04d9..ebcf1a4 100644
--- a/sys/cam/cam_periph.h
+++ b/sys/cam/cam_periph.h
@@ -152,6 +152,7 @@ cam_status cam_periph_alloc(periph_ctor_t *periph_ctor,
struct cam_periph *cam_periph_find(struct cam_path *path, char *name);
int cam_periph_list(struct cam_path *, struct sbuf *);
cam_status cam_periph_acquire(struct cam_periph *periph);
+void cam_periph_doacquire(struct cam_periph *periph);
void cam_periph_release(struct cam_periph *periph);
void cam_periph_release_locked(struct cam_periph *periph);
void cam_periph_release_locked_buses(struct cam_periph *periph);
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 86e2f5e..63bac64 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -3154,9 +3154,7 @@ restart:
}
if (periph->flags & CAM_PERIPH_RUN_TASK)
break;
- xpt_lock_buses();
- periph->refcount++; /* Unconditionally acquire */
- xpt_unlock_buses();
+ cam_periph_doacquire(periph);
periph->flags |= CAM_PERIPH_RUN_TASK;
taskqueue_enqueue(xsoftc.xpt_taskq,
&periph->periph_run_task);
diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c
index 69752e1..6d93b6a 100644
--- a/sys/cam/scsi/scsi_xpt.c
+++ b/sys/cam/scsi/scsi_xpt.c
@@ -890,12 +890,14 @@ again:
/*timeout*/60 * 1000);
break;
}
+done:
/*
* We'll have to do without, let our probedone
* routine finish up for us.
*/
start_ccb->csio.data_ptr = NULL;
cam_freeze_devq(periph->path);
+ cam_periph_doacquire(periph);
probedone(periph, start_ccb);
return;
}
@@ -921,14 +923,7 @@ again:
/*timeout*/60 * 1000);
break;
}
- /*
- * We'll have to do without, let our probedone
- * routine finish up for us.
- */
- start_ccb->csio.data_ptr = NULL;
- cam_freeze_devq(periph->path);
- probedone(periph, start_ccb);
- return;
+ goto done;
}
case PROBE_SERIAL_NUM:
{
@@ -961,19 +956,13 @@ again:
/*timeout*/60 * 1000);
break;
}
- /*
- * We'll have to do without, let our probedone
- * routine finish up for us.
- */
- start_ccb->csio.data_ptr = NULL;
- cam_freeze_devq(periph->path);
- probedone(periph, start_ccb);
- return;
+ goto done;
}
default:
panic("probestart: invalid action state 0x%x\n", softc->action);
}
start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
+ cam_periph_doacquire(periph);
xpt_action(start_ccb);
}
@@ -1121,7 +1110,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
if (cam_periph_error(done_ccb, 0,
SF_NO_PRINT, NULL) == ERESTART) {
-out:
+outr:
/* Drop freeze taken due to CAM_DEV_QFREEZE */
cam_release_devq(path, 0, 0, 0, FALSE);
return;
@@ -1135,7 +1124,11 @@ out:
PROBE_SET_ACTION(softc, PROBE_INQUIRY);
xpt_release_ccb(done_ccb);
xpt_schedule(periph, priority);
- goto out;
+out:
+ /* Drop freeze taken due to CAM_DEV_QFREEZE and release. */
+ cam_release_devq(path, 0, 0, 0, FALSE);
+ cam_periph_release_locked(periph);
+ return;
}
case PROBE_INQUIRY:
case PROBE_FULL_INQUIRY:
@@ -1222,7 +1215,7 @@ out:
? SF_RETRY_UA|SF_QUIET_IR
: SF_RETRY_UA,
&softc->saved_ccb) == ERESTART) {
- goto out;
+ goto outr;
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
/* Don't wedge the queue */
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
@@ -1263,7 +1256,7 @@ out:
done_ccb->ccb_h.target_lun > 0 ?
SF_RETRY_UA|SF_QUIET_IR : SF_RETRY_UA,
&softc->saved_ccb) == ERESTART) {
- goto out;
+ goto outr;
}
if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
xpt_release_devq(done_ccb->ccb_h.path, 1,
@@ -1373,7 +1366,7 @@ out:
} else if (cam_periph_error(done_ccb, 0,
SF_RETRY_UA|SF_NO_PRINT,
&softc->saved_ccb) == ERESTART) {
- goto out;
+ goto outr;
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
/* Don't wedge the queue */
xpt_release_devq(done_ccb->ccb_h.path,
@@ -1416,7 +1409,7 @@ out:
} else if (cam_periph_error(done_ccb, 0,
SF_RETRY_UA|SF_NO_PRINT,
&softc->saved_ccb) == ERESTART) {
- goto out;
+ goto outr;
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
/* Don't wedge the queue */
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
@@ -1461,7 +1454,7 @@ out:
} else if (cam_periph_error(done_ccb, 0,
SF_RETRY_UA,
&softc->saved_ccb) == ERESTART) {
- goto out;
+ goto outr;
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
/* Don't wedge the queue */
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
@@ -1516,7 +1509,7 @@ probe_device_check:
} else if (cam_periph_error(done_ccb, 0,
SF_RETRY_UA|SF_NO_PRINT,
&softc->saved_ccb) == ERESTART) {
- goto out;
+ goto outr;
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
/* Don't wedge the queue */
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
@@ -1699,6 +1692,7 @@ probe_device_check:
CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n"));
/* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
cam_release_devq(path, 0, 0, 0, FALSE);
+ cam_periph_release_locked(periph);
cam_periph_invalidate(periph);
cam_periph_release_locked(periph);
} else {
OpenPOWER on IntegriCloud