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.
This commit is contained in:
Alexander Motin 2014-01-11 13:35:36 +00:00
parent 120dc21b86
commit c33e40291b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=260541
4 changed files with 20 additions and 19 deletions

View file

@ -375,6 +375,17 @@ cam_periph_acquire(struct cam_periph *periph)
return (status);
}
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)
{

View file

@ -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);

View file

@ -3156,9 +3156,7 @@ xpt_run_allocq(struct cam_periph *periph, int sleep)
}
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);

View file

@ -888,12 +888,14 @@ probestart(struct cam_periph *periph, union ccb *start_ccb)
/*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 @@ probestart(struct cam_periph *periph, union ccb *start_ccb)
/*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 @@ probestart(struct cam_periph *periph, union ccb *start_ccb)
/*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, union ccb *done_ccb)
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 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
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 {