Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Apr 2013 21:09:27 +0000 (UTC)
From:      "Kenneth D. Merry" <ken@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r249661 - stable/9/sys/cam/ata
Message-ID:  <201304192109.r3JL9RXI019339@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ken
Date: Fri Apr 19 21:09:27 2013
New Revision: 249661
URL: http://svnweb.freebsd.org/changeset/base/249661

Log:
  MFC r249347:
    ------------------------------------------------------------------------
    r249347 | ken | 2013-04-10 16:12:21 -0600 (Wed, 10 Apr 2013) | 22 lines
  
    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

Modified:
  stable/9/sys/cam/ata/ata_da.c
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/cam/ata/ata_da.c
==============================================================================
--- stable/9/sys/cam/ata/ata_da.c	Fri Apr 19 21:08:56 2013	(r249660)
+++ stable/9/sys/cam/ata/ata_da.c	Fri Apr 19 21:09:27 2013	(r249661)
@@ -792,6 +792,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)
 {
@@ -1131,6 +1145,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 */
@@ -1194,6 +1209,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?201304192109.r3JL9RXI019339>