summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>2011-08-12 20:09:38 +0000
committermjacob <mjacob@FreeBSD.org>2011-08-12 20:09:38 +0000
commit0ba1fe7d116a032383d49c9a252a5f09682c76f0 (patch)
treec0594ec3c48dc3903a1950befb6584a14a900a2c /sys/cam
parentab2936096f3cdae594ff8d8fae7bf0f33d9d3286 (diff)
downloadFreeBSD-src-0ba1fe7d116a032383d49c9a252a5f09682c76f0.zip
FreeBSD-src-0ba1fe7d116a032383d49c9a252a5f09682c76f0.tar.gz
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
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/cam_xpt.c71
-rw-r--r--sys/cam/cam_xpt.h4
2 files changed, 59 insertions, 16 deletions
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 013c415..10b89c7 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -3336,8 +3336,10 @@ xpt_create_path_unlocked(struct cam_path **new_path_ptr,
}
}
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, target_id_t target_id)
* 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
diff --git a/sys/cam/cam_xpt.h b/sys/cam/cam_xpt.h
index f7d9b42..1d0e7f7 100644
--- a/sys/cam/cam_xpt.h
+++ b/sys/cam/cam_xpt.h
@@ -106,6 +106,9 @@ cam_status xpt_create_path_unlocked(struct cam_path **new_path_ptr,
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 *path);
#endif /* _KERNEL */
#endif /* _CAM_CAM_XPT_H */
-
OpenPOWER on IntegriCloud