Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 12 Aug 2011 20:09:38 +0000 (UTC)
From:      Matt Jacob <mjacob@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r224806 - head/sys/cam
Message-ID:  <201108122009.p7CK9cgo081051@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mjacob
Date: Fri Aug 12 20:09:38 2011
New Revision: 224806
URL: http://svn.freebsd.org/changeset/base/224806

Log:
  Fixes for sure bus reference miscounting and potential device and
  target reference miscounts.  It also adds a helper function to get
  the current reference counts for components of cam_path for debug
  aid.  One minor style(9) change.
  
  Partially Obtained from: Chuck Tuffli (Emulex)
  Reviewed by:	scsi@ (ken)
  Approved by:	re (kib)
  MFC after:	1 month

Modified:
  head/sys/cam/cam_xpt.c
  head/sys/cam/cam_xpt.h

Modified: head/sys/cam/cam_xpt.c
==============================================================================
--- head/sys/cam/cam_xpt.c	Fri Aug 12 20:02:47 2011	(r224805)
+++ head/sys/cam/cam_xpt.c	Fri Aug 12 20:09:38 2011	(r224806)
@@ -3336,8 +3336,10 @@ xpt_create_path_unlocked(struct cam_path
 		}
 	}
 	status = xpt_compile_path(path, periph, path_id, target_id, lun_id);
-	if (need_unlock)
+	if (need_unlock) {
 		CAM_SIM_UNLOCK(bus->sim);
+		xpt_release_bus(bus);
+	}
 	if (status != CAM_REQ_CMP) {
 		free(path, M_CAMXPT);
 		path = NULL;
@@ -3445,6 +3447,38 @@ xpt_free_path(struct cam_path *path)
 	free(path, M_CAMXPT);
 }
 
+void
+xpt_path_counts(struct cam_path *path, uint32_t *bus_ref,
+    uint32_t *periph_ref, uint32_t *target_ref, uint32_t *device_ref)
+{
+
+	mtx_lock(&xsoftc.xpt_topo_lock);
+	if (bus_ref) {
+		if (path->bus)
+			*bus_ref = path->bus->refcount;
+		else
+			*bus_ref = 0;
+	}
+	mtx_unlock(&xsoftc.xpt_topo_lock);
+	if (periph_ref) {
+		if (path->periph)
+			*periph_ref = path->periph->refcount;
+		else
+			*periph_ref = 0;
+	}
+	if (target_ref) {
+		if (path->target)
+			*target_ref = path->target->refcount;
+		else
+			*target_ref = 0;
+	}
+	if (device_ref) {
+		if (path->device)
+			*device_ref = path->device->refcount;
+		else
+			*device_ref = 0;
+	}
+}
 
 /*
  * Return -1 for failure, 0 for exact match, 1 for match with wildcards
@@ -4264,15 +4298,17 @@ static void
 xpt_release_bus(struct cam_eb *bus)
 {
 
+	mtx_lock(&xsoftc.xpt_topo_lock);
+	KASSERT(bus->refcount >= 1, ("bus->refcount >= 1"));
 	if ((--bus->refcount == 0)
 	 && (TAILQ_FIRST(&bus->et_entries) == NULL)) {
-		mtx_lock(&xsoftc.xpt_topo_lock);
 		TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links);
 		xsoftc.bus_generation++;
 		mtx_unlock(&xsoftc.xpt_topo_lock);
 		cam_sim_release(bus->sim);
 		free(bus, M_CAMXPT);
-	}
+	} else
+		mtx_unlock(&xsoftc.xpt_topo_lock);
 }
 
 static struct cam_et *
@@ -4296,7 +4332,9 @@ xpt_alloc_target(struct cam_eb *bus, tar
 		 * Hold a reference to our parent bus so it
 		 * will not go away before we do.
 		 */
+		mtx_lock(&xsoftc.xpt_topo_lock);
 		bus->refcount++;
+		mtx_unlock(&xsoftc.xpt_topo_lock);
 
 		/* Insertion sort into our bus's target list */
 		cur_target = TAILQ_FIRST(&bus->et_entries);
@@ -4317,15 +4355,17 @@ static void
 xpt_release_target(struct cam_et *target)
 {
 
-	if ((--target->refcount == 0)
-	 && (TAILQ_FIRST(&target->ed_entries) == NULL)) {
-		TAILQ_REMOVE(&target->bus->et_entries, target, links);
-		target->bus->generation++;
-		xpt_release_bus(target->bus);
-		if (target->luns)
-			free(target->luns, M_CAMXPT);
-		free(target, M_CAMXPT);
-	}
+	if (target->refcount == 1) {
+		if (TAILQ_FIRST(&target->ed_entries) == NULL) {
+			TAILQ_REMOVE(&target->bus->et_entries, target, links);
+			target->bus->generation++;
+			xpt_release_bus(target->bus);
+			if (target->luns)
+				free(target->luns, M_CAMXPT);
+			free(target, M_CAMXPT);
+		}
+	} else
+		target->refcount--;
 }
 
 static struct cam_ed *
@@ -4422,7 +4462,7 @@ void
 xpt_release_device(struct cam_ed *device)
 {
 
-	if (--device->refcount == 0) {
+	if (device->refcount == 1) {
 		struct cam_devq *devq;
 
 		if (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX
@@ -4430,7 +4470,7 @@ xpt_release_device(struct cam_ed *device
 			panic("Removing device while still queued for ccbs");
 
 		if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0)
-				callout_stop(&device->callout);
+			callout_stop(&device->callout);
 
 		TAILQ_REMOVE(&device->target->ed_entries, device,links);
 		device->target->generation++;
@@ -4442,7 +4482,8 @@ xpt_release_device(struct cam_ed *device
 		cam_ccbq_fini(&device->ccbq);
 		xpt_release_target(device->target);
 		free(device, M_CAMXPT);
-	}
+	} else
+		device->refcount--;
 }
 
 u_int32_t

Modified: head/sys/cam/cam_xpt.h
==============================================================================
--- head/sys/cam/cam_xpt.h	Fri Aug 12 20:02:47 2011	(r224805)
+++ head/sys/cam/cam_xpt.h	Fri Aug 12 20:09:38 2011	(r224806)
@@ -106,6 +106,9 @@ cam_status		xpt_create_path_unlocked(str
 int			xpt_getattr(char *buf, size_t len, const char *attr,
 				    struct cam_path *path);
 void			xpt_free_path(struct cam_path *path);
+void			xpt_path_counts(struct cam_path *path, uint32_t *bus_ref,
+					uint32_t *periph_ref, uint32_t *target_ref,
+					uint32_t *device_ref);
 int			xpt_path_comp(struct cam_path *path1,
 				      struct cam_path *path2);
 void			xpt_print_path(struct cam_path *path);
@@ -138,4 +141,3 @@ void			xpt_release_path(struct cam_path 
 #endif /* _KERNEL */
 
 #endif /* _CAM_CAM_XPT_H */
-



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