Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 18 Oct 2024 08:44:53 GMT
From:      Christos Margiolis <christos@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: ad4c8671bdda - main - sound: Use unr(9) to produce unique channel unit numbers
Message-ID:  <202410180844.49I8irlR087850@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by christos:

URL: https://cgit.FreeBSD.org/src/commit/?id=ad4c8671bddaa30bf0413089c74dde6a618d9021

commit ad4c8671bddaa30bf0413089c74dde6a618d9021
Author:     Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2024-10-18 08:39:08 +0000
Commit:     Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2024-10-18 08:39:08 +0000

    sound: Use unr(9) to produce unique channel unit numbers
    
    Currently it is possible to assign a unit number that already exists.
    Suppose the following channel list:
    
    [vp2]
    
    If we create 3 channels, we'll end up with the following list:
    
    [vp0, vp1, vp2, vp2]
    
    This happens because chn_init() does not check if the unit number we are
    assigning already exists. While fixing this is trivial when the channel
    list is sorted in ascending order, it is way more involved when sorted
    in descending order. Even though sorting the list in descending order
    would require deliberately modifying pcm_chn_add(), and is most likely
    not going to happen, make the mechanism more robust by using a unr(9)
    allocator for each channel type.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      2 days
    Reviewed by:    dev_submerge.ch
    Differential Revision:  https://reviews.freebsd.org/D46680
---
 sys/dev/sound/pcm/channel.c | 31 ++++++++++++++++++++++---------
 sys/dev/sound/pcm/sound.c   | 12 ++++++++++++
 sys/dev/sound/pcm/sound.h   |  4 ++++
 3 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
index bf9c74e2ed1d..d1c9bc616dcf 100644
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -1157,6 +1157,24 @@ chn_reset(struct pcm_channel *c, uint32_t fmt, uint32_t spd)
 	return r;
 }
 
+static struct unrhdr *
+chn_getunr(struct snddev_info *d, int type)
+{
+	switch (type) {
+	case SND_DEV_DSPHW_PLAY:
+		return (d->p_unr);
+	case SND_DEV_DSPHW_VPLAY:
+		return (d->vp_unr);
+	case SND_DEV_DSPHW_REC:
+		return (d->r_unr);
+	case SND_DEV_DSPHW_VREC:
+		return (d->vr_unr);
+	default:
+		__assert_unreachable();
+	}
+
+}
+
 struct pcm_channel *
 chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
     int dir, void *devinfo)
@@ -1165,7 +1183,7 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
 	struct feeder_class *fc;
 	struct snd_dbuf *b, *bs;
 	char *dirs, buf[CHN_NAMELEN];
-	int i, direction, type, unit;
+	int i, direction, type;
 
 	PCM_BUSYASSERT(d);
 	PCM_LOCKASSERT(d);
@@ -1198,13 +1216,6 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
 		return (NULL);
 	}
 
-	unit = 0;
-	CHN_FOREACH(c, d, channels.pcm) {
-		if (c->type != type)
-			continue;
-		unit++;
-	}
-
 	PCM_UNLOCK(d);
 	b = NULL;
 	bs = NULL;
@@ -1216,7 +1227,7 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
 	CHN_INIT(c, children.busy);
 	c->direction = direction;
 	c->type = type;
-	c->unit = unit;
+	c->unit = alloc_unr(chn_getunr(d, c->type));
 	c->format = SND_FORMAT(AFMT_U8, 1, 0);
 	c->speed = DSP_DEFAULT_SPEED;
 	c->pid = -1;
@@ -1304,6 +1315,7 @@ chn_init(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls,
 	return (c);
 
 fail:
+	free_unr(chn_getunr(d, c->type), c->unit);
 	feeder_remove(c);
 	if (c->devinfo && CHANNEL_FREE(c->methods, c->devinfo))
 		sndbuf_free(b);
@@ -1335,6 +1347,7 @@ chn_kill(struct pcm_channel *c)
 		chn_trigger(c, PCMTRIG_ABORT);
 		CHN_UNLOCK(c);
 	}
+	free_unr(chn_getunr(c->parentsnddev, c->type), c->unit);
 	feeder_remove(c);
 	if (CHANNEL_FREE(c->methods, c->devinfo))
 		sndbuf_free(b);
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index 1aaf614078a4..f9c87facfeec 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -568,6 +568,10 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
 	d->pvchanformat = 0;
 	d->rvchanrate = 0;
 	d->rvchanformat = 0;
+	d->p_unr = new_unrhdr(0, INT_MAX, NULL);
+	d->vp_unr = new_unrhdr(0, INT_MAX, NULL);
+	d->r_unr = new_unrhdr(0, INT_MAX, NULL);
+	d->vr_unr = new_unrhdr(0, INT_MAX, NULL);
 
 	CHN_INIT(d, channels.pcm);
 	CHN_INIT(d, channels.pcm.busy);
@@ -653,6 +657,14 @@ pcm_unregister(device_t dev)
 	cv_destroy(&d->cv);
 	PCM_UNLOCK(d);
 	snd_mtxfree(d->lock);
+	if (d->p_unr != NULL)
+		delete_unrhdr(d->p_unr);
+	if (d->vp_unr != NULL)
+		delete_unrhdr(d->vp_unr);
+	if (d->r_unr != NULL)
+		delete_unrhdr(d->r_unr);
+	if (d->vr_unr != NULL)
+		delete_unrhdr(d->vr_unr);
 
 	if (snd_unit == device_get_unit(dev)) {
 		snd_unit = pcm_best_unit(-1);
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
index 5f32dd767fe8..2de6ab29bd66 100644
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -325,6 +325,10 @@ struct snddev_info {
 	struct sysctl_ctx_list play_sysctl_ctx, rec_sysctl_ctx;
 	struct sysctl_oid *play_sysctl_tree, *rec_sysctl_tree;
 	struct cv cv;
+	struct unrhdr *p_unr;
+	struct unrhdr *vp_unr;
+	struct unrhdr *r_unr;
+	struct unrhdr *vr_unr;
 };
 
 void	sound_oss_sysinfo(oss_sysinfo *);



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