⬢ DragonFlyBSD Kernel Audit
DF-5025 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/raid/ips/ips_disk.h b/sys/dev/raid/ips/ips_disk.h
--- a/sys/dev/raid/ips/ips_disk.h
+++ b/sys/dev/raid/ips/ips_disk.h
@@ -59,4 +59,6 @@
 	cdev_t		ipsd_dev_t;
 	ips_softc_t	*sc;
 	struct devstat	stats;
+	int		active;		/* in-flight bios; sc->queue_lock */
+	int		disabled;	/* detach started;   sc->queue_lock */
 } ipsdisk_softc_t;
diff --git a/sys/dev/raid/ips/ips_disk.c b/sys/dev/raid/ips/ips_disk.c
--- a/sys/dev/raid/ips/ips_disk.c
+++ b/sys/dev/raid/ips/ips_disk.c
@@ -89,7 +89,9 @@
 
 	if (dsc == NULL)
 		return (ENXIO);
+	lockmgr(&dsc->sc->queue_lock, LK_EXCLUSIVE);
 	dsc->state |= IPS_DEV_OPEN;
+	lockmgr(&dsc->sc->queue_lock, LK_RELEASE);
 	DEVICE_PRINTF(2, dsc->dev, "I'm open\n");
 	return 0;
 }
@@ -100,7 +102,11 @@
 	cdev_t dev = ap->a_head.a_dev;
 	ipsdisk_softc_t *dsc = dev->si_drv1;
 
+	if (dsc == NULL)
+		return (ENXIO);
+	lockmgr(&dsc->sc->queue_lock, LK_EXCLUSIVE);
 	dsc->state &= ~IPS_DEV_OPEN;
+	lockmgr(&dsc->sc->queue_lock, LK_RELEASE);
 	DEVICE_PRINTF(2, dsc->dev, "I'm closed for the day\n");
 	return 0;
 }
@@ -113,6 +119,12 @@
 	ipsdisk_softc_t *dsc;
 
 	dsc = bio->bio_driver_info;
+	/*
+	 * Every caller (adapter interrupt handlers, ips_timeout, and the
+	 * strategy path) invokes us with sc->queue_lock held.
+	 */
+	dsc->active--;
+	wakeup(dsc);
 	if (bp->b_flags & B_ERROR) {
 		device_printf(dsc->dev, "iobuf error %d\n", bp->b_error);
 	} else {
@@ -129,13 +141,22 @@
 {
 	cdev_t dev = ap->a_head.a_dev;
 	struct bio *bio = ap->a_bio;
+	struct buf *bp = bio->bio_buf;
 	ipsdisk_softc_t *dsc;
 
 	dsc = dev->si_drv1;
 	DEVICE_PRINTF(8, dsc->dev, "in strategy\n");
+	if (dsc->disabled) {
+		bp->b_flags |= B_ERROR;
+		bp->b_error = ENXIO;
+		bp->b_resid = bp->b_bcount;
+		biodone(bio);
+		return (0);
+	}
 	bio->bio_driver_info = dsc;
 	devstat_start_transaction(&dsc->stats);
 	lockmgr(&dsc->sc->queue_lock, LK_EXCLUSIVE|LK_RETRY);
+	dsc->active++;
 	bioqdisksort(&dsc->sc->bio_queue, bio);
 	ips_start_io_request(dsc->sc);
 	lockmgr(&dsc->sc->queue_lock, LK_RELEASE);
@@ -208,8 +229,15 @@
 
 	DEVICE_PRINTF(2, dev, "in detach\n");
 	dsc = (ipsdisk_softc_t *)device_get_softc(dev);
-	if (dsc->state & IPS_DEV_OPEN)
+	lockmgr(&dsc->sc->queue_lock, LK_EXCLUSIVE);
+	if (dsc->state & IPS_DEV_OPEN) {
+		lockmgr(&dsc->sc->queue_lock, LK_RELEASE);
 		return (EBUSY);
+	}
+	dsc->disabled = 1;
+	while (dsc->active > 0)
+		lksleep(dsc, &dsc->sc->queue_lock, 0, "ipsddetach", hz);
+	lockmgr(&dsc->sc->queue_lock, LK_RELEASE);
 	devstat_remove_entry(&dsc->stats);
 	disk_destroy(&dsc->ipsd_disk);
 	return 0;