From f371c9e2601ae19f1dba536e65d16ef8509d371b Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Fri, 29 Mar 2013 07:50:47 +0000 Subject: [PATCH] Implement CAM_PERIPH_FOREACH() macro, safely iterating over the list of driver's periphs, acquiring and releaseing periph references while doing it. Use it to iterate over the lists of ada and da periphs when flushing caches and putting devices to sleep on shutdown and suspend. Previous code could panic in theory if some device disappear in the middle of the process. --- sys/cam/ata/ata_da.c | 6 +++--- sys/cam/cam_periph.h | 39 +++++++++++++++++++++++++++++++++++++++ sys/cam/scsi/scsi_da.c | 2 +- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index c700e7c5d1d4..e929e518506f 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -1835,7 +1835,7 @@ adaflush(void) struct ada_softc *softc; int error; - TAILQ_FOREACH(periph, &adadriver.units, unit_links) { + CAM_PERIPH_FOREACH(periph, &adadriver) { union ccb ccb; /* If we paniced with lock held - not recurse here. */ @@ -1889,7 +1889,7 @@ adaspindown(uint8_t cmd, int flags) struct ada_softc *softc; int error; - TAILQ_FOREACH(periph, &adadriver.units, unit_links) { + CAM_PERIPH_FOREACH(periph, &adadriver) { union ccb ccb; /* If we paniced with lock held - not recurse here. */ @@ -1962,7 +1962,7 @@ adaresume(void *arg) if (ada_spindown_suspend == 0) return; - TAILQ_FOREACH(periph, &adadriver.units, unit_links) { + CAM_PERIPH_FOREACH(periph, &adadriver) { cam_periph_lock(periph); softc = (struct ada_softc *)periph->softc; /* diff --git a/sys/cam/cam_periph.h b/sys/cam/cam_periph.h index b51fb681b2d3..bd378ec8afd1 100644 --- a/sys/cam/cam_periph.h +++ b/sys/cam/cam_periph.h @@ -183,6 +183,8 @@ void cam_periph_freeze_after_event(struct cam_periph *periph, u_int duration_ms); int cam_periph_error(union ccb *ccb, cam_flags camflags, u_int32_t sense_flags, union ccb *save_ccb); +void xpt_lock_buses(void); +void xpt_unlock_buses(void); static __inline void cam_periph_lock(struct cam_periph *periph) @@ -209,5 +211,42 @@ cam_periph_sleep(struct cam_periph *periph, void *chan, int priority, return (msleep(chan, periph->sim->mtx, priority, wmesg, timo)); } +static inline struct cam_periph * +cam_periph_acquire_first(struct periph_driver *driver) +{ + struct cam_periph *periph; + + xpt_lock_buses(); + periph = TAILQ_FIRST(&driver->units); + while (periph != NULL && (periph->flags & CAM_PERIPH_INVALID) != 0) + periph = TAILQ_NEXT(periph, unit_links); + if (periph != NULL) + periph->refcount++; + xpt_unlock_buses(); + return (periph); +} + +static inline struct cam_periph * +cam_periph_acquire_next(struct cam_periph *pperiph) +{ + struct cam_periph *periph = pperiph; + + mtx_assert(pperiph->sim->mtx, MA_NOTOWNED); + xpt_lock_buses(); + do { + periph = TAILQ_NEXT(periph, unit_links); + } while (periph != NULL && (periph->flags & CAM_PERIPH_INVALID) != 0); + if (periph != NULL) + periph->refcount++; + xpt_unlock_buses(); + cam_periph_release(pperiph); + return (periph); +} + +#define CAM_PERIPH_FOREACH(periph, driver) \ + for ((periph) = cam_periph_acquire_first(driver); \ + (periph) != NULL; \ + (periph) = cam_periph_acquire_next(periph)) + #endif /* _KERNEL */ #endif /* _CAM_CAM_PERIPH_H */ diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 9fd7039b8781..aaa2a4c42e25 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -2848,7 +2848,7 @@ dashutdown(void * arg, int howto) struct da_softc *softc; int error; - TAILQ_FOREACH(periph, &dadriver.units, unit_links) { + CAM_PERIPH_FOREACH(periph, &dadriver) { union ccb ccb; cam_periph_lock(periph);