The following patch makes audio(4) event filters MP-safe.

The knote lists are already serialized by audio_lock. By adding klist
init calls, the lock becomes visible to the lock assertion in knote().

The new f_modify and f_process callbacks cover the knote handling
with audio_lock. This also makes the NOTE_SUBMIT conditions unnecessary
in the f_event functions.

The patch does not change the use of selwakeup(). Replacing selwakeup()
with KNOTE() is a separate step.

OK?

Index: dev/audio.c
===================================================================
RCS file: src/sys/dev/audio.c,v
retrieving revision 1.196
diff -u -p -r1.196 audio.c
--- dev/audio.c 16 Feb 2022 06:23:42 -0000      1.196
+++ dev/audio.c 16 Feb 2022 15:28:18 -0000
@@ -170,32 +170,40 @@ struct cfdriver audio_cd = {
 
 void filt_audioctlrdetach(struct knote *);
 int filt_audioctlread(struct knote *, long);
+int filt_audiomodify(struct kevent *, struct knote *);
+int filt_audioprocess(struct knote *, struct kevent *);
 
 const struct filterops audioctlread_filtops = {
-       .f_flags        = FILTEROP_ISFD,
+       .f_flags        = FILTEROP_ISFD | FILTEROP_MPSAFE,
        .f_attach       = NULL,
        .f_detach       = filt_audioctlrdetach,
        .f_event        = filt_audioctlread,
+       .f_modify       = filt_audiomodify,
+       .f_process      = filt_audioprocess,
 };
 
 void filt_audiowdetach(struct knote *);
 int filt_audiowrite(struct knote *, long);
 
 const struct filterops audiowrite_filtops = {
-       .f_flags        = FILTEROP_ISFD,
+       .f_flags        = FILTEROP_ISFD | FILTEROP_MPSAFE,
        .f_attach       = NULL,
        .f_detach       = filt_audiowdetach,
        .f_event        = filt_audiowrite,
+       .f_modify       = filt_audiomodify,
+       .f_process      = filt_audioprocess,
 };
 
 void filt_audiordetach(struct knote *);
 int filt_audioread(struct knote *, long);
 
 const struct filterops audioread_filtops = {
-       .f_flags        = FILTEROP_ISFD,
+       .f_flags        = FILTEROP_ISFD | FILTEROP_MPSAFE,
        .f_attach       = NULL,
        .f_detach       = filt_audiordetach,
        .f_event        = filt_audioread,
+       .f_modify       = filt_audiomodify,
+       .f_process      = filt_audioprocess,
 };
 
 /*
@@ -308,11 +316,12 @@ audio_buf_wakeup(void *addr)
 int
 audio_buf_init(struct audio_softc *sc, struct audio_buf *buf, int dir)
 {
+       klist_init_mutex(&buf->sel.si_note, &audio_lock);
        buf->softintr = softintr_establish(IPL_SOFTAUDIO,
            audio_buf_wakeup, buf);
        if (buf->softintr == NULL) {
                printf("%s: can't establish softintr\n", DEVNAME(sc));
-               return ENOMEM;
+               goto bad;
        }
        if (sc->ops->round_buffersize) {
                buf->datalen = sc->ops->round_buffersize(sc->arg,
@@ -326,9 +335,12 @@ audio_buf_init(struct audio_softc *sc, s
                buf->data = malloc(buf->datalen, M_DEVBUF, M_WAITOK);
        if (buf->data == NULL) {
                softintr_disestablish(buf->softintr);
-               return ENOMEM;
+               goto bad;
        }
        return 0;
+bad:
+       klist_free(&buf->sel.si_note);
+       return ENOMEM;
 }
 
 void
@@ -339,6 +351,7 @@ audio_buf_done(struct audio_softc *sc, s
        else
                free(buf->data, M_DEVBUF, buf->datalen);
        softintr_disestablish(buf->softintr);
+       klist_free(&buf->sel.si_note);
 }
 
 /*
@@ -1260,9 +1273,11 @@ audio_attach(struct device *parent, stru
                return;
        }
 
+       klist_init_mutex(&sc->mix_sel.si_note, &audio_lock);
        sc->mix_softintr = softintr_establish(IPL_SOFTAUDIO,
            audio_mixer_wakeup, sc);
        if (sc->mix_softintr == NULL) {
+               klist_free(&sc->mix_sel.si_note);
                audio_buf_done(sc, &sc->rec);
                audio_buf_done(sc, &sc->play);
                sc->ops = 0;
@@ -1455,6 +1470,7 @@ audio_detach(struct device *self, int fl
 
        /* free resources */
        softintr_disestablish(sc->mix_softintr);
+       klist_free(&sc->mix_sel.si_note);
        free(sc->mix_evbuf, M_DEVBUF, sc->mix_nent * sizeof(struct mixer_ev));
        free(sc->mix_ents, M_DEVBUF, sc->mix_nent * sizeof(struct mixer_ctrl));
        audio_buf_done(sc, &sc->play);
@@ -2298,9 +2314,7 @@ audiokqfilter(dev_t dev, struct knote *k
        }
        kn->kn_hook = sc;
 
-       mtx_enter(&audio_lock);
-       klist_insert_locked(klist, kn);
-       mtx_leave(&audio_lock);
+       klist_insert(klist, kn);
 done:
        device_unref(&sc->dev);
        return error;
@@ -2311,24 +2325,17 @@ filt_audiordetach(struct knote *kn)
 {
        struct audio_softc *sc = kn->kn_hook;
 
-       mtx_enter(&audio_lock);
-       klist_remove_locked(&sc->rec.sel.si_note, kn);
-       mtx_leave(&audio_lock);
+       klist_remove(&sc->rec.sel.si_note, kn);
 }
 
 int
 filt_audioread(struct knote *kn, long hint)
 {
        struct audio_softc *sc = kn->kn_hook;
-       int retval = 0;
 
-       if ((hint & NOTE_SUBMIT) == 0)
-               mtx_enter(&audio_lock);
-       retval = (sc->mode & AUMODE_RECORD) && (sc->rec.used > 0);
-       if ((hint & NOTE_SUBMIT) == 0)
-               mtx_leave(&audio_lock);
+       MUTEX_ASSERT_LOCKED(&audio_lock);
 
-       return retval;
+       return (sc->mode & AUMODE_RECORD) && (sc->rec.used > 0);
 }
 
 void
@@ -2336,24 +2343,17 @@ filt_audiowdetach(struct knote *kn)
 {
        struct audio_softc *sc = kn->kn_hook;
 
-       mtx_enter(&audio_lock);
-       klist_remove_locked(&sc->play.sel.si_note, kn);
-       mtx_leave(&audio_lock);
+       klist_remove(&sc->play.sel.si_note, kn);
 }
 
 int
 filt_audiowrite(struct knote *kn, long hint)
 {
        struct audio_softc *sc = kn->kn_hook;
-       int retval = 0;
 
-       if ((hint & NOTE_SUBMIT) == 0)
-               mtx_enter(&audio_lock);
-       retval = (sc->mode & AUMODE_PLAY) && (sc->play.used < sc->play.len);
-       if ((hint & NOTE_SUBMIT) == 0)
-               mtx_leave(&audio_lock);
+       MUTEX_ASSERT_LOCKED(&audio_lock);
 
-       return retval;
+       return (sc->mode & AUMODE_PLAY) && (sc->play.used < sc->play.len);
 }
 
 void
@@ -2361,24 +2361,41 @@ filt_audioctlrdetach(struct knote *kn)
 {
        struct audio_softc *sc = kn->kn_hook;
 
-       mtx_enter(&audio_lock);
-       klist_remove_locked(&sc->mix_sel.si_note, kn);
-       mtx_leave(&audio_lock);
+       klist_remove(&sc->mix_sel.si_note, kn);
 }
 
 int
 filt_audioctlread(struct knote *kn, long hint)
 {
        struct audio_softc *sc = kn->kn_hook;
-       int retval = 0;
 
-       if ((hint & NOTE_SUBMIT) == 0)
-               mtx_enter(&audio_lock);
-       retval = (sc->mix_isopen && sc->mix_pending);
-       if ((hint & NOTE_SUBMIT) == 0)
-               mtx_leave(&audio_lock);
+       MUTEX_ASSERT_LOCKED(&audio_lock);
+
+       return (sc->mix_isopen && sc->mix_pending);
+}
+
+int
+filt_audiomodify(struct kevent *kev, struct knote *kn)
+{
+       int active;
+
+       mtx_enter(&audio_lock);
+       active = knote_modify(kev, kn);
+       mtx_leave(&audio_lock);
+
+       return active;
+}
+
+int
+filt_audioprocess(struct knote *kn, struct kevent *kev)
+{
+       int active;
+
+       mtx_enter(&audio_lock);
+       active = knote_process(kn, kev);
+       mtx_leave(&audio_lock);
 
-       return retval;
+       return active;
 }
 
 #if NWSKBD > 0

Reply via email to