summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authorken <ken@FreeBSD.org>2013-04-10 22:12:21 +0000
committerken <ken@FreeBSD.org>2013-04-10 22:12:21 +0000
commit2e36122e63be842feeab6d01ac190f987e2bc2d2 (patch)
tree2ff6aa8c5ed14b76f5ccdca3474520aa40014559 /sys/cam
parent695c50ff24460c5a7a186dd0adf77c976f32ec06 (diff)
downloadFreeBSD-src-2e36122e63be842feeab6d01ac190f987e2bc2d2.zip
FreeBSD-src-2e36122e63be842feeab6d01ac190f987e2bc2d2.tar.gz
Add a callback to the ada(4) driver so that it knows when GEOM has released
references to it. This is the functional equivalent to change r237518, which added this functionality to the cd(4) and da(4) drivers. This fix prevents a panic caused by GEOM calling adaopen() while the device is going away. We now keep the device around until GEOM has finished cleaning up its state. ata_da.c: In adaregister(), add a d_gone callback to the GEOM disk structure registered for the ada driver. Increment the peripheral reference count for GEOM. Add a new callback, adadiskgonecb(), that GEOM calls when it is done with its resources. This callback releases the reference acquired in adaregister(). Submitted by: Po-Li Soong Sponsored by: Spectra Logic MFC After: 5 days
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/ata/ata_da.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c
index c40edba..bf3e683 100644
--- a/sys/cam/ata/ata_da.c
+++ b/sys/cam/ata/ata_da.c
@@ -801,6 +801,20 @@ adainit(void)
}
}
+/*
+ * Callback from GEOM, called when it has finished cleaning up its
+ * resources.
+ */
+static void
+adadiskgonecb(struct disk *dp)
+{
+ struct cam_periph *periph;
+
+ periph = (struct cam_periph *)dp->d_drv1;
+
+ cam_periph_release(periph);
+}
+
static void
adaoninvalidate(struct cam_periph *periph)
{
@@ -1157,6 +1171,7 @@ adaregister(struct cam_periph *periph, void *arg)
softc->disk->d_strategy = adastrategy;
softc->disk->d_getattr = adagetattr;
softc->disk->d_dump = adadump;
+ softc->disk->d_gone = adadiskgonecb;
softc->disk->d_name = "ada";
softc->disk->d_drv1 = periph;
maxio = cpi.maxio; /* Honor max I/O size of SIM */
@@ -1222,6 +1237,17 @@ adaregister(struct cam_periph *periph, void *arg)
}
} else
legacy_id = -1;
+ /*
+ * Acquire a reference to the periph before we register with GEOM.
+ * We'll release this reference once GEOM calls us back (via
+ * adadiskgonecb()) telling us that our provider has been freed.
+ */
+ if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
+ xpt_print(periph->path, "%s: lost periph during "
+ "registration!\n", __func__);
+ cam_periph_lock(periph);
+ return (CAM_REQ_CMP_ERR);
+ }
disk_create(softc->disk, DISK_VERSION);
cam_periph_lock(periph);
cam_periph_unhold(periph);
OpenPOWER on IntegriCloud