On Wed, Jun 02, 2010 at 06:06:32PM +0000, Matt Jacob wrote:
> Author: mjacob
> Date: Wed Jun  2 18:06:32 2010
> New Revision: 208752
> URL: http://svn.freebsd.org/changeset/base/208752
> 
> Log:
>   Protect periph drivers list and rearrange things to minimize the chance of
>   stepping oneself during probing.
>   
>   Don't blindly decrement a periph probe count.
>   


This commit causes a kernel panic on cdrecord -scanbus:

Unread portion of the kernel message buffer:
panic: _mtx_lock_sleep: recursed on non-recursive mutex XPT topology
lock @ /work/head/sys/cam/cam_xpt.c:4814

#11 0xffffffff80319dd9 in _mtx_lock_flags (m=0xffffffff808761d8,
opts=0x0,
    file=0xffffffff8061ae4f "/work/head/sys/cam/cam_xpt.c", line=0x12ce)
at /work/head/sys/kern/kern_mutex.c:203
#12 0xffffffff80179adc in xptpdperiphtraverse (pdrv=0xffffff000377e600,
start_periph=0x0,
    tr_func=0xffffffff8017a670 <xptplistperiphfunc>,
arg=0xffffff006b872000) at /work/head/sys/cam/cam_xpt.c:2151
#13 0xffffffff80179753 in xptpdrvtraverse (start_pdrv=Variable
"start_pdrv" is not available.
) at /work/head/sys/cam/cam_xpt.c:2132
#14 0xffffffff8017fd09 in xpt_action_default
(start_ccb=0xffffff006b872000) at /work/head/sys/cam/cam_xpt.c:1967
#15 0xffffffff8017bc63 in xptioctl (dev=Variable "dev" is not available.
) at /work/head/sys/cam/cam_xpt.c:598
#16 0xffffffff802bc3c6 in devfs_ioctl_f (fp=0xffffff006b4a0a00,
com=0xc4a81502, data=Variable "data" is not available.
)
    at /work/head/sys/fs/devfs/devfs_vnops.c:669
#17 0xffffffff80379632 in kern_ioctl (td=0xffffff006b4b83f0, fd=Variable
"fd" is not available.
) at file.h:254
#18 0xffffffff80379890 in ioctl (td=0xffffff006b4b83f0,
uap=0xffffff80b1312bf0)
    at /work/head/sys/kern/sys_generic.c:678




>   Reviewed by:        scsi@
>   Obtained from:      Alexander Motin, Atillio Rao, Others
>   MFC after:  1 month
> 
> Modified:
>   head/sys/cam/cam_periph.c
>   head/sys/cam/cam_xpt.c
> 
> Modified: head/sys/cam/cam_periph.c
> ==============================================================================
> --- head/sys/cam/cam_periph.c Wed Jun  2 17:27:23 2010        (r208751)
> +++ head/sys/cam/cam_periph.c Wed Jun  2 18:06:32 2010        (r208752)
> @@ -185,17 +185,6 @@ cam_periph_alloc(periph_ctor_t *periph_c
>       
>       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_c
>       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_c
>       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, c
>               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_per
>               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();
> 
> Modified: head/sys/cam/cam_xpt.c
> ==============================================================================
> --- head/sys/cam/cam_xpt.c    Wed Jun  2 17:27:23 2010        (r208751)
> +++ head/sys/cam/cam_xpt.c    Wed Jun  2 18:06:32 2010        (r208752)
> @@ -2138,6 +2138,7 @@ xptpdperiphtraverse(struct periph_driver
>  
>       retval = 1;
>  
> +     xpt_lock_buses();

already acquired in xpt_action_default?



>       for (periph = (start_periph ? start_periph :
>            TAILQ_FIRST(&(*pdrv)->units)); periph != NULL;
>            periph = next_periph) {
> @@ -2145,9 +2146,12 @@ xptpdperiphtraverse(struct periph_driver
>               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;

-- 
Have fun!
chd

Attachment: pgpnnuSPcXed8.pgp
Description: PGP signature

Reply via email to