Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Jun 2001 18:31:02 -0400 (EDT)
From:      "Alexander N. Kabaev" <ak03@gte.com>
To:        FreeBSD-gnats-submit@freebsd.org
Cc:        cg@freebsd.org
Subject:   kern/28084: Two possible PCM problems and patch
Message-ID:  <200106112231.f5BMV2k00928@h132-197-97-45.gte.com>

next in thread | raw e-mail | index | archive | help

>Number:         28084
>Category:       kern
>Synopsis:       Two possible PCM problems and patch
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jun 11 15:40:01 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Alexander N. Kabaev
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
Verizon Information Technology
>Environment:
System: FreeBSD kanpc.gte.com 5.0-CURRENT FreeBSD 5.0-CURRENT #21: Fri Jun 8 12:48:33 EDT 2001 root@kanpc.gte.com:/usr/src/sys/compile/KANPC i386

>Description:
	There are three possible promlems in the -CURRENT PCM code

	a) pcm_chn_add deletes channel passed to it as a parameter, even 
	   though all pcm_chn_add callers call pcm_chn_destroy themselves
	   when pcm_chn_add fails. pcm_chn_destroy then attempts to delete
	   pcm_channel struct which already has been deleted

	b) dynamic sysctl handler for the number of virtual channels does 
	   not resize d->arec and d->aplay arrays. The code like d->aplay[chan]
	   is used all over the place in PCM, and in presence of dynamically
	   allocated vchannels channel number can be bigger than d->maxchan
	   which is statically computed in pcm_register based of the number
	   of actual hardware channels.

	c) When creating additional vchannels, the code sets CHN_F_BUSY 
	   flag _before_ calling vchan_create and fails to clean that 
	   flag when vchan_create returns error and no other vchannels weres
           created, thus leaving the parent channel permanently busy.
	
>How-To-Repeat:
	N/A
>Fix:

	Attached patch patch tries to address the above problems. With patch
	applied I was able to run my sbc16 sound card with 4 vchannels all
	playing simultaneously :)

Index: pcm/sound.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/sound/pcm/sound.c,v
retrieving revision 1.48
diff -u -r1.48 sound.c
--- pcm/sound.c	2001/06/10 15:48:03	1.48
+++ pcm/sound.c	2001/06/11 20:09:47
@@ -345,10 +345,8 @@
     	int unit = device_get_unit(d->dev);
 
 	sce = malloc(sizeof(*sce), M_DEVBUF, M_WAITOK | M_ZERO);
-	if (!sce) {
-		free(ch, M_DEVBUF);
+	if (!sce)
 		return ENOMEM;
-	}
 
 	snd_mtxlock(d->lock);
 	sce->channel = ch;
Index: pcm/vchan.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/sound/pcm/vchan.c,v
retrieving revision 1.2
diff -u -r1.2 vchan.c
--- pcm/vchan.c	2001/06/07 20:06:22	1.2
+++ pcm/vchan.c	2001/06/11 22:07:31
@@ -331,8 +331,8 @@
 {
 	struct snddev_info *d;
     	struct snddev_channel *sce;
-	struct pcm_channel *c;
-	int err, newcnt, cnt;
+	struct pcm_channel *c, **arec, **aplay;
+	int err, newcnt, cnt, sz;
 
 	d = oidp->oid_arg1;
 
@@ -373,12 +373,36 @@
 			snd_mtxunlock(d->lock);
 			return EBUSY;
 addok:
+			if (d->maxchans < (d->chancount + newcnt - cnt)) {
+				sz = (d->chancount + newcnt - cnt) *
+					sizeof(struct pcm_channel *);
+				aplay = (struct pcm_channel **)
+					malloc(sz, M_DEVBUF, M_WAITOK | M_ZERO);
+				arec = (struct pcm_channel **)
+					malloc(sz, M_DEVBUF, M_WAITOK | M_ZERO);
+                		if (!arec || !aplay) {
+					if (aplay) free(aplay, M_DEVBUF);	
+					if (arec) free(arec, M_DEVBUF);	
+					return ENOMEM;
+				}
+				sz = d->maxchans * sizeof(struct pcm_channel *);
+		                bcopy(d->arec, arec, sz);
+		                bcopy(d->aplay, aplay, sz);
+				free(d->arec, M_DEVBUF);
+				free(d->aplay, M_DEVBUF);
+				d->arec   = arec;
+				d->aplay  = aplay;
+				d->maxchans = d->chancount + newcnt - cnt;
+			}
 			c->flags |= CHN_F_BUSY;
 			while (err == 0 && newcnt > cnt) {
 				err = vchan_create(c);
 				if (err == 0)
 					cnt++;
 			}
+			/* Clear parent busy flag if no children were created */
+			if (SLIST_EMPTY(&c->children))
+				c->flags &= ~CHN_F_BUSY;
 		} else if (newcnt < cnt) {
 			while (err == 0 && newcnt < cnt) {
 				SLIST_FOREACH(sce, &d->channels, link) {
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200106112231.f5BMV2k00928>