summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>2010-06-02 18:06:32 +0000
committermjacob <mjacob@FreeBSD.org>2010-06-02 18:06:32 +0000
commitcfb9348b6980d65002d99e13cf49c6a386082d46 (patch)
tree44f2282d71ccbeb50748e8401f10977f571fb2e6 /sys/cam
parent6840cdea0c707d950ac0a2eb39fba080bfbaaebf (diff)
downloadFreeBSD-src-cfb9348b6980d65002d99e13cf49c6a386082d46.zip
FreeBSD-src-cfb9348b6980d65002d99e13cf49c6a386082d46.tar.gz
Protect periph drivers list and rearrange things to minimize the chance of
stepping oneself during probing. Don't blindly decrement a periph probe count. Reviewed by: scsi@ Obtained from: Alexander Motin, Atillio Rao, Others MFC after: 1 month
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/cam_periph.c59
-rw-r--r--sys/cam/cam_xpt.c9
2 files changed, 41 insertions, 27 deletions
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index 4c7502a..36a4f22 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -185,17 +185,6 @@ cam_periph_alloc(periph_ctor_t *periph_ctor,
init_level++;
- xpt_lock_buses();
- for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) {
- if (strcmp((*p_drv)->driver_name, name) == 0)
- break;
- }
- xpt_unlock_buses();
- if (*p_drv == NULL) {
- printf("cam_periph_alloc: invalid periph name '%s'\n", name);
- free(periph, M_CAMPERIPH);
- return (CAM_REQ_INVALID);
- }
sim = xpt_path_sim(path);
path_id = xpt_path_path_id(path);
@@ -208,7 +197,6 @@ cam_periph_alloc(periph_ctor_t *periph_ctor,
periph->periph_oninval = periph_oninvalidate;
periph->type = type;
periph->periph_name = name;
- periph->unit_number = camperiphunit(*p_drv, path_id, target_id, lun_id);
periph->immediate_priority = CAM_PRIORITY_NONE;
periph->refcount = 0;
periph->sim = sim;
@@ -216,26 +204,39 @@ cam_periph_alloc(periph_ctor_t *periph_ctor,
status = xpt_create_path(&path, periph, path_id, target_id, lun_id);
if (status != CAM_REQ_CMP)
goto failure;
-
periph->path = path;
- init_level++;
-
- status = xpt_add_periph(periph);
-
- if (status != CAM_REQ_CMP)
- goto failure;
+ xpt_lock_buses();
+ for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) {
+ if (strcmp((*p_drv)->driver_name, name) == 0)
+ break;
+ }
+ if (*p_drv == NULL) {
+ printf("cam_periph_alloc: invalid periph name '%s'\n", name);
+ xpt_free_path(periph->path);
+ free(periph, M_CAMPERIPH);
+ xpt_unlock_buses();
+ return (CAM_REQ_INVALID);
+ }
+ periph->unit_number = camperiphunit(*p_drv, path_id, target_id, lun_id);
cur_periph = TAILQ_FIRST(&(*p_drv)->units);
while (cur_periph != NULL
&& cur_periph->unit_number < periph->unit_number)
cur_periph = TAILQ_NEXT(cur_periph, unit_links);
-
- if (cur_periph != NULL)
+ if (cur_periph != NULL) {
+ KASSERT(cur_periph->unit_number != periph->unit_number, ("duplicate units on periph list"));
TAILQ_INSERT_BEFORE(cur_periph, periph, unit_links);
- else {
+ } else {
TAILQ_INSERT_TAIL(&(*p_drv)->units, periph, unit_links);
(*p_drv)->generation++;
}
+ xpt_unlock_buses();
+
+ init_level++;
+
+ status = xpt_add_periph(periph);
+ if (status != CAM_REQ_CMP)
+ goto failure;
init_level++;
@@ -250,10 +251,12 @@ failure:
/* Initialized successfully */
break;
case 3:
- TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links);
xpt_remove_periph(periph);
/* FALLTHROUGH */
case 2:
+ xpt_lock_buses();
+ TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links);
+ xpt_unlock_buses();
xpt_free_path(periph->path);
/* FALLTHROUGH */
case 1:
@@ -288,6 +291,7 @@ cam_periph_find(struct cam_path *path, char *name)
TAILQ_FOREACH(periph, &(*p_drv)->units, unit_links) {
if (xpt_path_comp(periph->path, path) == 0) {
xpt_unlock_buses();
+ mtx_assert(periph->sim->mtx, MA_OWNED);
return(periph);
}
}
@@ -322,8 +326,13 @@ cam_periph_release_locked(struct cam_periph *periph)
return;
xpt_lock_buses();
- if ((--periph->refcount == 0)
- && (periph->flags & CAM_PERIPH_INVALID)) {
+ if (periph->refcount != 0) {
+ periph->refcount--;
+ } else {
+ xpt_print(periph->path, "%s: release %p when refcount is zero\n ", __func__, periph);
+ }
+ if (periph->refcount == 0
+ && (periph->flags & CAM_PERIPH_INVALID)) {
camperiphfree(periph);
}
xpt_unlock_buses();
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 2284006..80dee2a 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -2138,6 +2138,7 @@ xptpdperiphtraverse(struct periph_driver **pdrv,
retval = 1;
+ xpt_lock_buses();
for (periph = (start_periph ? start_periph :
TAILQ_FIRST(&(*pdrv)->units)); periph != NULL;
periph = next_periph) {
@@ -2145,9 +2146,12 @@ xptpdperiphtraverse(struct periph_driver **pdrv,
next_periph = TAILQ_NEXT(periph, unit_links);
retval = tr_func(periph, arg);
- if (retval == 0)
+ if (retval == 0) {
+ xpt_unlock_buses();
return(retval);
+ }
}
+ xpt_unlock_buses();
return(retval);
}
@@ -2323,7 +2327,6 @@ xpt_action_default(union ccb *start_ccb)
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action_default\n"));
-
switch (start_ccb->ccb_h.func_code) {
case XPT_SCSI_IO:
{
@@ -2670,7 +2673,9 @@ xpt_action_default(union ccb *start_ccb)
xptedtmatch(cdm);
break;
case CAM_DEV_POS_PDRV:
+ xpt_lock_buses();
xptperiphlistmatch(cdm);
+ xpt_unlock_buses();
break;
default:
cdm->status = CAM_DEV_MATCH_ERROR;
OpenPOWER on IntegriCloud