Module Name: src Committed By: riastradh Date: Mon Mar 28 12:39:57 UTC 2022
Modified Files: src/sys/dev/audio: audio.c Log Message: audio(4): Use d_cfdriver/devtounit to avoid open/detach races. To generate a diff of this commit: cvs rdiff -u -r1.120 -r1.121 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.120 src/sys/dev/audio/audio.c:1.121 --- src/sys/dev/audio/audio.c:1.120 Sat Mar 26 06:49:27 2022 +++ src/sys/dev/audio/audio.c Mon Mar 28 12:39:57 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: audio.c,v 1.120 2022/03/26 06:49:27 isaki Exp $ */ +/* $NetBSD: audio.c,v 1.121 2022/03/28 12:39:57 riastradh Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -181,7 +181,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.120 2022/03/26 06:49:27 isaki Exp $"); +__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.121 2022/03/28 12:39:57 riastradh Exp $"); #ifdef _KERNEL_OPT #include "audio.h" @@ -567,7 +567,6 @@ 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 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 *); @@ -766,6 +765,13 @@ audio_volume_to_outer(u_int v) static dev_type_open(audioopen); /* XXXMRG use more dev_type_xxx */ +static int +audiounit(dev_t dev) +{ + + return AUDIOUNIT(dev); +} + const struct cdevsw audio_cdevsw = { .d_open = audioopen, .d_close = noclose, @@ -778,6 +784,8 @@ const struct cdevsw audio_cdevsw = { .d_mmap = nommap, .d_kqfilter = nokqfilter, .d_discard = nodiscard, + .d_cfdriver = &audio_cd, + .d_devtounit = audiounit, .d_flag = D_OTHER | D_MPSAFE }; @@ -1590,31 +1598,6 @@ audio_exlock_exit(struct audio_softc *sc } /* - * 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. @@ -1732,21 +1715,20 @@ 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 */ + /* + * Find the device. Because we wired the cdevsw to the audio + * autoconf instance, the system ensures it will not go away + * until after we return. + */ sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev)); 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) - goto done; + return error; device_active(sc->sc_dev, DVA_SYSTEM); switch (AUDIODEV(dev)) { @@ -1766,9 +1748,6 @@ audioopen(dev_t dev, int flags, int ifmt } audio_exlock_exit(sc); -done: - audio_sc_release(sc, &sc_ref); - curlwp_bindx(bound); return error; } @@ -2150,30 +2129,42 @@ done: int audiobellopen(dev_t dev, audio_file_t **filep) { + device_t audiodev = NULL; struct audio_softc *sc; - struct psref sc_ref; - int bound; + bool exlock = false; int error; - /* Find the device */ - sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev)); - if (sc == NULL || sc->hw_if == NULL) - return ENXIO; + /* + * Find the autoconf instance and make sure it doesn't go away + * while we are opening it. + */ + audiodev = device_lookup_acquire(&audio_cd, AUDIOUNIT(dev)); + if (audiodev == NULL) { + error = ENXIO; + goto out; + } - bound = curlwp_bind(); - audio_sc_acquire_foropen(sc, &sc_ref); + /* If attach failed, it's hopeless -- give up. */ + sc = device_private(audiodev); + if (sc->hw_if == NULL) { + error = ENXIO; + goto out; + } + /* Take the exclusive configuration lock. */ error = audio_exlock_enter(sc); if (error) - goto done; + goto out; + exlock = true; + /* Open the audio device. */ 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); +out: if (exlock) + audio_exlock_exit(sc); + if (audiodev) + device_release(audiodev); return error; }