From rea-fbsd@codelabs.ru  Mon Jan 19 11:17:15 2009
Return-Path: <rea-fbsd@codelabs.ru>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 55B801065CA5
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 19 Jan 2009 11:17:15 +0000 (UTC)
	(envelope-from rea-fbsd@codelabs.ru)
Received: from 0.mx.codelabs.ru (0.mx.codelabs.ru [144.206.177.45])
	by mx1.freebsd.org (Postfix) with ESMTP id 7B83B8FC43
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 19 Jan 2009 11:17:14 +0000 (UTC)
	(envelope-from rea-fbsd@codelabs.ru)
Received: from void.codelabs.ru (void.codelabs.ru [144.206.177.25])
	by 0.mx.codelabs.ru with esmtps (TLSv1:CAMELLIA256-SHA:256)
	id 1LOs81-0002HD-Kw for FreeBSD-gnats-submit@freebsd.org; Mon, 19 Jan 2009 14:17:13 +0300
Message-Id: <20090119111713.715D5DA81B@void.codelabs.ru>
Date: Mon, 19 Jan 2009 14:17:13 +0300 (MSK)
From: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
Reply-To: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [patch] pass M_NOWAIT to the malloc() call inside cdreaddvdstructure()
X-Send-Pr-Version: 3.113
X-GNATS-Notify: scottl@freebsd.org

>Number:         130735
>Category:       kern
>Synopsis:       [cam] [patch] pass M_NOWAIT to the malloc() call inside cdreaddvdstructure()
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    jh
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jan 19 11:20:01 UTC 2009
>Closed-Date:    Thu Oct 14 18:25:26 UTC 2010
>Last-Modified:  Thu Oct 14 18:25:26 UTC 2010
>Originator:     Eygene Ryabinkin
>Release:        FreeBSD 7.1-STABLE amd64
>Organization:
Code Labs
>Environment:

System: FreeBSD 7.1-STABLE amd64

>Description:

cdreaddvdstructure() is called from cdioctl() with periph lock held
(sys/dev/cam/scsi/scsi_cd.c):
-----
	cam_periph_lock(periph);
	error = cdreaddvdstructure(periph, dvdstruct);
	cam_periph_unlock(periph);
-----
but malloc() inside cdreaddvdstructure() uses M_WAITOK.

The following diagnostics is thrown with WITNESS enabled:
-----
uma_zalloc_arg: zone "16" with the following non-sleepable locks held:
exclusive sleep mutex ATAPICAM lock r = 0 (0xffffff000475a2a8) locked @
cam/cam_periph.h:182
KDB: stack backtrace:
db_trace_self_wrapper() at db_trace_self_wrapper+0x2a
witness_warn() at witness_warn+0x23a
uma_zalloc_arg() at uma_zalloc_arg+0x338
malloc() at malloc+0x80
cdioctl() at cdioctl+0x13c3
g_disk_ioctl() at g_disk_ioctl+0x4c
g_dev_ioctl() at g_dev_ioctl+0x83
devfs_ioctl_f() at devfs_ioctl_f+0x71
kern_ioctl() at kern_ioctl+0x91
ioctl() at ioctl+0xe8
syscall() at syscall+0x1ce
Xfast_syscall() at Xfast_syscall+0xab
--- syscall (54, FreeBSD ELF64, ioctl), rip = 0x801c2b27c, rsp =
0x7fffffffa268, rbp = 0x8072e7800 ---
acd0: FAILURE - READ_BIG timed out
-----

>How-To-Repeat:

Try to play scratchy DVD/CD disk that will cause read timeouts.  WITNESS
will complain, if it is enabled.  System could hang after some timeouts.
Or may be it won't hang -- it depends on the actual thread layout.

I am using atapicam emulation layer, but this should be also reproducible
with native SCSI CD/DVD devices.

>Fix:

The following simple patch works for me.  I am living with it for around
a week and tried to play many scratchy disks -- no errors or hangups,
just 'acd0: FAILURE - READ_BIG timed out' messages, but this is expected.

--- scsi_cd-cdreaddvdstructure-use-M_NOWAIT.diff begins here ---
From 42386566b7816a95a7245df0163d8049d9d59376 Mon Sep 17 00:00:00 2001
From: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
Date: Sat, 17 Jan 2009 07:31:41 +0300

Signed-off-by: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
---
 sys/cam/scsi/scsi_cd.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c
index f97ed41..f084cae 100644
--- a/sys/cam/scsi/scsi_cd.c
+++ b/sys/cam/scsi/scsi_cd.c
@@ -4063,7 +4063,7 @@ cdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct)
 	}
 
 	if (length != 0) {
-		databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
+		databuf = malloc(length, M_DEVBUF, M_NOWAIT | M_ZERO);
 	} else
 		databuf = NULL;
 
-- 
1.6.0.5
--- scsi_cd-cdreaddvdstructure-use-M_NOWAIT.diff ends here ---
>Release-Note:
>Audit-Trail:

From: Jaakko Heinonen <jh@saunalahti.fi>
To: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/130735: [patch] pass M_NOWAIT to the malloc() call inside
	cdreaddvdstructure()
Date: Mon, 19 Jan 2009 17:06:47 +0200

 Hi,
 
 On 2009-01-19, Eygene Ryabinkin wrote:
 > --- a/sys/cam/scsi/scsi_cd.c
 > +++ b/sys/cam/scsi/scsi_cd.c
 > @@ -4063,7 +4063,7 @@ cdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct)
 >  	}
 >  
 >  	if (length != 0) {
 > -		databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
 > +		databuf = malloc(length, M_DEVBUF, M_NOWAIT | M_ZERO);
 >  	} else
 >  		databuf = NULL;
 
 This change doesn't look correct. If you use M_NOWAIT malloc(9) can fail
 and return NULL. You should check the return value.
 
 -- 
 Jaakko
Responsible-Changed-From-To: freebsd-bugs->freebsd-scsi 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Mon Jan 19 15:34:25 UTC 2009 
Responsible-Changed-Why:  
Over to maintainer(s). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=130735 

From: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
To: Jaakko Heinonen <jh@saunalahti.fi>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/130735: [patch] pass M_NOWAIT to the malloc() call inside
	cdreaddvdstructure()
Date: Mon, 19 Jan 2009 22:25:28 +0300

 --WIyZ46R2i8wDzkSu
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 Jakko, good day.
 
 Mon, Jan 19, 2009 at 05:06:47PM +0200, Jaakko Heinonen wrote:
 > On 2009-01-19, Eygene Ryabinkin wrote:
 > > --- a/sys/cam/scsi/scsi_cd.c
 > > +++ b/sys/cam/scsi/scsi_cd.c
 > > @@ -4063,7 +4063,7 @@ cdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct)
 > >  	}
 > >  
 > >  	if (length != 0) {
 > > -		databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
 > > +		databuf = malloc(length, M_DEVBUF, M_NOWAIT | M_ZERO);
 > >  	} else
 > >  		databuf = NULL;
 > 
 > This change doesn't look correct. If you use M_NOWAIT malloc(9) can fail
 > and return NULL.
 
 Good catch -- I wasn't aware of it.  The attached patch should be
 slightly better.
 -- 
 Eygene
  _                ___       _.--.   #
  \`.|\..----...-'`   `-._.-'_.-'`   #  Remember that it is hard
  /  ' `         ,       __.--'      #  to read the on-line manual
  )/' _/     \   `-_,   /            #  while single-stepping the kernel.
  `-'" `"\_  ,_.-;_.-\_ ',  fsc/as   #
      _.-'_./   {_.'   ; /           #    -- FreeBSD Developers handbook
     {_.-``-'         {_/            #
 
 --WIyZ46R2i8wDzkSu
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename=p
 
 --- sys/cam/scsi/scsi_cd.c.orig	2007-07-21 22:07:45.000000000 +0400
 +++ sys/cam/scsi/scsi_cd.c	2009-01-19 22:19:18.000000000 +0300
 @@ -4063,7 +4063,11 @@
  	}
  
  	if (length != 0) {
 -		databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
 +		databuf = malloc(length, M_DEVBUF, M_NOWAIT | M_ZERO);
 +		if (databuf == NULL) {
 +			error = ENOMEM;
 +			goto bailout;
 +		}
  	} else
  		databuf = NULL;
  
 
 --WIyZ46R2i8wDzkSu--

From: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
To: bug-followup@FreeBSD.org
Cc: mav@freebsd.org, scottl@freebsd.org
Subject: Re: kern/130735: [patch] pass M_NOWAIT to the malloc() call inside
 cdreaddvdstructure()
Date: Sat, 24 Oct 2009 23:40:43 +0400

 Gentlemen, good day.
 
 I am feeling myself lucky today -- may be someone will be able
 to look at this PR and fix the bad malloc() invocation?
 
 Thanks!
 -- 
 Eygene
  _                ___       _.--.   #
  \`.|\..----...-'`   `-._.-'_.-'`   #  Remember that it is hard
  /  ' `         ,       __.--'      #  to read the on-line manual
  )/' _/     \   `-_,   /            #  while single-stepping the kernel.
  `-'" `"\_  ,_.-;_.-\_ ',  fsc/as   #
      _.-'_./   {_.'   ; /           #    -- FreeBSD Developers handbook
     {_.-``-'         {_/            #

From: Jaakko Heinonen <jh@FreeBSD.org>
To: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/130735: [patch] pass M_NOWAIT to the malloc() call inside
	cdreaddvdstructure()
Date: Mon, 26 Oct 2009 11:19:20 +0200

 Hi,
 
 On 2009-10-24, Eygene Ryabinkin wrote:
 >  I am feeling myself lucky today -- may be someone will be able
 >  to look at this PR and fix the bad malloc() invocation?
 
 I have been looking at this. The same problem also exists in
 cdreportkey() and cdsendkey(). I think that it's better to drop periph
 lock while doing M_WAITOK malloc instead of using M_NOWAIT. Could you
 test and look at this patch:
 
 http://www.saunalahti.fi/~jh3/patches/scsi_cd-M_WAITOK-fixes.diff
 
 -- 
 Jaakko

From: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
To: Jaakko Heinonen <jh@FreeBSD.org>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/130735: [patch] pass M_NOWAIT to the malloc() call inside
 cdreaddvdstructure()
Date: Thu, 29 Oct 2009 10:40:27 +0300

 Jaakko, good day.
 
 Mon, Oct 26, 2009 at 11:19:20AM +0200, Jaakko Heinonen wrote:
 > I have been looking at this. The same problem also exists in
 > cdreportkey() and cdsendkey(). I think that it's better to drop periph
 > lock while doing M_WAITOK malloc instead of using M_NOWAIT. Could you
 > test and look at this patch:
 > 
 > http://www.saunalahti.fi/~jh3/patches/scsi_cd-M_WAITOK-fixes.diff
 
 It works fine for me.  Alhough I am no completely familiar with the CAM
 locking (and that't why I had patched with M_NOWAIT rather than with
 dropping the locks), so I can't fully judge if dropping the lock inside
 the helper is good.  As I understand, locking is done to prevent races
 with other requests on the same device.  Most probably, dropping the
 lock inside cdreportkey(), cdsendkey() and cdreaddvdstructure(), is OK,
 since all three calls are wrapped by the lock/unlock in the ioctl
 handler like this:
 -----
 cam_periph_lock(periph);
 error = cdXXX(ARGS);
 cam_periph_unlock(periph);
 -----
 so dropping the lock at the entry and restoring it after the malloc
 call is just equivalent to the moving the lock acquisition/release
 to the functions themselves.  I mean that these three functions can
 be called unlocked and will have the following structure:
 -----
 int cdXXX(...) {
 	check for sanity
 	grab the memory
 	cam_periph_lock(periph);
 	do the stuff
 	cam_periph_unlock(periph);
 }
 -----
 It looks a bit cleaner from the design point of view (and that is what
 happens in practice, because the situation when the caller locks us and
 we unlock the stuff readily upon the entry to the function, just leads
 to the two locking calls that essentially do nothing): one won't think
 "heck, why we're dropping the lock here, will it be good?".  But this
 contradicts with the general stratedy of scsi_cd.c to call all helper
 functions that do the actual work locked.  Perhaps, the comment on the
 top of the cdioctl() that explains that everything, but the ioctl
 helpers that need malloc(M_WAIT), will be called locked and the said
 functions should grab the locks by themselves.
 -- 
 Eygene
  _                ___       _.--.   #
  \`.|\..----...-'`   `-._.-'_.-'`   #  Remember that it is hard
  /  ' `         ,       __.--'      #  to read the on-line manual
  )/' _/     \   `-_,   /            #  while single-stepping the kernel.
  `-'" `"\_  ,_.-;_.-\_ ',  fsc/as   #
      _.-'_./   {_.'   ; /           #    -- FreeBSD Developers handbook
     {_.-``-'         {_/            #
State-Changed-From-To: open->patched 
State-Changed-By: jh 
State-Changed-When: Wed Dec 2 17:00:16 UTC 2009 
State-Changed-Why:  
Patched in head (r200036). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=130735 
Responsible-Changed-From-To: freebsd-scsi->jh 
Responsible-Changed-By: jh 
Responsible-Changed-When: Wed Oct 13 13:57:14 UTC 2010 
Responsible-Changed-Why:  
Take. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=130735 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/130735: commit references a PR
Date: Wed, 13 Oct 2010 14:03:01 +0000 (UTC)

 Author: jh
 Date: Wed Oct 13 14:02:45 2010
 New Revision: 213776
 URL: http://svn.freebsd.org/changeset/base/213776
 
 Log:
   MFC r200036 by scottl:
   
   Fix several cases where the periph lock was held over malloc.
   
   PR:		kern/130735
 
 Modified:
   stable/8/sys/cam/scsi/scsi_cd.c
 Directory Properties:
   stable/8/sys/   (props changed)
   stable/8/sys/amd64/include/xen/   (props changed)
   stable/8/sys/cddl/contrib/opensolaris/   (props changed)
   stable/8/sys/contrib/dev/acpica/   (props changed)
   stable/8/sys/contrib/pf/   (props changed)
   stable/8/sys/dev/xen/xenpci/   (props changed)
 
 Modified: stable/8/sys/cam/scsi/scsi_cd.c
 ==============================================================================
 --- stable/8/sys/cam/scsi/scsi_cd.c	Wed Oct 13 13:22:11 2010	(r213775)
 +++ stable/8/sys/cam/scsi/scsi_cd.c	Wed Oct 13 14:02:45 2010	(r213776)
 @@ -2671,12 +2671,10 @@ cdioctl(struct disk *dp, u_long cmd, voi
  
  		authinfo = (struct dvd_authinfo *)addr;
  
 -		cam_periph_lock(periph);
  		if (cmd == DVDIOCREPORTKEY)
  			error = cdreportkey(periph, authinfo);
  		else
  			error = cdsendkey(periph, authinfo);
 -		cam_periph_unlock(periph);
  		break;
  		}
  	case DVDIOCREADSTRUCTURE: {
 @@ -2684,9 +2682,7 @@ cdioctl(struct disk *dp, u_long cmd, voi
  
  		dvdstruct = (struct dvd_struct *)addr;
  
 -		cam_periph_lock(periph);
  		error = cdreaddvdstructure(periph, dvdstruct);
 -		cam_periph_unlock(periph);
  
  		break;
  	}
 @@ -3732,8 +3728,6 @@ cdreportkey(struct cam_periph *periph, s
  	databuf = NULL;
  	lba = 0;
  
 -	ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
 -
  	switch (authinfo->format) {
  	case DVD_REPORT_AGID:
  		length = sizeof(struct scsi_report_key_data_agid);
 @@ -3759,9 +3753,7 @@ cdreportkey(struct cam_periph *periph, s
  		length = 0;
  		break;
  	default:
 -		error = EINVAL;
 -		goto bailout;
 -		break; /* NOTREACHED */
 +		return (EINVAL);
  	}
  
  	if (length != 0) {
 @@ -3769,6 +3761,8 @@ cdreportkey(struct cam_periph *periph, s
  	} else
  		databuf = NULL;
  
 +	cam_periph_lock(periph);
 +	ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
  
  	scsi_report_key(&ccb->csio,
  			/* retries */ cd_retry_count,
 @@ -3869,12 +3863,14 @@ cdreportkey(struct cam_periph *periph, s
  		goto bailout;
  		break; /* NOTREACHED */
  	}
 +
  bailout:
 +	xpt_release_ccb(ccb);
 +	cam_periph_unlock(periph);
 +
  	if (databuf != NULL)
  		free(databuf, M_DEVBUF);
  
 -	xpt_release_ccb(ccb);
 -
  	return(error);
  }
  
 @@ -3889,8 +3885,6 @@ cdsendkey(struct cam_periph *periph, str
  	error = 0;
  	databuf = NULL;
  
 -	ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
 -
  	switch(authinfo->format) {
  	case DVD_SEND_CHALLENGE: {
  		struct scsi_report_key_data_challenge *challenge_data;
 @@ -3942,11 +3936,12 @@ cdsendkey(struct cam_periph *periph, str
  		break;
  	}
  	default:
 -		error = EINVAL;
 -		goto bailout;
 -		break; /* NOTREACHED */
 +		return (EINVAL);
  	}
  
 +	cam_periph_lock(periph);
 +	ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
 +
  	scsi_send_key(&ccb->csio,
  		      /* retries */ cd_retry_count,
  		      /* cbfcnp */ cddone,
 @@ -3961,13 +3956,12 @@ cdsendkey(struct cam_periph *periph, str
  	error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
  			 /*sense_flags*/SF_RETRY_UA);
  
 -bailout:
 +	xpt_release_ccb(ccb);
 +	cam_periph_unlock(periph);
  
  	if (databuf != NULL)
  		free(databuf, M_DEVBUF);
  
 -	xpt_release_ccb(ccb);
 -
  	return(error);
  }
  
 @@ -3985,8 +3979,6 @@ cdreaddvdstructure(struct cam_periph *pe
  	/* The address is reserved for many of the formats */
  	address = 0;
  
 -	ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
 -
  	switch(dvdstruct->format) {
  	case DVD_STRUCT_PHYSICAL:
  		length = sizeof(struct scsi_read_dvd_struct_data_physical);
 @@ -4004,13 +3996,7 @@ cdreaddvdstructure(struct cam_periph *pe
  		length = sizeof(struct scsi_read_dvd_struct_data_manufacturer);
  		break;
  	case DVD_STRUCT_CMI:
 -		error = ENODEV;
 -		goto bailout;
 -#ifdef notyet
 -		length = sizeof(struct scsi_read_dvd_struct_data_copy_manage);
 -		address = dvdstruct->address;
 -#endif
 -		break; /* NOTREACHED */
 +		return (ENODEV);
  	case DVD_STRUCT_PROTDISCID:
  		length = sizeof(struct scsi_read_dvd_struct_data_prot_discid);
  		break;
 @@ -4027,21 +4013,9 @@ cdreaddvdstructure(struct cam_periph *pe
  		length = sizeof(struct scsi_read_dvd_struct_data_spare_area);
  		break;
  	case DVD_STRUCT_RMD_LAST:
 -		error = ENODEV;
 -		goto bailout;
 -#ifdef notyet
 -		length = sizeof(struct scsi_read_dvd_struct_data_rmd_borderout);
 -		address = dvdstruct->address;
 -#endif
 -		break; /* NOTREACHED */
 +		return (ENODEV);
  	case DVD_STRUCT_RMD_RMA:
 -		error = ENODEV;
 -		goto bailout;
 -#ifdef notyet
 -		length = sizeof(struct scsi_read_dvd_struct_data_rmd);
 -		address = dvdstruct->address;
 -#endif
 -		break; /* NOTREACHED */
 +		return (ENODEV);
  	case DVD_STRUCT_PRERECORDED:
  		length = sizeof(struct scsi_read_dvd_struct_data_leadin);
  		break;
 @@ -4049,13 +4023,7 @@ cdreaddvdstructure(struct cam_periph *pe
  		length = sizeof(struct scsi_read_dvd_struct_data_disc_id);
  		break;
  	case DVD_STRUCT_DCB:
 -		error = ENODEV;
 -		goto bailout;
 -#ifdef notyet
 -		length = sizeof(struct scsi_read_dvd_struct_data_dcb);
 -		address = dvdstruct->address;
 -#endif
 -		break; /* NOTREACHED */
 +		return (ENODEV);
  	case DVD_STRUCT_LIST:
  		/*
  		 * This is the maximum allocation length for the READ DVD
 @@ -4067,9 +4035,7 @@ cdreaddvdstructure(struct cam_periph *pe
  		length = 65535;
  		break;
  	default:
 -		error = EINVAL;
 -		goto bailout;
 -		break; /* NOTREACHED */
 +		return (EINVAL);
  	}
  
  	if (length != 0) {
 @@ -4077,6 +4043,9 @@ cdreaddvdstructure(struct cam_periph *pe
  	} else
  		databuf = NULL;
  
 +	cam_periph_lock(periph);
 +	ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
 +
  	scsi_read_dvd_structure(&ccb->csio,
  				/* retries */ cd_retry_count,
  				/* cbfcnp */ cddone,
 @@ -4164,13 +4133,14 @@ cdreaddvdstructure(struct cam_periph *pe
  		      min(sizeof(dvdstruct->data), dvdstruct->length));
  		break;
  	}
 +
  bailout:
 +	xpt_release_ccb(ccb);
 +	cam_periph_unlock(periph);
  
  	if (databuf != NULL)
  		free(databuf, M_DEVBUF);
  
 -	xpt_release_ccb(ccb);
 -
  	return(error);
  }
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/130735: commit references a PR
Date: Thu, 14 Oct 2010 18:02:38 +0000 (UTC)

 Author: jh
 Date: Thu Oct 14 18:02:31 2010
 New Revision: 213843
 URL: http://svn.freebsd.org/changeset/base/213843
 
 Log:
   MFC r200036 by scottl:
   
   Fix several cases where the periph lock was held over malloc.
   
   PR:		kern/130735
 
 Modified:
   stable/7/sys/cam/scsi/scsi_cd.c
 Directory Properties:
   stable/7/sys/   (props changed)
   stable/7/sys/cddl/contrib/opensolaris/   (props changed)
   stable/7/sys/contrib/dev/acpica/   (props changed)
   stable/7/sys/contrib/pf/   (props changed)
 
 Modified: stable/7/sys/cam/scsi/scsi_cd.c
 ==============================================================================
 --- stable/7/sys/cam/scsi/scsi_cd.c	Thu Oct 14 17:57:52 2010	(r213842)
 +++ stable/7/sys/cam/scsi/scsi_cd.c	Thu Oct 14 18:02:31 2010	(r213843)
 @@ -2666,12 +2666,10 @@ cdioctl(struct disk *dp, u_long cmd, voi
  
  		authinfo = (struct dvd_authinfo *)addr;
  
 -		cam_periph_lock(periph);
  		if (cmd == DVDIOCREPORTKEY)
  			error = cdreportkey(periph, authinfo);
  		else
  			error = cdsendkey(periph, authinfo);
 -		cam_periph_unlock(periph);
  		break;
  		}
  	case DVDIOCREADSTRUCTURE: {
 @@ -2679,9 +2677,7 @@ cdioctl(struct disk *dp, u_long cmd, voi
  
  		dvdstruct = (struct dvd_struct *)addr;
  
 -		cam_periph_lock(periph);
  		error = cdreaddvdstructure(periph, dvdstruct);
 -		cam_periph_unlock(periph);
  
  		break;
  	}
 @@ -3726,8 +3722,6 @@ cdreportkey(struct cam_periph *periph, s
  	databuf = NULL;
  	lba = 0;
  
 -	ccb = cdgetccb(periph, /* priority */ 1);
 -
  	switch (authinfo->format) {
  	case DVD_REPORT_AGID:
  		length = sizeof(struct scsi_report_key_data_agid);
 @@ -3753,9 +3747,7 @@ cdreportkey(struct cam_periph *periph, s
  		length = 0;
  		break;
  	default:
 -		error = EINVAL;
 -		goto bailout;
 -		break; /* NOTREACHED */
 +		return (EINVAL);
  	}
  
  	if (length != 0) {
 @@ -3763,6 +3755,8 @@ cdreportkey(struct cam_periph *periph, s
  	} else
  		databuf = NULL;
  
 +	cam_periph_lock(periph);
 +	ccb = cdgetccb(periph, /* priority */ 1);
  
  	scsi_report_key(&ccb->csio,
  			/* retries */ 1,
 @@ -3863,12 +3857,14 @@ cdreportkey(struct cam_periph *periph, s
  		goto bailout;
  		break; /* NOTREACHED */
  	}
 +
  bailout:
 +	xpt_release_ccb(ccb);
 +	cam_periph_unlock(periph);
 +
  	if (databuf != NULL)
  		free(databuf, M_DEVBUF);
  
 -	xpt_release_ccb(ccb);
 -
  	return(error);
  }
  
 @@ -3883,8 +3879,6 @@ cdsendkey(struct cam_periph *periph, str
  	error = 0;
  	databuf = NULL;
  
 -	ccb = cdgetccb(periph, /* priority */ 1);
 -
  	switch(authinfo->format) {
  	case DVD_SEND_CHALLENGE: {
  		struct scsi_report_key_data_challenge *challenge_data;
 @@ -3936,11 +3930,12 @@ cdsendkey(struct cam_periph *periph, str
  		break;
  	}
  	default:
 -		error = EINVAL;
 -		goto bailout;
 -		break; /* NOTREACHED */
 +		return (EINVAL);
  	}
  
 +	cam_periph_lock(periph);
 +	ccb = cdgetccb(periph, /* priority */ 1);
 +
  	scsi_send_key(&ccb->csio,
  		      /* retries */ 1,
  		      /* cbfcnp */ cddone,
 @@ -3955,13 +3950,12 @@ cdsendkey(struct cam_periph *periph, str
  	error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
  			 /*sense_flags*/SF_RETRY_UA);
  
 -bailout:
 +	xpt_release_ccb(ccb);
 +	cam_periph_unlock(periph);
  
  	if (databuf != NULL)
  		free(databuf, M_DEVBUF);
  
 -	xpt_release_ccb(ccb);
 -
  	return(error);
  }
  
 @@ -3979,8 +3973,6 @@ cdreaddvdstructure(struct cam_periph *pe
  	/* The address is reserved for many of the formats */
  	address = 0;
  
 -	ccb = cdgetccb(periph, /* priority */ 1);
 -
  	switch(dvdstruct->format) {
  	case DVD_STRUCT_PHYSICAL:
  		length = sizeof(struct scsi_read_dvd_struct_data_physical);
 @@ -3998,13 +3990,7 @@ cdreaddvdstructure(struct cam_periph *pe
  		length = sizeof(struct scsi_read_dvd_struct_data_manufacturer);
  		break;
  	case DVD_STRUCT_CMI:
 -		error = ENODEV;
 -		goto bailout;
 -#ifdef notyet
 -		length = sizeof(struct scsi_read_dvd_struct_data_copy_manage);
 -		address = dvdstruct->address;
 -#endif
 -		break; /* NOTREACHED */
 +		return (ENODEV);
  	case DVD_STRUCT_PROTDISCID:
  		length = sizeof(struct scsi_read_dvd_struct_data_prot_discid);
  		break;
 @@ -4021,21 +4007,9 @@ cdreaddvdstructure(struct cam_periph *pe
  		length = sizeof(struct scsi_read_dvd_struct_data_spare_area);
  		break;
  	case DVD_STRUCT_RMD_LAST:
 -		error = ENODEV;
 -		goto bailout;
 -#ifdef notyet
 -		length = sizeof(struct scsi_read_dvd_struct_data_rmd_borderout);
 -		address = dvdstruct->address;
 -#endif
 -		break; /* NOTREACHED */
 +		return (ENODEV);
  	case DVD_STRUCT_RMD_RMA:
 -		error = ENODEV;
 -		goto bailout;
 -#ifdef notyet
 -		length = sizeof(struct scsi_read_dvd_struct_data_rmd);
 -		address = dvdstruct->address;
 -#endif
 -		break; /* NOTREACHED */
 +		return (ENODEV);
  	case DVD_STRUCT_PRERECORDED:
  		length = sizeof(struct scsi_read_dvd_struct_data_leadin);
  		break;
 @@ -4043,13 +4017,7 @@ cdreaddvdstructure(struct cam_periph *pe
  		length = sizeof(struct scsi_read_dvd_struct_data_disc_id);
  		break;
  	case DVD_STRUCT_DCB:
 -		error = ENODEV;
 -		goto bailout;
 -#ifdef notyet
 -		length = sizeof(struct scsi_read_dvd_struct_data_dcb);
 -		address = dvdstruct->address;
 -#endif
 -		break; /* NOTREACHED */
 +		return (ENODEV);
  	case DVD_STRUCT_LIST:
  		/*
  		 * This is the maximum allocation length for the READ DVD
 @@ -4061,9 +4029,7 @@ cdreaddvdstructure(struct cam_periph *pe
  		length = 65535;
  		break;
  	default:
 -		error = EINVAL;
 -		goto bailout;
 -		break; /* NOTREACHED */
 +		return (EINVAL);
  	}
  
  	if (length != 0) {
 @@ -4071,6 +4037,9 @@ cdreaddvdstructure(struct cam_periph *pe
  	} else
  		databuf = NULL;
  
 +	cam_periph_lock(periph);
 +	ccb = cdgetccb(periph, /* priority */ 1);
 +
  	scsi_read_dvd_structure(&ccb->csio,
  				/* retries */ 1,
  				/* cbfcnp */ cddone,
 @@ -4158,13 +4127,14 @@ cdreaddvdstructure(struct cam_periph *pe
  		      min(sizeof(dvdstruct->data), dvdstruct->length));
  		break;
  	}
 +
  bailout:
 +	xpt_release_ccb(ccb);
 +	cam_periph_unlock(periph);
  
  	if (databuf != NULL)
  		free(databuf, M_DEVBUF);
  
 -	xpt_release_ccb(ccb);
 -
  	return(error);
  }
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: jh 
State-Changed-When: Thu Oct 14 18:25:25 UTC 2010 
State-Changed-Why:  
Fixed in head, stable/8 and stable/7. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=130735 
>Unformatted:
