svn commit: r247114 - stable/9/sys/cam/scsi

Alexander Motin mav at FreeBSD.org
Thu Feb 21 18:56:10 UTC 2013


Author: mav
Date: Thu Feb 21 18:56:09 2013
New Revision: 247114
URL: http://svnweb.freebsd.org/changeset/base/247114

Log:
  MFC r237328 (by ken) for recently merged scsi_enc.c:
  
  Fix several reference counting and object lifetime issues between
  the pass(4) and enc(4) drivers and devfs.
  
  The pass(4) driver uses the destroy_dev_sched() routine to
  schedule its device node for destruction in a separate thread
  context.  It does this because the passcleanup() routine can get
  called indirectly from the passclose() routine, and that would
  cause a deadlock if the close routine tried to destroy its own
  device node.
  
  In any case, once a particular passthrough driver number, e.g.
  pass3, is destroyed, CAM considers that unit number (3 in this
  case) available for reuse.
  
  The problem is that devfs may not be done cleaning up the previous
  instance of pass3, and will panic if isn't done cleaning up the
  previous instance.
  
  The solution is to get a callback from devfs when the device node
  is removed, and make sure we hold a reference to the peripheral
  until that happens.
  
  Testing exposed some other cases where we have reference counting
  issues, and those were also fixed in the pass(4) driver.
  
  cam_periph.c:	In camperiphfree(), reorder some of the operations.
  
  		The peripheral destructor needs to be called before
  		the peripheral is removed from the peripheral is
  		removed from the list.  This is because once we
  		remove the peripheral from the list, and drop the
  		topology lock, the peripheral number may be reused.
  		But if the destructor hasn't been called yet, there
  		may still be resources hanging around (like devfs
  		nodes) that haven't been fully cleaned up.
  
  cam_xpt.c:	Add an argument to xpt_remove_periph() to indicate
  		whether the topology lock is already held.
  
  scsi_enc.c:	Acquire an extra reference to the peripheral during
  		registration, and release it once we get a callback
  		from devfs indicating that the device node is gone.
  
  		Call destroy_dev_sched_cb() in enc_oninvalidate()
  		instead of calling destroy_dev() in the cleanup
  		routine.
  
  scsi_pass.c:	Add reference counting to handle peripheral and
  		devfs object lifetime issues.
  
  		Add a reference to the peripheral and the devfs
  		node in the peripheral registration.
  
  		Don't attempt to add a physical path alias if the
  		peripheral has been marked invalid.
  
  		Release the devfs reference once the initial
  		physical path alias taskqueue run has completed.
  
  		Schedule devfs node destruction in the
  		passoninvalidate(), and release our peripheral
  		reference in a new routine, passdevgonecb() once
  		the devfs node is gone.  This allows the peripheral
  		to fully go away, and the peripheral destructor,
  		passcleanup(), will get called.

Modified:
  stable/9/sys/cam/scsi/scsi_enc.c

Modified: stable/9/sys/cam/scsi/scsi_enc.c
==============================================================================
--- stable/9/sys/cam/scsi/scsi_enc.c	Thu Feb 21 18:49:05 2013	(r247113)
+++ stable/9/sys/cam/scsi/scsi_enc.c	Thu Feb 21 18:56:09 2013	(r247114)
@@ -109,6 +109,16 @@ enc_init(void)
 }
 
 static void
+enc_devgonecb(void *arg)
+{
+	struct cam_periph *periph;
+
+	periph = (struct cam_periph *)arg;
+
+	cam_periph_release(periph);
+}
+
+static void
 enc_oninvalidate(struct cam_periph *periph)
 {
 	struct enc_softc *enc;
@@ -136,6 +146,8 @@ enc_oninvalidate(struct cam_periph *peri
 	}
 	callout_drain(&enc->status_updater);
 
+	destroy_dev_sched_cb(enc->enc_dev, enc_devgonecb, periph);
+
 	xpt_print(periph->path, "lost device\n");
 }
 
@@ -147,9 +159,7 @@ enc_dtor(struct cam_periph *periph)
 	enc = periph->softc;
 
 	xpt_print(periph->path, "removing device entry\n");
-	cam_periph_unlock(periph);
-	destroy_dev(enc->enc_dev);
-	cam_periph_lock(periph);
+
 
 	/* If the sub-driver has a cleanup routine, call it */
 	if (enc->enc_vec.softc_cleanup != NULL)
@@ -935,9 +945,19 @@ enc_ctor(struct cam_periph *periph, void
 			goto out;
 		}
 	}
+
+	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);
+	}
+
 	enc->enc_dev = make_dev(&enc_cdevsw, periph->unit_number,
 	    UID_ROOT, GID_OPERATOR, 0600, "%s%d",
 	    periph->periph_name, periph->unit_number);
+
 	cam_periph_lock(periph);
 	enc->enc_dev->si_drv1 = periph;
 


More information about the svn-src-all mailing list