Fix data race in scsi cd driver.

There is a data race between cdsysctlinit and cdcheckmedia.  Both
functions change softc->flags without synchronization.

Submitted by:	Arseny Smalyuk <smalukav@gmail.com>
MFC after:	2 weeks
Differential Revision: https://reviews.freebsd.org/D31726
This commit is contained in:
Alexander Motin 2021-09-13 08:59:51 -04:00
parent 2d78130185
commit e76786909c

View File

@ -371,6 +371,7 @@ cdoninvalidate(struct cam_periph *periph)
{
struct cd_softc *softc;
cam_periph_assert(periph, MA_OWNED);
softc = (struct cd_softc *)periph->softc;
/*
@ -451,7 +452,7 @@ cdasync(void *callback_arg, u_int32_t code,
printf("cdasync: Unable to attach new device "
"due to status 0x%x\n", status);
break;
return;
}
case AC_UNIT_ATTENTION:
{
@ -471,10 +472,10 @@ cdasync(void *callback_arg, u_int32_t code,
if (asc == 0x28 && ascq == 0x00)
disk_media_changed(softc->disk, M_NOWAIT);
}
cam_periph_async(periph, code, path, arg);
break;
}
case AC_SCSI_AEN:
cam_periph_assert(periph, MA_OWNED);
softc = (struct cd_softc *)periph->softc;
if (softc->state == CD_STATE_NORMAL && !softc->tur) {
if (cam_periph_acquire(periph) == 0) {
@ -488,6 +489,7 @@ cdasync(void *callback_arg, u_int32_t code,
{
struct ccb_hdr *ccbh;
cam_periph_assert(periph, MA_OWNED);
softc = (struct cd_softc *)periph->softc;
/*
* Don't fail on the expected unit attention
@ -496,12 +498,13 @@ cdasync(void *callback_arg, u_int32_t code,
softc->flags |= CD_FLAG_RETRY_UA;
LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
ccbh->ccb_state |= CD_CCB_RETRY_UA;
/* FALLTHROUGH */
}
default:
cam_periph_async(periph, code, path, arg);
break;
}
default:
break;
}
cam_periph_async(periph, code, path, arg);
}
static void
@ -520,7 +523,9 @@ cdsysctlinit(void *context, int pending)
snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
sysctl_ctx_init(&softc->sysctl_ctx);
cam_periph_lock(periph);
softc->flags |= CD_FLAG_SCTX_INIT;
cam_periph_unlock(periph);
softc->sysctl_tree = SYSCTL_ADD_NODE_WITH_LABEL(&softc->sysctl_ctx,
SYSCTL_STATIC_CHILDREN(_kern_cam_cd), OID_AUTO,
tmpstr2, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, tmpstr,
@ -899,6 +904,7 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb)
struct bio *bp;
struct ccb_scsiio *csio;
cam_periph_assert(periph, MA_OWNED);
softc = (struct cd_softc *)periph->softc;
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n"));
@ -1143,6 +1149,7 @@ cddone(struct cam_periph *periph, union ccb *done_ccb)
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n"));
cam_periph_assert(periph, MA_OWNED);
softc = (struct cd_softc *)periph->softc;
csio = &done_ccb->csio;
@ -2624,6 +2631,7 @@ cdprevent(struct cam_periph *periph, int action)
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n"));
cam_periph_assert(periph, MA_OWNED);
softc = (struct cd_softc *)periph->softc;
if (((action == PR_ALLOW)
@ -2661,6 +2669,7 @@ cdmediaprobedone(struct cam_periph *periph)
{
struct cd_softc *softc;
cam_periph_assert(periph, MA_OWNED);
softc = (struct cd_softc *)periph->softc;
softc->flags &= ~CD_FLAG_MEDIA_SCAN_ACT;
@ -2682,6 +2691,7 @@ cdcheckmedia(struct cam_periph *periph, int do_wait)
struct cd_softc *softc;
int error;
cam_periph_assert(periph, MA_OWNED);
softc = (struct cd_softc *)periph->softc;
error = 0;
@ -3071,13 +3081,14 @@ cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
periph = xpt_path_periph(ccb->ccb_h.path);
softc = (struct cd_softc *)periph->softc;
error = 0;
cam_periph_assert(periph, MA_OWNED);
/*
* We use a status of CAM_REQ_INVALID as shorthand -- if a 6 byte
* CDB comes back with this particular error, try transforming it
* into the 10 byte version.
*/
error = 0;
if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) {
error = cd6byteworkaround(ccb);
} else if (scsi_extract_sense_ccb(ccb,