Page MenuHomeFreeBSD

D14040.id38453.diff
No OneTemporary

D14040.id38453.diff

Index: sys/cam/cam_xpt.c
===================================================================
--- sys/cam/cam_xpt.c
+++ sys/cam/cam_xpt.c
@@ -5374,8 +5374,8 @@
static void
xpt_done_process(struct ccb_hdr *ccb_h)
{
- struct cam_sim *sim;
- struct cam_devq *devq;
+ struct cam_sim *sim = NULL;
+ struct cam_devq *devq = NULL;
struct mtx *mtx = NULL;
#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING)
@@ -5418,9 +5418,15 @@
mtx_unlock(&xsoftc.xpt_highpower_lock);
}
- sim = ccb_h->path->bus->sim;
+ /*
+ * Insulate against a race where the periph is destroyed
+ * but CCBs are still not all processed.
+ */
+ if (ccb_h->path->bus)
+ sim = ccb_h->path->bus->sim;
if (ccb_h->status & CAM_RELEASE_SIMQ) {
+ KASSERT(sim, ("sim missing for CAM_RELEASE_SIMQ request"));
xpt_release_simq(sim, /*run_queue*/FALSE);
ccb_h->status &= ~CAM_RELEASE_SIMQ;
}
@@ -5431,10 +5437,13 @@
ccb_h->status &= ~CAM_DEV_QFRZN;
}
- devq = sim->devq;
if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) {
struct cam_ed *dev = ccb_h->path->device;
+ if (sim)
+ devq = sim->devq;
+ KASSERT(devq, ("sim missing for XPT_FC_USER_CCB request"));
+
mtx_lock(&devq->send_mtx);
devq->send_active--;
devq->send_openings++;
Index: sys/cam/scsi/scsi_da.c
===================================================================
--- sys/cam/scsi/scsi_da.c
+++ sys/cam/scsi/scsi_da.c
@@ -51,6 +51,7 @@
#include <sys/sbuf.h>
#include <geom/geom.h>
#include <geom/geom_disk.h>
+#include <machine/atomic.h>
#endif /* _KERNEL */
#ifndef _KERNEL
@@ -291,6 +292,31 @@
#define DA_WORK_TUR (1 << 16)
+typedef enum {
+ DA_REF_OPEN = 1,
+ DA_REF_OPEN_HOLD,
+ DA_REF_CLOSE_HOLD,
+ DA_REF_PROBE_HOLD,
+ DA_REF_TUR,
+ DA_REF_GEOM,
+ DA_REF_SYSCTL,
+ DA_REF_REPROBE,
+ DA_REF_MAX /* KEEP LAST */
+} da_ref_token;
+
+const char *da_ref_text[] = {
+ "bogus",
+ "open",
+ "open hold",
+ "close hold",
+ "reprobe hold",
+ "Test Unit Ready",
+ "Geom",
+ "sysctl",
+ "reprobe",
+ "max -- also bogus"
+};
+
struct da_softc {
struct cam_iosched_softc *cam_iosched;
struct bio_queue_head delete_run_queue;
@@ -335,6 +361,7 @@
uint8_t unmap_buf[UNMAP_BUF_SIZE];
struct scsi_read_capacity_data_long rcaplong;
struct callout mediapoll_c;
+ int ref_flags[DA_REF_MAX];
#ifdef CAM_IO_STATS
struct sysctl_ctx_list sysctl_stats_ctx;
struct sysctl_oid *sysctl_stats_tree;
@@ -1469,6 +1496,105 @@
static MALLOC_DEFINE(M_SCSIDA, "scsi_da", "scsi_da buffers");
+#define CAM_PERIPH_PRINT(p, fmt...) xpt_print((p)->path, ##fmt)
+//#define CAM_PERIPH_PRINT(p, fmt...)
+
+static inline void
+token_sanity(da_ref_token token)
+{
+ if ((unsigned)token >= DA_REF_MAX)
+ panic("Bad token value passed in %d\n", token);
+}
+
+static inline int
+da_periph_hold(struct cam_periph *periph, int priority, da_ref_token token)
+{
+ int err = cam_periph_hold(periph, priority);
+
+ token_sanity(token);
+ CAM_PERIPH_PRINT(periph, "Holding device %s (%d): %d\n",
+ da_ref_text[token], token, err);
+ if (err == 0) {
+ int cnt;
+ struct da_softc *softc = periph->softc;
+
+ cnt = atomic_fetchadd_int(&softc->ref_flags[token], 1);
+ if (cnt != 0)
+ panic("Re-holding for reason %d, cnt = %d", token, cnt);
+ }
+ return (err);
+}
+
+static inline void
+da_periph_unhold(struct cam_periph *periph, da_ref_token token)
+{
+ int cnt;
+ struct da_softc *softc = periph->softc;
+
+ token_sanity(token);
+ cam_periph_unhold(periph);
+ CAM_PERIPH_PRINT(periph, "Unholding device %s (%d)\n",
+ da_ref_text[token], token);
+ cnt = atomic_fetchadd_int(&softc->ref_flags[token], -1);
+ if (cnt != 1)
+ panic("Unholding %d with cnt = %d", token, cnt);
+}
+
+static inline int
+da_periph_acquire(struct cam_periph *periph, da_ref_token token)
+{
+ int err = cam_periph_acquire(periph);
+
+ token_sanity(token);
+ CAM_PERIPH_PRINT(periph, "acquiring device %s (%d): %d\n",
+ da_ref_text[token], token, err);
+ if (err == CAM_REQ_CMP) {
+ int cnt;
+ struct da_softc *softc = periph->softc;
+
+ cnt = atomic_fetchadd_int(&softc->ref_flags[token], 1);
+ if (cnt != 0)
+ panic("Re-refing for reason %d, cnt = %d", token, cnt);
+ }
+ return (err);
+}
+
+static inline void
+da_periph_release(struct cam_periph *periph, da_ref_token token)
+{
+ int cnt;
+ struct da_softc *softc = periph->softc;
+
+ token_sanity(token);
+ cam_periph_release(periph);
+ CAM_PERIPH_PRINT(periph, "releasing device %s (%d)\n",
+ da_ref_text[token], token);
+ cnt = atomic_fetchadd_int(&softc->ref_flags[token], -1);
+ if (cnt != 1)
+ panic("Unholding %d with cnt = %d", token, cnt);
+}
+
+static inline void
+da_periph_release_locked(struct cam_periph *periph, da_ref_token token)
+{
+ int cnt;
+ struct da_softc *softc = periph->softc;
+
+ token_sanity(token);
+ cam_periph_release_locked(periph);
+ CAM_PERIPH_PRINT(periph, "releasing device (locked) %s (%d)\n",
+ da_ref_text[token], token);
+ cnt = atomic_fetchadd_int(&softc->ref_flags[token], -1);
+ if (cnt != 1)
+ panic("Unholding %d with cnt = %d", token, cnt);
+}
+
+#define cam_periph_hold POISON
+#define cam_periph_unhold POISON
+#define cam_periph_acquire POISON
+#define cam_periph_release POISON
+#define cam_periph_release_locked POISON
+
static int
daopen(struct disk *dp)
{
@@ -1477,14 +1603,14 @@
int error;
periph = (struct cam_periph *)dp->d_drv1;
- if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+ if (da_periph_acquire(periph, DA_REF_OPEN) != CAM_REQ_CMP) {
return (ENXIO);
}
cam_periph_lock(periph);
- if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) {
+ if ((error = da_periph_hold(periph, PRIBIO|PCATCH, DA_REF_OPEN_HOLD)) != 0) {
cam_periph_unlock(periph);
- cam_periph_release(periph);
+ da_periph_release(periph, DA_REF_OPEN);
return (error);
}
@@ -1512,11 +1638,11 @@
softc->flags |= DA_FLAG_OPEN;
}
- cam_periph_unhold(periph);
+ da_periph_unhold(periph, DA_REF_OPEN_HOLD);
cam_periph_unlock(periph);
if (error != 0)
- cam_periph_release(periph);
+ da_periph_release(periph, DA_REF_OPEN);
return (error);
}
@@ -1534,7 +1660,7 @@
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH,
("daclose\n"));
- if (cam_periph_hold(periph, PRIBIO) == 0) {
+ if (da_periph_hold(periph, PRIBIO, DA_REF_CLOSE_HOLD) == 0) {
/* Flush disk cache. */
if ((softc->flags & DA_FLAG_DIRTY) != 0 &&
@@ -1557,7 +1683,7 @@
(softc->quirks & DA_Q_NO_PREVENT) == 0)
daprevent(periph, PR_ALLOW);
- cam_periph_unhold(periph);
+ da_periph_unhold(periph, DA_REF_CLOSE_HOLD);
}
/*
@@ -1572,7 +1698,7 @@
while (softc->refcount != 0)
cam_periph_sleep(periph, &softc->refcount, PRIBIO, "daclose", 1);
cam_periph_unlock(periph);
- cam_periph_release(periph);
+ da_periph_release(periph, DA_REF_OPEN);
return (0);
}
@@ -1750,7 +1876,7 @@
struct cam_periph *periph;
periph = (struct cam_periph *)dp->d_drv1;
- cam_periph_release(periph);
+ da_periph_release(periph, DA_REF_GEOM);
}
static void
@@ -1910,7 +2036,7 @@
case AC_SCSI_AEN:
softc = (struct da_softc *)periph->softc;
if (!cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR)) {
- if (cam_periph_acquire(periph) == CAM_REQ_CMP) {
+ if (da_periph_acquire(periph, DA_REF_TUR) == CAM_REQ_CMP) {
cam_iosched_set_work_flags(softc->cam_iosched, DA_WORK_TUR);
daschedule(periph);
}
@@ -1955,7 +2081,7 @@
* periph was held for us when this task was enqueued
*/
if (periph->flags & CAM_PERIPH_INVALID) {
- cam_periph_release(periph);
+ da_periph_release(periph, DA_REF_SYSCTL);
return;
}
@@ -1970,7 +2096,7 @@
CTLFLAG_RD, 0, tmpstr, "device_index");
if (softc->sysctl_tree == NULL) {
printf("dasysctlinit: unable to allocate sysctl tree\n");
- cam_periph_release(periph);
+ da_periph_release(periph, DA_REF_SYSCTL);
return;
}
@@ -2052,7 +2178,7 @@
xpt_action((union ccb *)&cts);
cam_periph_unlock(periph);
if (cts.ccb_h.status != CAM_REQ_CMP) {
- cam_periph_release(periph);
+ da_periph_release(periph, DA_REF_SYSCTL);
return;
}
if (cts.protocol == PROTO_SCSI && cts.transport == XPORT_FC) {
@@ -2103,7 +2229,7 @@
cam_iosched_sysctl_init(softc->cam_iosched, &softc->sysctl_ctx,
softc->sysctl_tree);
- cam_periph_release(periph);
+ da_periph_release(periph, DA_REF_SYSCTL);
}
static int
@@ -2269,9 +2395,9 @@
wakeup(&softc->disk->d_mediasize);
if ((softc->flags & DA_FLAG_ANNOUNCED) == 0) {
softc->flags |= DA_FLAG_ANNOUNCED;
- cam_periph_unhold(periph);
+ da_periph_unhold(periph, DA_REF_PROBE_HOLD);
} else
- cam_periph_release_locked(periph);
+ da_periph_release_locked(periph, DA_REF_REPROBE);
}
static void
@@ -2484,8 +2610,10 @@
* Take an exclusive refcount on the periph while dastart is called
* to finish the probe. The reference will be dropped in dadone at
* the end of probe.
+ *
+ * XXX if cam_periph_hold returns an error, we don't hold a refcount.
*/
- (void)cam_periph_hold(periph, PRIBIO);
+ (void)da_periph_hold(periph, PRIBIO, DA_REF_PROBE_HOLD);
/*
* Schedule a periodic event to occasionally send an
@@ -2579,7 +2707,7 @@
* We'll release this reference once GEOM calls us back (via
* dadiskgonecb()) telling us that our provider has been freed.
*/
- if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+ if (da_periph_acquire(periph, DA_REF_GEOM) != CAM_REQ_CMP) {
xpt_print(periph->path, "%s: lost periph during "
"registration!\n", __func__);
cam_periph_lock(periph);
@@ -2965,7 +3093,7 @@
if (cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR)) {
cam_iosched_clr_work_flags(softc->cam_iosched, DA_WORK_TUR);
- cam_periph_release_locked(periph);
+ da_periph_release_locked(periph, DA_REF_TUR);
}
if ((bp->bio_flags & BIO_ORDERED) != 0 ||
@@ -4547,7 +4675,7 @@
* we have successfully attached.
*/
/* increase the refcount */
- if (cam_periph_acquire(periph) == CAM_REQ_CMP) {
+ if (da_periph_acquire(periph, DA_REF_SYSCTL) == CAM_REQ_CMP) {
taskqueue_enqueue(taskqueue_thread,
&softc->sysctl_task);
@@ -5392,7 +5520,7 @@
/*getcount_only*/0);
}
xpt_release_ccb(done_ccb);
- cam_periph_release_locked(periph);
+ da_periph_release_locked(periph, DA_REF_TUR);
return;
}
default:
@@ -5413,7 +5541,7 @@
if (softc->state != DA_STATE_NORMAL)
return;
- status = cam_periph_acquire(periph);
+ status = da_periph_acquire(periph, DA_REF_REPROBE);
KASSERT(status == CAM_REQ_CMP,
("dareprobe: cam_periph_acquire failed"));
@@ -5513,7 +5641,7 @@
if (!cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR) &&
LIST_EMPTY(&softc->pending_ccbs)) {
- if (cam_periph_acquire(periph) == CAM_REQ_CMP) {
+ if (da_periph_acquire(periph, DA_REF_TUR) == CAM_REQ_CMP) {
cam_iosched_set_work_flags(softc->cam_iosched, DA_WORK_TUR);
daschedule(periph);
}

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 18, 6:21 AM (8 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29848974
Default Alt Text
D14040.id38453.diff (10 KB)

Event Timeline