Module Name: src
Committed By: martin
Date: Sat Mar 21 15:47:01 UTC 2020
Modified Files:
src/sys/dev/audio [netbsd-9]: audio.c audiodef.h audiovar.h
Log Message:
Pull up following revision(s) (requested by isaki in ticket #794):
sys/dev/audio/audiodef.h: revision 1.10
sys/dev/audio/audio.c: revision 1.56 (via patch)
sys/dev/audio/audio.c: revision 1.57
sys/dev/audio/audiovar.h: revision 1.8
sys/dev/audio/audio.c: revision 1.38
Remove obsoleted comment.
Prevent a race between audiodetach and fileops methods using psref(9).
Fix PR kern/54427.
Thank you so much riastradh@
Release memories on audiobellclose.
It's rest of the last commit.
To generate a diff of this commit:
cvs rdiff -u -r1.28.2.8 -r1.28.2.9 src/sys/dev/audio/audio.c
cvs rdiff -u -r1.7.2.2 -r1.7.2.3 src/sys/dev/audio/audiodef.h
cvs rdiff -u -r1.4.2.1 -r1.4.2.2 src/sys/dev/audio/audiovar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/audio/audio.c
diff -u src/sys/dev/audio/audio.c:1.28.2.8 src/sys/dev/audio/audio.c:1.28.2.9
--- src/sys/dev/audio/audio.c:1.28.2.8 Sat Mar 21 15:41:18 2020
+++ src/sys/dev/audio/audio.c Sat Mar 21 15:47:00 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: audio.c,v 1.28.2.8 2020/03/21 15:41:18 martin Exp $ */
+/* $NetBSD: audio.c,v 1.28.2.9 2020/03/21 15:47:00 martin Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -142,7 +142,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.28.2.8 2020/03/21 15:41:18 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.28.2.9 2020/03/21 15:47:00 martin Exp $");
#ifdef _KERNEL_OPT
#include "audio.h"
@@ -499,6 +499,8 @@ static void audio_softintr_wr(void *);
static int audio_enter_exclusive(struct audio_softc *);
static void audio_exit_exclusive(struct audio_softc *);
+static struct audio_softc *audio_file_enter(audio_file_t *, struct psref *);
+static void audio_file_exit(struct audio_softc *, struct psref *);
static int audio_track_waitio(struct audio_softc *, audio_track_t *);
static int audioclose(struct file *);
@@ -519,6 +521,7 @@ static int filt_audioread_event(struct
static int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *,
audio_file_t **);
static int audio_close(struct audio_softc *, audio_file_t *);
+static int audio_unlink(struct audio_softc *, audio_file_t *);
static int audio_read(struct audio_softc *, struct uio *, int, audio_file_t *);
static int audio_write(struct audio_softc *, struct uio *, int, audio_file_t *);
static void audio_file_clear(struct audio_softc *, audio_file_t *);
@@ -530,7 +533,6 @@ static int audio_mmap(struct audio_softc
struct uvm_object **, int *, audio_file_t *);
static int audioctl_open(dev_t, struct audio_softc *, int, int, struct lwp *);
-static int audioctl_close(struct audio_softc *, audio_file_t *);
static void audio_pintr(void *);
static void audio_rintr(void *);
@@ -811,6 +813,8 @@ static const struct portname otable[] =
{ 0, 0 }
};
+static struct psref_class *audio_psref_class __read_mostly;
+
CFATTACH_DECL3_NEW(audio, sizeof(struct audio_softc),
audiomatch, audioattach, audiodetach, audioactivate, audiorescan,
audiochilddet, DVF_DETACH_SHUTDOWN);
@@ -963,6 +967,9 @@ audioattach(device_t parent, device_t se
goto bad;
}
+ sc->sc_psz = pserialize_create();
+ psref_target_init(&sc->sc_psref, audio_psref_class);
+
selinit(&sc->sc_wsel);
selinit(&sc->sc_rsel);
@@ -1220,7 +1227,7 @@ static int
audiodetach(device_t self, int flags)
{
struct audio_softc *sc;
- int maj, mn;
+ struct audio_file *file;
int error;
sc = device_private(self);
@@ -1235,6 +1242,9 @@ audiodetach(device_t self, int flags)
if (error)
return error;
+ /* delete sysctl nodes */
+ sysctl_teardown(&sc->sc_log);
+
mutex_enter(sc->sc_lock);
sc->sc_dying = true;
cv_broadcast(&sc->sc_exlockcv);
@@ -1242,23 +1252,36 @@ audiodetach(device_t self, int flags)
cv_broadcast(&sc->sc_pmixer->outcv);
if (sc->sc_rmixer)
cv_broadcast(&sc->sc_rmixer->outcv);
- mutex_exit(sc->sc_lock);
- /* delete sysctl nodes */
- sysctl_teardown(&sc->sc_log);
+ /* Prevent new users */
+ SLIST_FOREACH(file, &sc->sc_files, entry) {
+ atomic_store_relaxed(&file->dying, true);
+ }
+
+ /*
+ * Wait for existing users to drain.
+ * - pserialize_perform waits for all pserialize_read sections on
+ * all CPUs; after this, no more new psref_acquire can happen.
+ * - psref_target_destroy waits for all extant acquired psrefs to
+ * be psref_released.
+ */
+ pserialize_perform(sc->sc_psz);
+ mutex_exit(sc->sc_lock);
+ psref_target_destroy(&sc->sc_psref, audio_psref_class);
- /* locate the major number */
- maj = cdevsw_lookup_major(&audio_cdevsw);
+ /*
+ * We are now guaranteed that there are no calls to audio fileops
+ * that hold sc, and any new calls with files that were for sc will
+ * fail. Thus, we now have exclusive access to the softc.
+ */
/*
- * Nuke the vnodes for any open instances (calls close).
- * Will wait until any activity on the device nodes has ceased.
+ * Nuke all open instances.
+ * Here, we no longer need any locks to traverse sc_files.
*/
- mn = device_unit(self);
- vdevgone(maj, mn | SOUND_DEVICE, mn | SOUND_DEVICE, VCHR);
- vdevgone(maj, mn | AUDIO_DEVICE, mn | AUDIO_DEVICE, VCHR);
- vdevgone(maj, mn | AUDIOCTL_DEVICE, mn | AUDIOCTL_DEVICE, VCHR);
- vdevgone(maj, mn | MIXER_DEVICE, mn | MIXER_DEVICE, VCHR);
+ while ((file = SLIST_FIRST(&sc->sc_files)) != NULL) {
+ audio_unlink(sc, file);
+ }
pmf_event_deregister(self, PMFE_AUDIO_VOLUME_DOWN,
audio_volume_down, true);
@@ -1403,6 +1426,48 @@ audio_exit_exclusive(struct audio_softc
}
/*
+ * Acquire sc from file, and increment the psref count.
+ * If successful, returns sc. Otherwise returns NULL.
+ */
+struct audio_softc *
+audio_file_enter(audio_file_t *file, struct psref *refp)
+{
+ int s;
+ bool dying;
+
+ /* psref(9) forbids to migrate CPUs */
+ curlwp_bind();
+
+ /* Block audiodetach while we acquire a reference */
+ s = pserialize_read_enter();
+
+ /* If close or audiodetach already ran, tough -- no more audio */
+ dying = atomic_load_relaxed(&file->dying);
+ if (dying) {
+ pserialize_read_exit(s);
+ return NULL;
+ }
+
+ /* Acquire a reference */
+ psref_acquire(refp, &file->sc->sc_psref, audio_psref_class);
+
+ /* Now sc won't go away until we drop the reference count */
+ pserialize_read_exit(s);
+
+ return file->sc;
+}
+
+/*
+ * Decrement the psref count.
+ */
+void
+audio_file_exit(struct audio_softc *sc, struct psref *refp)
+{
+
+ psref_release(refp, &sc->sc_psref, audio_psref_class);
+}
+
+/*
* Wait for I/O to complete, releasing sc_lock.
* Must be called with sc_lock held.
*/
@@ -1503,34 +1568,51 @@ static int
audioclose(struct file *fp)
{
struct audio_softc *sc;
+ struct psref sc_ref;
audio_file_t *file;
int error;
dev_t dev;
KASSERT(fp->f_audioctx);
file = fp->f_audioctx;
- sc = file->sc;
dev = file->dev;
+ error = 0;
- /* audio_{enter,exit}_exclusive() is called by lower audio_close() */
+ /*
+ * audioclose() must
+ * - unplug track from the trackmixer (and unplug anything from softc),
+ * if sc exists.
+ * - free all memory objects, regardless of sc.
+ */
- device_active(sc->sc_dev, DVA_SYSTEM);
- switch (AUDIODEV(dev)) {
- case SOUND_DEVICE:
- case AUDIO_DEVICE:
- error = audio_close(sc, file);
- break;
- case AUDIOCTL_DEVICE:
- error = audioctl_close(sc, file);
- break;
- case MIXER_DEVICE:
- error = mixer_close(sc, file);
- break;
- default:
- error = ENXIO;
- break;
+ sc = audio_file_enter(file, &sc_ref);
+ if (sc) {
+ switch (AUDIODEV(dev)) {
+ case SOUND_DEVICE:
+ case AUDIO_DEVICE:
+ error = audio_close(sc, file);
+ break;
+ case AUDIOCTL_DEVICE:
+ error = 0;
+ break;
+ case MIXER_DEVICE:
+ error = mixer_close(sc, file);
+ break;
+ default:
+ error = ENXIO;
+ break;
+ }
+
+ audio_file_exit(sc, &sc_ref);
}
- /* f_audioctx has already been freed in lower *_close() */
+
+ /* Free memory objects anyway */
+ TRACEF(2, file, "free memory");
+ if (file->ptrack)
+ audio_track_destroy(file->ptrack);
+ if (file->rtrack)
+ audio_track_destroy(file->rtrack);
+ kmem_free(file, sizeof(*file));
fp->f_audioctx = NULL;
return error;
@@ -1541,15 +1623,19 @@ audioread(struct file *fp, off_t *offp,
int ioflag)
{
struct audio_softc *sc;
+ struct psref sc_ref;
audio_file_t *file;
int error;
dev_t dev;
KASSERT(fp->f_audioctx);
file = fp->f_audioctx;
- sc = file->sc;
dev = file->dev;
+ sc = audio_file_enter(file, &sc_ref);
+ if (sc == NULL)
+ return EIO;
+
if (fp->f_flag & O_NONBLOCK)
ioflag |= IO_NDELAY;
@@ -1567,6 +1653,7 @@ audioread(struct file *fp, off_t *offp,
break;
}
+ audio_file_exit(sc, &sc_ref);
return error;
}
@@ -1575,15 +1662,19 @@ audiowrite(struct file *fp, off_t *offp,
int ioflag)
{
struct audio_softc *sc;
+ struct psref sc_ref;
audio_file_t *file;
int error;
dev_t dev;
KASSERT(fp->f_audioctx);
file = fp->f_audioctx;
- sc = file->sc;
dev = file->dev;
+ sc = audio_file_enter(file, &sc_ref);
+ if (sc == NULL)
+ return EIO;
+
if (fp->f_flag & O_NONBLOCK)
ioflag |= IO_NDELAY;
@@ -1601,6 +1692,7 @@ audiowrite(struct file *fp, off_t *offp,
break;
}
+ audio_file_exit(sc, &sc_ref);
return error;
}
@@ -1608,6 +1700,7 @@ static int
audioioctl(struct file *fp, u_long cmd, void *addr)
{
struct audio_softc *sc;
+ struct psref sc_ref;
audio_file_t *file;
struct lwp *l = curlwp;
int error;
@@ -1615,9 +1708,12 @@ audioioctl(struct file *fp, u_long cmd,
KASSERT(fp->f_audioctx);
file = fp->f_audioctx;
- sc = file->sc;
dev = file->dev;
+ sc = audio_file_enter(file, &sc_ref);
+ if (sc == NULL)
+ return EIO;
+
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
@@ -1639,23 +1735,32 @@ audioioctl(struct file *fp, u_long cmd,
break;
}
+ audio_file_exit(sc, &sc_ref);
return error;
}
static int
audiostat(struct file *fp, struct stat *st)
{
+ struct audio_softc *sc;
+ struct psref sc_ref;
audio_file_t *file;
KASSERT(fp->f_audioctx);
file = fp->f_audioctx;
+ sc = audio_file_enter(file, &sc_ref);
+ if (sc == NULL)
+ return EIO;
+
memset(st, 0, sizeof(*st));
st->st_dev = file->dev;
st->st_uid = kauth_cred_geteuid(fp->f_cred);
st->st_gid = kauth_cred_getegid(fp->f_cred);
st->st_mode = S_IFCHR;
+
+ audio_file_exit(sc, &sc_ref);
return 0;
}
@@ -1663,6 +1768,7 @@ static int
audiopoll(struct file *fp, int events)
{
struct audio_softc *sc;
+ struct psref sc_ref;
audio_file_t *file;
struct lwp *l = curlwp;
int revents;
@@ -1670,9 +1776,12 @@ audiopoll(struct file *fp, int events)
KASSERT(fp->f_audioctx);
file = fp->f_audioctx;
- sc = file->sc;
dev = file->dev;
+ sc = audio_file_enter(file, &sc_ref);
+ if (sc == NULL)
+ return EIO;
+
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
@@ -1687,6 +1796,7 @@ audiopoll(struct file *fp, int events)
break;
}
+ audio_file_exit(sc, &sc_ref);
return revents;
}
@@ -1694,15 +1804,19 @@ static int
audiokqfilter(struct file *fp, struct knote *kn)
{
struct audio_softc *sc;
+ struct psref sc_ref;
audio_file_t *file;
dev_t dev;
int error;
KASSERT(fp->f_audioctx);
file = fp->f_audioctx;
- sc = file->sc;
dev = file->dev;
+ sc = audio_file_enter(file, &sc_ref);
+ if (sc == NULL)
+ return EIO;
+
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
@@ -1717,6 +1831,7 @@ audiokqfilter(struct file *fp, struct kn
break;
}
+ audio_file_exit(sc, &sc_ref);
return error;
}
@@ -1725,15 +1840,19 @@ audiommap(struct file *fp, off_t *offp,
int *advicep, struct uvm_object **uobjp, int *maxprotp)
{
struct audio_softc *sc;
+ struct psref sc_ref;
audio_file_t *file;
dev_t dev;
int error;
KASSERT(fp->f_audioctx);
file = fp->f_audioctx;
- sc = file->sc;
dev = file->dev;
+ sc = audio_file_enter(file, &sc_ref);
+ if (sc == NULL)
+ return EIO;
+
mutex_enter(sc->sc_lock);
device_active(sc->sc_dev, DVA_SYSTEM); /* XXXJDM */
mutex_exit(sc->sc_lock);
@@ -1751,6 +1870,7 @@ audiommap(struct file *fp, off_t *offp,
break;
}
+ audio_file_exit(sc, &sc_ref);
return error;
}
@@ -1789,18 +1909,21 @@ int
audiobellclose(audio_file_t *file)
{
struct audio_softc *sc;
+ struct psref sc_ref;
int error;
- sc = file->sc;
+ sc = audio_file_enter(file, &sc_ref);
+ if (sc == NULL)
+ return EIO;
- device_active(sc->sc_dev, DVA_SYSTEM);
error = audio_close(sc, file);
- /*
- * Since file has already been destructed,
- * audio_file_release() is not necessary.
- */
+ audio_file_exit(sc, &sc_ref);
+ KASSERT(file->ptrack);
+ audio_track_destroy(file->ptrack);
+ KASSERT(file->rtrack == NULL);
+ kmem_free(file, sizeof(*file));
return error;
}
@@ -1809,20 +1932,25 @@ int
audiobellsetrate(audio_file_t *file, u_int sample_rate)
{
struct audio_softc *sc;
+ struct psref sc_ref;
struct audio_info ai;
int error;
- sc = file->sc;
+ sc = audio_file_enter(file, &sc_ref);
+ if (sc == NULL)
+ return EIO;
AUDIO_INITINFO(&ai);
ai.play.sample_rate = sample_rate;
error = audio_enter_exclusive(sc);
if (error)
- return error;
+ goto done;
error = audio_file_setinfo(sc, file, &ai);
audio_exit_exclusive(sc);
+done:
+ audio_file_exit(sc, &sc_ref);
return error;
}
@@ -1831,10 +1959,16 @@ int
audiobellwrite(audio_file_t *file, struct uio *uio)
{
struct audio_softc *sc;
+ struct psref sc_ref;
int error;
- sc = file->sc;
+ sc = audio_file_enter(file, &sc_ref);
+ if (sc == NULL)
+ return EIO;
+
error = audio_write(sc, uio, 0, file);
+
+ audio_file_exit(sc, &sc_ref);
return error;
}
@@ -2099,7 +2233,30 @@ bad1:
int
audio_close(struct audio_softc *sc, audio_file_t *file)
{
- audio_track_t *oldtrack;
+
+ /* Protect entering new fileops to this file */
+ atomic_store_relaxed(&file->dying, true);
+
+ /*
+ * Drain first.
+ * It must be done before unlinking(acquiring exclusive lock).
+ */
+ if (file->ptrack) {
+ mutex_enter(sc->sc_lock);
+ audio_track_drain(sc, file->ptrack);
+ mutex_exit(sc->sc_lock);
+ }
+
+ return audio_unlink(sc, file);
+}
+
+/*
+ * Unlink this file, but not freeing memory here.
+ * Must be called without sc_lock nor sc_exlock held.
+ */
+int
+audio_unlink(struct audio_softc *sc, audio_file_t *file)
+{
int error;
TRACEF(1, file, "%spid=%d.%d po=%d ro=%d",
@@ -2110,46 +2267,50 @@ audio_close(struct audio_softc *sc, audi
"sc->sc_popens=%d, sc->sc_ropens=%d",
sc->sc_popens, sc->sc_ropens);
+ mutex_enter(sc->sc_lock);
/*
- * Drain first.
- * It must be done before acquiring exclusive lock.
+ * Acquire exclusive lock to protect counters.
+ * Does not use audio_enter_exclusive() due to sc_dying.
*/
- if (file->ptrack) {
- mutex_enter(sc->sc_lock);
- audio_track_drain(sc, file->ptrack);
- mutex_exit(sc->sc_lock);
+ while (__predict_false(sc->sc_exlock != 0)) {
+ error = cv_timedwait_sig(&sc->sc_exlockcv, sc->sc_lock,
+ mstohz(AUDIO_TIMEOUT));
+ /* XXX what should I do on error? */
+ if (error == EWOULDBLOCK) {
+ mutex_exit(sc->sc_lock);
+ device_printf(sc->sc_dev,
+ "%s: cv_timedwait_sig failed %d", __func__, error);
+ return error;
+ }
}
+ sc->sc_exlock = 1;
- /* Then, acquire exclusive lock to protect counters. */
- /* XXX what should I do when an error occurs? */
- error = audio_enter_exclusive(sc);
- if (error)
- return error;
+ device_active(sc->sc_dev, DVA_SYSTEM);
+
+ mutex_enter(sc->sc_intr_lock);
+ SLIST_REMOVE(&sc->sc_files, file, audio_file, entry);
+ mutex_exit(sc->sc_intr_lock);
if (file->ptrack) {
+ TRACET(3, file->ptrack, "dropframes=%" PRIu64,
+ file->ptrack->dropframes);
+
+ KASSERT(sc->sc_popens > 0);
+ sc->sc_popens--;
+
/* Call hw halt_output if this is the last playback track. */
- if (sc->sc_popens == 1 && sc->sc_pbusy) {
+ if (sc->sc_popens == 0 && sc->sc_pbusy) {
error = audio_pmixer_halt(sc);
if (error) {
device_printf(sc->sc_dev,
- "halt_output failed with %d\n", error);
+ "halt_output failed with %d (ignored)\n",
+ error);
}
}
- /* Destroy the track. */
- oldtrack = file->ptrack;
- mutex_enter(sc->sc_intr_lock);
- file->ptrack = NULL;
- mutex_exit(sc->sc_intr_lock);
- TRACET(3, oldtrack, "dropframes=%" PRIu64,
- oldtrack->dropframes);
- audio_track_destroy(oldtrack);
-
- KASSERT(sc->sc_popens > 0);
- sc->sc_popens--;
-
/* Restore mixing volume if all tracks are gone. */
if (sc->sc_popens == 0) {
+ /* intr_lock is not necessary, but just manners. */
mutex_enter(sc->sc_intr_lock);
sc->sc_pmixer->volume = 256;
sc->sc_pmixer->voltimer = 0;
@@ -2157,26 +2318,22 @@ audio_close(struct audio_softc *sc, audi
}
}
if (file->rtrack) {
+ TRACET(3, file->rtrack, "dropframes=%" PRIu64,
+ file->rtrack->dropframes);
+
+ KASSERT(sc->sc_ropens > 0);
+ sc->sc_ropens--;
+
/* Call hw halt_input if this is the last recording track. */
- if (sc->sc_ropens == 1 && sc->sc_rbusy) {
+ if (sc->sc_ropens == 0 && sc->sc_rbusy) {
error = audio_rmixer_halt(sc);
if (error) {
device_printf(sc->sc_dev,
- "halt_input failed with %d\n", error);
+ "halt_input failed with %d (ignored)\n",
+ error);
}
}
- /* Destroy the track. */
- oldtrack = file->rtrack;
- mutex_enter(sc->sc_intr_lock);
- file->rtrack = NULL;
- mutex_exit(sc->sc_intr_lock);
- TRACET(3, oldtrack, "dropframes=%" PRIu64,
- oldtrack->dropframes);
- audio_track_destroy(oldtrack);
-
- KASSERT(sc->sc_ropens > 0);
- sc->sc_ropens--;
}
/* Call hw close if this is the last track. */
@@ -2191,14 +2348,9 @@ audio_close(struct audio_softc *sc, audi
kauth_cred_free(sc->sc_cred);
}
- mutex_enter(sc->sc_intr_lock);
- SLIST_REMOVE(&sc->sc_files, file, audio_file, entry);
- mutex_exit(sc->sc_intr_lock);
-
TRACE(3, "done");
audio_exit_exclusive(sc);
- kmem_free(file, sizeof(*file));
return 0;
}
@@ -3064,14 +3216,6 @@ audioctl_open(dev_t dev, struct audio_so
return error;
}
-static int
-audioctl_close(struct audio_softc *sc, audio_file_t *file)
-{
-
- kmem_free(file, sizeof(*file));
- return 0;
-}
-
/*
* Free 'mem' if available, and initialize the pointer.
* For this reason, this is implemented as macro.
@@ -7688,7 +7832,6 @@ mixer_close(struct audio_softc *sc, audi
mixer_remove(sc);
mutex_exit(sc->sc_lock);
- kmem_free(file, sizeof(*file));
return 0;
}
@@ -8447,9 +8590,11 @@ audio_modcmd(modcmd_t cmd, void *arg)
{
int error = 0;
-#ifdef _MODULE
switch (cmd) {
case MODULE_CMD_INIT:
+ /* XXX interrupt level? */
+ audio_psref_class = psref_class_create("audio", IPL_SOFTSERIAL);
+#ifdef _MODULE
error = devsw_attach(audio_cd.cd_name, NULL, &audio_bmajor,
&audio_cdevsw, &audio_cmajor);
if (error)
@@ -8460,20 +8605,23 @@ audio_modcmd(modcmd_t cmd, void *arg)
if (error) {
devsw_detach(NULL, &audio_cdevsw);
}
+#endif
break;
case MODULE_CMD_FINI:
+#ifdef _MODULE
devsw_detach(NULL, &audio_cdevsw);
error = config_fini_component(cfdriver_ioconf_audio,
cfattach_ioconf_audio, cfdata_ioconf_audio);
if (error)
devsw_attach(audio_cd.cd_name, NULL, &audio_bmajor,
&audio_cdevsw, &audio_cmajor);
+#endif
+ psref_class_destroy(audio_psref_class);
break;
default:
error = ENOTTY;
break;
}
-#endif
return error;
}
Index: src/sys/dev/audio/audiodef.h
diff -u src/sys/dev/audio/audiodef.h:1.7.2.2 src/sys/dev/audio/audiodef.h:1.7.2.3
--- src/sys/dev/audio/audiodef.h:1.7.2.2 Sat Mar 21 15:41:18 2020
+++ src/sys/dev/audio/audiodef.h Sat Mar 21 15:47:00 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: audiodef.h,v 1.7.2.2 2020/03/21 15:41:18 martin Exp $ */
+/* $NetBSD: audiodef.h,v 1.7.2.3 2020/03/21 15:47:00 martin Exp $ */
/*
* Copyright (C) 2017 Tetsuya Isaki. All rights reserved.
@@ -202,6 +202,9 @@ struct audio_file {
/* process who wants audio SIGIO. */
pid_t async_audio;
+ /* true when closing */
+ bool dying;
+
SLIST_ENTRY(audio_file) entry;
};
Index: src/sys/dev/audio/audiovar.h
diff -u src/sys/dev/audio/audiovar.h:1.4.2.1 src/sys/dev/audio/audiovar.h:1.4.2.2
--- src/sys/dev/audio/audiovar.h:1.4.2.1 Sun Oct 6 11:00:15 2019
+++ src/sys/dev/audio/audiovar.h Sat Mar 21 15:47:01 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: audiovar.h,v 1.4.2.1 2019/10/06 11:00:15 martin Exp $ */
+/* $NetBSD: audiovar.h,v 1.4.2.2 2020/03/21 15:47:01 martin Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -70,6 +70,8 @@
#if defined(_KERNEL)
#include <sys/condvar.h>
#include <sys/proc.h>
+#include <sys/pserialize.h>
+#include <sys/psref.h>
#include <sys/queue.h>
#include <dev/audio/audio_if.h>
@@ -224,6 +226,13 @@ struct audio_softc {
kcondvar_t sc_exlockcv;
/*
+ * Passive reference to prevent a race between detach and fileops.
+ * pserialize_perform(sc_psz) must be protected by sc_lock.
+ */
+ pserialize_t sc_psz;
+ struct psref_target sc_psref;
+
+ /*
* Must be protected by sc_lock (?)
*/
bool sc_dying;