DF-2284 / fix.diff
--- a/sys/bus/cam/scsi/scsi_sg.c +++ b/sys/bus/cam/scsi/scsi_sg.c @@ -180,6 +180,27 @@ softc->flags |= SG_FLAG_INVALID; /* + * DF-2284: nothing else ever frees the queued rdwr entries (only a + * matching sgread() dequeues them), so write-only usage leaks every + * sg_rdwr + ccb + buffer. Drop completed entries here; sgcleanup() + * drains whatever remains before the softc is freed. + */ + { + struct sg_rdwr *rdwr, *rdwr2; + + TAILQ_FOREACH_MUTABLE(rdwr, &softc->rdwr_done, rdwr_link, + rdwr2) { + if (rdwr->state == SG_RDWR_DONE) { + TAILQ_REMOVE(&softc->rdwr_done, rdwr, + rdwr_link); + xpt_free_ccb(&rdwr->ccb->ccb_h); + kfree(rdwr->buf, M_DEVBUF); + kfree(rdwr, M_DEVBUF); + } + } + } + + /* * XXX Return all queued I/O with ENXIO. * XXX Handle any transactions queued to the card * with XPT_ABORT_CCB. @@ -202,6 +223,21 @@ cam_periph_unlock(periph); destroy_dev(softc->dev); cam_periph_lock(periph); + /* + * DF-2284: final drain -- anything still on rdwr_done is + * unreachable once the softc is freed. + */ + { + struct sg_rdwr *rdwr, *rdwr2; + + TAILQ_FOREACH_MUTABLE(rdwr, &softc->rdwr_done, rdwr_link, + rdwr2) { + TAILQ_REMOVE(&softc->rdwr_done, rdwr, rdwr_link); + xpt_free_ccb(&rdwr->ccb->ccb_h); + kfree(rdwr->buf, M_DEVBUF); + kfree(rdwr, M_DEVBUF); + } + } kfree(softc, M_DEVBUF); } |