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 */
-
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to