From 02fa548cde3215113a7004f60bf8597a8a7d50cd Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Wed, 13 Nov 2019 01:58:43 +0000 Subject: [PATCH] Fix a race between daopen and damediapoll When we do a daopen, we call dareprobe and wait for the results. The repoll runs the da state machine up through the DA_STATE_RC* and then exits. For removable media, we poll the device every 3 seconds with a TUR to see if it has disappeared. This introduces a race. If the removable device has lots of partitions, and if it's a little slow (like say a USB2 connected USB stick), then we can have a fair amount of time that this reporbe is going on for. If, during that time, damediapoll fires, it calls daschedule which changes the scheduling priority from NONE to NORMAL. When that happens, the careful single stepping in the da state machine is disrupted and we wind up sceduling multiple read capacity calls. The first one succeeds and releases the reference. The second one succeeds and releases the reference (and panics if the right code is compiled into the da driver). To avoid the race, only do the TUR calls while in state normal, otherwise just reschedule damediapoll. This prevents the race from happening. --- sys/cam/scsi/scsi_da.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 2d3ab971628..386eb376a84 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -5949,6 +5949,7 @@ damediapoll(void *arg) if (!cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR) && (softc->flags & DA_FLAG_TUR_PENDING) == 0 && + softc->state == DA_STATE_NORMAL && LIST_EMPTY(&softc->pending_ccbs)) { if (da_periph_acquire(periph, DA_REF_TUR) == 0) { cam_iosched_set_work_flags(softc->cam_iosched, DA_WORK_TUR);