diff options
author | mjacob <mjacob@FreeBSD.org> | 2010-06-02 18:06:32 +0000 |
---|---|---|
committer | mjacob <mjacob@FreeBSD.org> | 2010-06-02 18:06:32 +0000 |
commit | cfb9348b6980d65002d99e13cf49c6a386082d46 (patch) | |
tree | 44f2282d71ccbeb50748e8401f10977f571fb2e6 /sys/cam | |
parent | 6840cdea0c707d950ac0a2eb39fba080bfbaaebf (diff) | |
download | FreeBSD-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.c | 59 | ||||
-rw-r--r-- | sys/cam/cam_xpt.c | 9 |
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; |