Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 9 Jun 2012 08:51:26 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r236800 - stable/8/sys/cam
Message-ID:  <201206090851.q598pQxg018870@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sat Jun  9 08:51:25 2012
New Revision: 236800
URL: http://svn.freebsd.org/changeset/base/236800

Log:
  MFC r224806i (by mjacob):
  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.

Modified:
  stable/8/sys/cam/cam_xpt.c
  stable/8/sys/cam/cam_xpt.h
Directory Properties:
  stable/8/sys/   (props changed)

Modified: stable/8/sys/cam/cam_xpt.c
==============================================================================
--- stable/8/sys/cam/cam_xpt.c	Sat Jun  9 08:41:30 2012	(r236799)
+++ stable/8/sys/cam/cam_xpt.c	Sat Jun  9 08:51:25 2012	(r236800)
@@ -3396,8 +3396,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;
@@ -3505,6 +3507,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
@@ -4350,15 +4384,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 *
@@ -4381,7 +4417,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);
@@ -4402,15 +4440,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 *
@@ -4507,7 +4547,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
@@ -4515,7 +4555,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++;
@@ -4527,7 +4567,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: stable/8/sys/cam/cam_xpt.h
==============================================================================
--- stable/8/sys/cam/cam_xpt.h	Sat Jun  9 08:41:30 2012	(r236799)
+++ stable/8/sys/cam/cam_xpt.h	Sat Jun  9 08:51:25 2012	(r236800)
@@ -104,6 +104,9 @@ cam_status		xpt_create_path_unlocked(str
 					path_id_t path_id,
 					target_id_t target_id, lun_id_t lun_id);
 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);
@@ -136,4 +139,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?201206090851.q598pQxg018870>