Date: Sat, 11 Jan 2014 13:35:36 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r260541 - in head/sys/cam: . scsi Message-ID: <201401111335.s0BDZaFU070072@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: mav Date: Sat Jan 11 13:35:36 2014 New Revision: 260541 URL: http://svnweb.freebsd.org/changeset/base/260541 Log: 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. Modified: head/sys/cam/cam_periph.c head/sys/cam/cam_periph.h head/sys/cam/cam_xpt.c head/sys/cam/scsi/scsi_xpt.c Modified: head/sys/cam/cam_periph.c ============================================================================== --- head/sys/cam/cam_periph.c Sat Jan 11 09:44:00 2014 (r260540) +++ head/sys/cam/cam_periph.c Sat Jan 11 13:35:36 2014 (r260541) @@ -376,6 +376,17 @@ cam_periph_acquire(struct cam_periph *pe } 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) { Modified: head/sys/cam/cam_periph.h ============================================================================== --- head/sys/cam/cam_periph.h Sat Jan 11 09:44:00 2014 (r260540) +++ head/sys/cam/cam_periph.h Sat Jan 11 13:35:36 2014 (r260541) @@ -152,6 +152,7 @@ cam_status cam_periph_alloc(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); Modified: head/sys/cam/cam_xpt.c ============================================================================== --- head/sys/cam/cam_xpt.c Sat Jan 11 09:44:00 2014 (r260540) +++ head/sys/cam/cam_xpt.c Sat Jan 11 13:35:36 2014 (r260541) @@ -3156,9 +3156,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); Modified: head/sys/cam/scsi/scsi_xpt.c ============================================================================== --- head/sys/cam/scsi/scsi_xpt.c Sat Jan 11 09:44:00 2014 (r260540) +++ head/sys/cam/scsi/scsi_xpt.c Sat Jan 11 13:35:36 2014 (r260541) @@ -888,12 +888,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; } @@ -919,14 +921,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: { @@ -959,19 +954,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); } @@ -1122,6 +1111,7 @@ probedone(struct cam_periph *periph, uni out: /* Drop freeze taken due to CAM_DEV_QFREEZE */ cam_release_devq(path, 0, 0, 0, FALSE); + cam_periph_release_locked(periph); return; } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) @@ -1697,6 +1687,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 {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201401111335.s0BDZaFU070072>