svn commit: r208752 - head/sys/cam

Chagin Dmitry dchagin at freebsd.org
Mon Jun 28 21:23:15 UTC 2010


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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/svn-src-head/attachments/20100628/4faf2ca2/attachment-0001.pgp


More information about the svn-src-head mailing list