Module Name:    src
Committed By:   martin
Date:           Mon Mar  1 16:00:08 UTC 2021

Modified Files:
        src/sys/dev/audio [netbsd-9]: audio.c

Log Message:
Pull up following revision(s) (requested by isaki in ticket #1219):

        sys/dev/audio/audio.c: revision 1.89
        sys/dev/audio/audio.c: revision 1.90
        sys/dev/audio/audio.c: revision 1.91

Change the lock conditions to call audio_unlink().

This can remove a different copy of audio_exlock_enter() in audio_unlink()
and can use normal one.  Also, in audiodetach(), this can set the exlock
at more natual order (before calling audio_unlink()).

No noticeable functional changes are intended.
Thanks for comments, riastradh@.

Protect also audioopen() and audiobellopen() from audiodetach() with
psref(9), as well as others(audioread, audiowrite, etc..).
- Rename audio_file_enter to audio_sc_acquire_fromfile, audio_file_exit
  to audio_sc_release, for clarify.  These are the reference counter for
  this sc.
- Introduce audio_sc_acquire_foropen for audio{,bell}open.
- audio_open needs to examine sc_dying again before inserting it into
  sc_files, in order to keep sc_files consistency.

The race between audiodetach and audioopen is pointed out by riastradh@.
Thank you for many advices.

Add missing curlwp_bindx() corresponding to curlwp_bind().
Pointed out by riastradh@.


To generate a diff of this commit:
cvs rdiff -u -r1.28.2.20 -r1.28.2.21 src/sys/dev/audio/audio.c

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.20 src/sys/dev/audio/audio.c:1.28.2.21
--- src/sys/dev/audio/audio.c:1.28.2.20	Sun Feb 28 07:07:38 2021
+++ src/sys/dev/audio/audio.c	Mon Mar  1 16:00:08 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: audio.c,v 1.28.2.20 2021/02/28 07:07:38 martin Exp $	*/
+/*	$NetBSD: audio.c,v 1.28.2.21 2021/03/01 16:00:08 martin Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -138,7 +138,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.28.2.20 2021/02/28 07:07:38 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.28.2.21 2021/03/01 16:00:08 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "audio.h"
@@ -524,8 +524,10 @@ static int audio_exlock_mutex_enter(stru
 static void audio_exlock_mutex_exit(struct audio_softc *);
 static int audio_exlock_enter(struct audio_softc *);
 static void audio_exlock_exit(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 void audio_sc_acquire_foropen(struct audio_softc *, struct psref *);
+static struct audio_softc *audio_sc_acquire_fromfile(audio_file_t *,
+	struct psref *);
+static void audio_sc_release(struct audio_softc *, struct psref *);
 static int audio_track_waitio(struct audio_softc *, audio_track_t *);
 
 static int audioclose(struct file *);
@@ -1295,7 +1297,10 @@ audiodetach(device_t self, int flags)
 	if (error)
 		return error;
 
-	/* delete sysctl nodes */
+	/*
+	 * This waits currently running sysctls to finish if exists.
+	 * After this, no more new sysctls will come.
+	 */
 	sysctl_teardown(&sc->sc_log);
 
 	mutex_enter(sc->sc_lock);
@@ -1327,9 +1332,10 @@ audiodetach(device_t self, int flags)
 	 * that hold sc, and any new calls with files that were for sc will
 	 * fail.  Thus, we now have exclusive access to the softc.
 	 */
+	sc->sc_exlock = 1;
 
 	/*
-	 * Nuke all open instances.
+	 * Clean up all open instances.
 	 * Here, we no longer need any locks to traverse sc_files.
 	 */
 	while ((file = SLIST_FIRST(&sc->sc_files)) != NULL) {
@@ -1352,7 +1358,6 @@ audiodetach(device_t self, int flags)
 	pmf_device_deregister(self);
 
 	/* Free resources */
-	sc->sc_exlock = 1;
 	if (sc->sc_pmixer) {
 		audio_mixer_destroy(sc, sc->sc_pmixer);
 		kmem_free(sc->sc_pmixer, sizeof(*sc->sc_pmixer));
@@ -1524,18 +1529,41 @@ audio_exlock_exit(struct audio_softc *sc
 }
 
 /*
- * Acquire sc from file, and increment the psref count.
+ * Increment reference counter for this sc.
+ * This is intended to be used for open.
+ */
+void
+audio_sc_acquire_foropen(struct audio_softc *sc, struct psref *refp)
+{
+	int s;
+
+	/* Block audiodetach while we acquire a reference */
+	s = pserialize_read_enter();
+
+	/*
+	 * We don't examine sc_dying here.  However, all open methods
+	 * call audio_exlock_enter() right after this, so we can examine
+	 * sc_dying in it.
+	 */
+
+	/* Acquire a reference */
+	psref_acquire(refp, &sc->sc_psref, audio_psref_class);
+
+	/* Now sc won't go away until we drop the reference count */
+	pserialize_read_exit(s);
+}
+
+/*
+ * Get sc from file, and increment reference counter for this sc.
+ * This is intended to be used for methods other than open.
  * If successful, returns sc.  Otherwise returns NULL.
  */
 struct audio_softc *
-audio_file_enter(audio_file_t *file, struct psref *refp)
+audio_sc_acquire_fromfile(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();
 
@@ -1556,10 +1584,10 @@ audio_file_enter(audio_file_t *file, str
 }
 
 /*
- * Decrement the psref count.
+ * Decrement reference counter for this sc.
  */
 void
-audio_file_exit(struct audio_softc *sc, struct psref *refp)
+audio_sc_release(struct audio_softc *sc, struct psref *refp)
 {
 
 	psref_release(refp, &sc->sc_psref, audio_psref_class);
@@ -1637,6 +1665,8 @@ static int
 audioopen(dev_t dev, int flags, int ifmt, struct lwp *l)
 {
 	struct audio_softc *sc;
+	struct psref sc_ref;
+	int bound;
 	int error;
 
 	/* Find the device */
@@ -1644,9 +1674,12 @@ audioopen(dev_t dev, int flags, int ifmt
 	if (sc == NULL || sc->hw_if == NULL)
 		return ENXIO;
 
+	bound = curlwp_bind();
+	audio_sc_acquire_foropen(sc, &sc_ref);
+
 	error = audio_exlock_enter(sc);
 	if (error)
-		return error;
+		goto done;
 
 	device_active(sc->sc_dev, DVA_SYSTEM);
 	switch (AUDIODEV(dev)) {
@@ -1666,6 +1699,9 @@ audioopen(dev_t dev, int flags, int ifmt
 	}
 	audio_exlock_exit(sc);
 
+done:
+	audio_sc_release(sc, &sc_ref);
+	curlwp_bindx(bound);
 	return error;
 }
 
@@ -1675,6 +1711,7 @@ audioclose(struct file *fp)
 	struct audio_softc *sc;
 	struct psref sc_ref;
 	audio_file_t *file;
+	int bound;
 	int error;
 	dev_t dev;
 
@@ -1690,7 +1727,8 @@ audioclose(struct file *fp)
 	 * - free all memory objects, regardless of sc.
 	 */
 
-	sc = audio_file_enter(file, &sc_ref);
+	bound = curlwp_bind();
+	sc = audio_sc_acquire_fromfile(file, &sc_ref);
 	if (sc) {
 		switch (AUDIODEV(dev)) {
 		case SOUND_DEVICE:
@@ -1708,8 +1746,9 @@ audioclose(struct file *fp)
 			break;
 		}
 
-		audio_file_exit(sc, &sc_ref);
+		audio_sc_release(sc, &sc_ref);
 	}
+	curlwp_bindx(bound);
 
 	/* Free memory objects anyway */
 	TRACEF(2, file, "free memory");
@@ -1730,6 +1769,7 @@ audioread(struct file *fp, off_t *offp, 
 	struct audio_softc *sc;
 	struct psref sc_ref;
 	audio_file_t *file;
+	int bound;
 	int error;
 	dev_t dev;
 
@@ -1737,9 +1777,12 @@ audioread(struct file *fp, off_t *offp, 
 	file = fp->f_audioctx;
 	dev = file->dev;
 
-	sc = audio_file_enter(file, &sc_ref);
-	if (sc == NULL)
-		return EIO;
+	bound = curlwp_bind();
+	sc = audio_sc_acquire_fromfile(file, &sc_ref);
+	if (sc == NULL) {
+		error = EIO;
+		goto done;
+	}
 
 	if (fp->f_flag & O_NONBLOCK)
 		ioflag |= IO_NDELAY;
@@ -1758,7 +1801,9 @@ audioread(struct file *fp, off_t *offp, 
 		break;
 	}
 
-	audio_file_exit(sc, &sc_ref);
+	audio_sc_release(sc, &sc_ref);
+done:
+	curlwp_bindx(bound);
 	return error;
 }
 
@@ -1769,6 +1814,7 @@ audiowrite(struct file *fp, off_t *offp,
 	struct audio_softc *sc;
 	struct psref sc_ref;
 	audio_file_t *file;
+	int bound;
 	int error;
 	dev_t dev;
 
@@ -1776,9 +1822,12 @@ audiowrite(struct file *fp, off_t *offp,
 	file = fp->f_audioctx;
 	dev = file->dev;
 
-	sc = audio_file_enter(file, &sc_ref);
-	if (sc == NULL)
-		return EIO;
+	bound = curlwp_bind();
+	sc = audio_sc_acquire_fromfile(file, &sc_ref);
+	if (sc == NULL) {
+		error = EIO;
+		goto done;
+	}
 
 	if (fp->f_flag & O_NONBLOCK)
 		ioflag |= IO_NDELAY;
@@ -1797,7 +1846,9 @@ audiowrite(struct file *fp, off_t *offp,
 		break;
 	}
 
-	audio_file_exit(sc, &sc_ref);
+	audio_sc_release(sc, &sc_ref);
+done:
+	curlwp_bindx(bound);
 	return error;
 }
 
@@ -1808,6 +1859,7 @@ audioioctl(struct file *fp, u_long cmd, 
 	struct psref sc_ref;
 	audio_file_t *file;
 	struct lwp *l = curlwp;
+	int bound;
 	int error;
 	dev_t dev;
 
@@ -1815,9 +1867,12 @@ audioioctl(struct file *fp, u_long cmd, 
 	file = fp->f_audioctx;
 	dev = file->dev;
 
-	sc = audio_file_enter(file, &sc_ref);
-	if (sc == NULL)
-		return EIO;
+	bound = curlwp_bind();
+	sc = audio_sc_acquire_fromfile(file, &sc_ref);
+	if (sc == NULL) {
+		error = EIO;
+		goto done;
+	}
 
 	switch (AUDIODEV(dev)) {
 	case SOUND_DEVICE:
@@ -1840,7 +1895,9 @@ audioioctl(struct file *fp, u_long cmd, 
 		break;
 	}
 
-	audio_file_exit(sc, &sc_ref);
+	audio_sc_release(sc, &sc_ref);
+done:
+	curlwp_bindx(bound);
 	return error;
 }
 
@@ -1850,14 +1907,20 @@ audiostat(struct file *fp, struct stat *
 	struct audio_softc *sc;
 	struct psref sc_ref;
 	audio_file_t *file;
+	int bound;
+	int error;
 
 	KASSERT(fp->f_audioctx);
 	file = fp->f_audioctx;
 
-	sc = audio_file_enter(file, &sc_ref);
-	if (sc == NULL)
-		return EIO;
+	bound = curlwp_bind();
+	sc = audio_sc_acquire_fromfile(file, &sc_ref);
+	if (sc == NULL) {
+		error = EIO;
+		goto done;
+	}
 
+	error = 0;
 	memset(st, 0, sizeof(*st));
 
 	st->st_dev = file->dev;
@@ -1865,8 +1928,10 @@ audiostat(struct file *fp, struct stat *
 	st->st_gid = kauth_cred_getegid(fp->f_cred);
 	st->st_mode = S_IFCHR;
 
-	audio_file_exit(sc, &sc_ref);
-	return 0;
+	audio_sc_release(sc, &sc_ref);
+done:
+	curlwp_bindx(bound);
+	return error;
 }
 
 static int
@@ -1876,6 +1941,7 @@ audiopoll(struct file *fp, int events)
 	struct psref sc_ref;
 	audio_file_t *file;
 	struct lwp *l = curlwp;
+	int bound;
 	int revents;
 	dev_t dev;
 
@@ -1883,9 +1949,12 @@ audiopoll(struct file *fp, int events)
 	file = fp->f_audioctx;
 	dev = file->dev;
 
-	sc = audio_file_enter(file, &sc_ref);
-	if (sc == NULL)
-		return POLLERR;
+	bound = curlwp_bind();
+	sc = audio_sc_acquire_fromfile(file, &sc_ref);
+	if (sc == NULL) {
+		revents = POLLERR;
+		goto done;
+	}
 
 	switch (AUDIODEV(dev)) {
 	case SOUND_DEVICE:
@@ -1901,7 +1970,9 @@ audiopoll(struct file *fp, int events)
 		break;
 	}
 
-	audio_file_exit(sc, &sc_ref);
+	audio_sc_release(sc, &sc_ref);
+done:
+	curlwp_bindx(bound);
 	return revents;
 }
 
@@ -1912,15 +1983,19 @@ audiokqfilter(struct file *fp, struct kn
 	struct psref sc_ref;
 	audio_file_t *file;
 	dev_t dev;
+	int bound;
 	int error;
 
 	KASSERT(fp->f_audioctx);
 	file = fp->f_audioctx;
 	dev = file->dev;
 
-	sc = audio_file_enter(file, &sc_ref);
-	if (sc == NULL)
-		return EIO;
+	bound = curlwp_bind();
+	sc = audio_sc_acquire_fromfile(file, &sc_ref);
+	if (sc == NULL) {
+		error = EIO;
+		goto done;
+	}
 
 	switch (AUDIODEV(dev)) {
 	case SOUND_DEVICE:
@@ -1936,7 +2011,9 @@ audiokqfilter(struct file *fp, struct kn
 		break;
 	}
 
-	audio_file_exit(sc, &sc_ref);
+	audio_sc_release(sc, &sc_ref);
+done:
+	curlwp_bindx(bound);
 	return error;
 }
 
@@ -1948,15 +2025,19 @@ audiommap(struct file *fp, off_t *offp, 
 	struct psref sc_ref;
 	audio_file_t *file;
 	dev_t dev;
+	int bound;
 	int error;
 
 	KASSERT(fp->f_audioctx);
 	file = fp->f_audioctx;
 	dev = file->dev;
 
-	sc = audio_file_enter(file, &sc_ref);
-	if (sc == NULL)
-		return EIO;
+	bound = curlwp_bind();
+	sc = audio_sc_acquire_fromfile(file, &sc_ref);
+	if (sc == NULL) {
+		error = EIO;
+		goto done;
+	}
 
 	mutex_enter(sc->sc_lock);
 	device_active(sc->sc_dev, DVA_SYSTEM); /* XXXJDM */
@@ -1975,7 +2056,9 @@ audiommap(struct file *fp, off_t *offp, 
 		break;
 	}
 
-	audio_file_exit(sc, &sc_ref);
+	audio_sc_release(sc, &sc_ref);
+done:
+	curlwp_bindx(bound);
 	return error;
 }
 
@@ -1991,6 +2074,8 @@ int
 audiobellopen(dev_t dev, audio_file_t **filep)
 {
 	struct audio_softc *sc;
+	struct psref sc_ref;
+	int bound;
 	int error;
 
 	/* Find the device */
@@ -1998,14 +2083,20 @@ audiobellopen(dev_t dev, audio_file_t **
 	if (sc == NULL || sc->hw_if == NULL)
 		return ENXIO;
 
+	bound = curlwp_bind();
+	audio_sc_acquire_foropen(sc, &sc_ref);
+
 	error = audio_exlock_enter(sc);
 	if (error)
-		return error;
+		goto done;
 
 	device_active(sc->sc_dev, DVA_SYSTEM);
 	error = audio_open(dev, sc, FWRITE, 0, curlwp, filep);
 
 	audio_exlock_exit(sc);
+done:
+	audio_sc_release(sc, &sc_ref);
+	curlwp_bindx(bound);
 	return error;
 }
 
@@ -2015,16 +2106,24 @@ audiobellclose(audio_file_t *file)
 {
 	struct audio_softc *sc;
 	struct psref sc_ref;
+	int bound;
 	int error;
 
-	sc = audio_file_enter(file, &sc_ref);
-	if (sc == NULL)
-		return EIO;
-
-	error = audio_close(sc, file);
-
-	audio_file_exit(sc, &sc_ref);
+	error = 0;
+	/*
+	 * audiobellclose() must
+	 * - unplug track from the trackmixer if sc exist.
+	 * - free all memory objects, regardless of sc.
+	 */
+	bound = curlwp_bind();
+	sc = audio_sc_acquire_fromfile(file, &sc_ref);
+	if (sc) {
+		error = audio_close(sc, file);
+		audio_sc_release(sc, &sc_ref);
+	}
+	curlwp_bindx(bound);
 
+	/* Free memory objects anyway */
 	KASSERT(file->ptrack);
 	audio_track_destroy(file->ptrack);
 	KASSERT(file->rtrack == NULL);
@@ -2039,23 +2138,29 @@ audiobellsetrate(audio_file_t *file, u_i
 	struct audio_softc *sc;
 	struct psref sc_ref;
 	struct audio_info ai;
+	int bound;
 	int error;
 
-	sc = audio_file_enter(file, &sc_ref);
-	if (sc == NULL)
-		return EIO;
+	bound = curlwp_bind();
+	sc = audio_sc_acquire_fromfile(file, &sc_ref);
+	if (sc == NULL) {
+		error = EIO;
+		goto done1;
+	}
 
 	AUDIO_INITINFO(&ai);
 	ai.play.sample_rate = sample_rate;
 
 	error = audio_exlock_enter(sc);
 	if (error)
-		goto done;
+		goto done2;
 	error = audio_file_setinfo(sc, file, &ai);
 	audio_exlock_exit(sc);
 
-done:
-	audio_file_exit(sc, &sc_ref);
+done2:
+	audio_sc_release(sc, &sc_ref);
+done1:
+	curlwp_bindx(bound);
 	return error;
 }
 
@@ -2065,15 +2170,21 @@ audiobellwrite(audio_file_t *file, struc
 {
 	struct audio_softc *sc;
 	struct psref sc_ref;
+	int bound;
 	int error;
 
-	sc = audio_file_enter(file, &sc_ref);
-	if (sc == NULL)
-		return EIO;
+	bound = curlwp_bind();
+	sc = audio_sc_acquire_fromfile(file, &sc_ref);
+	if (sc == NULL) {
+		error = EIO;
+		goto done;
+	}
 
 	error = audio_write(sc, uio, 0, file);
 
-	audio_file_exit(sc, &sc_ref);
+	audio_sc_release(sc, &sc_ref);
+done:
+	curlwp_bindx(bound);
 	return error;
 }
 
@@ -2097,6 +2208,7 @@ audio_open(dev_t dev, struct audio_softc
 	bool cred_held;
 	bool hw_opened;
 	bool rmixer_started;
+	bool inserted;
 	int fd;
 	int error;
 
@@ -2111,6 +2223,7 @@ audio_open(dev_t dev, struct audio_softc
 	cred_held = false;
 	hw_opened = false;
 	rmixer_started = false;
+	inserted = false;
 
 	af = kmem_zalloc(sizeof(audio_file_t), KM_SLEEP);
 	af->sc = sc;
@@ -2314,22 +2427,22 @@ audio_open(dev_t dev, struct audio_softc
 		rmixer_started = true;
 	}
 
-	if (bellfile) {
-		*bellfile = af;
-	} else {
-		error = fd_allocfile(&fp, &fd);
-		if (error)
-			goto bad;
-
-		error = fd_clone(fp, fd, flags, &audio_fileops, af);
-		KASSERTMSG(error == EMOVEFD, "error=%d", error);
-	}
-
 	/*
-	 * Count up finally.
-	 * Don't fail from here.
+	 * This is the last sc_lock section in the function, so we have to
+	 * examine sc_dying again before starting the rest tasks.  Because
+	 * audiodeatch() may have been invoked (and it would set sc_dying)
+	 * from the time audioopen() was executed until now.  If it happens,
+	 * audiodetach() may already have set file->dying for all sc_files
+	 * that exist at that point, so that audioopen() must abort without
+	 * inserting af to sc_files, in order to keep consistency.
 	 */
 	mutex_enter(sc->sc_lock);
+	if (sc->sc_dying) {
+		mutex_exit(sc->sc_lock);
+		goto bad;
+	}
+
+	/* Count up finally */
 	if (af->ptrack)
 		sc->sc_popens++;
 	if (af->rtrack)
@@ -2338,13 +2451,35 @@ audio_open(dev_t dev, struct audio_softc
 	SLIST_INSERT_HEAD(&sc->sc_files, af, entry);
 	mutex_exit(sc->sc_intr_lock);
 	mutex_exit(sc->sc_lock);
+	inserted = true;
+
+	if (bellfile) {
+		*bellfile = af;
+	} else {
+		error = fd_allocfile(&fp, &fd);
+		if (error)
+			goto bad;
+
+		error = fd_clone(fp, fd, flags, &audio_fileops, af);
+		KASSERTMSG(error == EMOVEFD, "error=%d", error);
+	}
+
+	/* Be nothing else after fd_clone */
 
 	TRACEF(3, af, "done");
 	return error;
 
 bad:
-	if (fp) {
-		fd_abort(curproc, fp, fd);
+	if (inserted) {
+		mutex_enter(sc->sc_lock);
+		mutex_enter(sc->sc_intr_lock);
+		SLIST_REMOVE(&sc->sc_files, af, audio_file, entry);
+		mutex_exit(sc->sc_intr_lock);
+		if (af->ptrack)
+			sc->sc_popens--;
+		if (af->rtrack)
+			sc->sc_ropens--;
+		mutex_exit(sc->sc_lock);
 	}
 
 	if (rmixer_started) {
@@ -2389,6 +2524,7 @@ bad:
 int
 audio_close(struct audio_softc *sc, audio_file_t *file)
 {
+	int error;
 
 	/* Protect entering new fileops to this file */
 	atomic_store_relaxed(&file->dying, true);
@@ -2403,12 +2539,27 @@ audio_close(struct audio_softc *sc, audi
 		mutex_exit(sc->sc_lock);
 	}
 
-	return audio_unlink(sc, file);
+	error = audio_exlock_enter(sc);
+	if (error) {
+		/*
+		 * If EIO, this sc is about to detach.  In this case, even if
+		 * we don't do subsequent _unlink(), audiodetach() will do it.
+		 */
+		if (error == EIO)
+			return error;
+
+		/* XXX This should not happen but what should I do ? */
+		panic("%s: can't acquire exlock: errno=%d", __func__, error);
+	}
+	error = audio_unlink(sc, file);
+	audio_exlock_exit(sc);
+
+	return error;
 }
 
 /*
  * Unlink this file, but not freeing memory here.
- * Must be called without sc_lock nor sc_exlock held.
+ * Must be called with sc_exlock held and without sc_lock held.
  */
 int
 audio_unlink(struct audio_softc *sc, audio_file_t *file)
@@ -2425,25 +2576,6 @@ audio_unlink(struct audio_softc *sc, aud
 	    "sc->sc_popens=%d, sc->sc_ropens=%d",
 	    sc->sc_popens, sc->sc_ropens);
 
-	/*
-	 * Acquire exlock to protect counters.
-	 * audio_exlock_enter() cannot be used here because we have to go
-	 * forward even if sc_dying is set.
-	 */
-	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);
-			audio_printf(sc,
-			    "%s: cv_timedwait_sig failed: errno=%d\n",
-			    __func__, error);
-			return error;
-		}
-	}
-	sc->sc_exlock = 1;
-
 	device_active(sc->sc_dev, DVA_SYSTEM);
 
 	mutex_enter(sc->sc_intr_lock);
@@ -2510,7 +2642,6 @@ audio_unlink(struct audio_softc *sc, aud
 		kauth_cred_free(sc->sc_cred);
 
 	TRACE(3, "done");
-	audio_exlock_exit(sc);
 
 	return 0;
 }

Reply via email to