Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 10 Apr 2013 22:12:22 +0000 (UTC)
From:      "Kenneth D. Merry" <ken@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r249347 - head/sys/cam/ata
Message-ID:  <201304102212.r3AMCMxk097062@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ken
Date: Wed Apr 10 22:12:21 2013
New Revision: 249347
URL: http://svnweb.freebsd.org/changeset/base/249347

Log:
  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

Modified:
  head/sys/cam/ata/ata_da.c

Modified: head/sys/cam/ata/ata_da.c
==============================================================================
--- head/sys/cam/ata/ata_da.c	Wed Apr 10 20:38:15 2013	(r249346)
+++ head/sys/cam/ata/ata_da.c	Wed Apr 10 22:12:21 2013	(r249347)
@@ -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, v
 	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, v
 		}
 	} 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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201304102212.r3AMCMxk097062>