Module Name: src Committed By: nat Date: Tue Jan 9 04:23:59 UTC 2018
Modified Files: src/sys/dev/pad: pad.c Log Message: Fix pad on systems with many cores/cpus: * Introduce a lock to serialize attach/detach of pad devices. * Forcefully detach children of pad on close. * Be more carefull in pad_open with regards to config_detach only if new instances of the pad device are created and fail to open. Addresses PR kern/52889. These changes were developed with and tested by pgoyette@. To generate a diff of this commit: cvs rdiff -u -r1.49 -r1.50 src/sys/dev/pad/pad.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/pad/pad.c diff -u src/sys/dev/pad/pad.c:1.49 src/sys/dev/pad/pad.c:1.50 --- src/sys/dev/pad/pad.c:1.49 Sun Dec 17 21:57:11 2017 +++ src/sys/dev/pad/pad.c Tue Jan 9 04:23:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: pad.c,v 1.49 2017/12/17 21:57:11 pgoyette Exp $ */ +/* $NetBSD: pad.c,v 1.50 2018/01/09 04:23:59 nat Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.49 2017/12/17 21:57:11 pgoyette Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.50 2018/01/09 04:23:59 nat Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -67,6 +67,7 @@ __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.49 #define PADENC AUDIO_ENCODING_SLINEAR_LE extern struct cfdriver pad_cd; +kmutex_t padconfig; typedef struct pad_block { uint8_t *pb_ptr; @@ -200,6 +201,7 @@ padattach(int n) config_cfdriver_detach(&pad_cd); return; } + mutex_init(&padconfig, MUTEX_DEFAULT, IPL_NONE); return; } @@ -286,34 +288,13 @@ static int pad_detach(device_t self, int flags) { pad_softc_t *sc; - int cmaj, mn, rc; + int cmaj, mn; sc = device_private(self); - config_deactivate(sc->sc_audiodev); - - /* Start draining existing accessors of the device. */ - if ((rc = config_detach_children(self, flags)) != 0) - return rc; - - mutex_enter(&sc->sc_lock); - sc->sc_dying = true; - cv_broadcast(&sc->sc_condvar); - mutex_exit(&sc->sc_lock); - - KASSERT(sc->sc_open > 0); - sc->sc_open = 0; - cmaj = cdevsw_lookup_major(&pad_cdevsw); mn = device_unit(sc->sc_dev); - vdevgone(cmaj, mn, mn, VCHR); - - pmf_device_deregister(sc->sc_dev); - - mutex_destroy(&sc->sc_lock); - mutex_destroy(&sc->sc_intr_lock); - cv_destroy(&sc->sc_condvar); - - auconv_delete_encodings(sc->sc_encodings); + if (!sc->sc_dying) + vdevgone(cmaj, mn, mn, VCHR); return 0; } @@ -327,16 +308,17 @@ pad_open(dev_t dev, int flags, int fmt, cfdata_t cf; int error, fd, i; + mutex_enter(&padconfig); if (PADUNIT(dev) == PADCLONER) { for (i = 0; i < MAXDEVS; i++) { if (device_lookup(&pad_cd, i) == NULL) break; } if (i == MAXDEVS) - return ENXIO; + goto bad; } else { if (PADUNIT(dev) >= MAXDEVS) - return ENXIO; + goto bad; i = PADUNIT(dev); } @@ -346,18 +328,23 @@ pad_open(dev_t dev, int flags, int fmt, cf->cf_unit = i; cf->cf_fstate = FSTATE_STAR; + bool existing = false; paddev = device_lookup(&pad_cd, minor(dev)); if (paddev == NULL) paddev = config_attach_pseudo(cf); + else + existing = true; if (paddev == NULL) - return ENXIO; + goto bad; sc = device_private(paddev); if (sc == NULL) - return ENXIO; + goto bad; - if (sc->sc_open == 1) + if (sc->sc_open == 1) { + mutex_exit(&padconfig); return EBUSY; + } sc->sc_dev = paddev; sc->sc_dying = false; @@ -365,7 +352,9 @@ pad_open(dev_t dev, int flags, int fmt, if (PADUNIT(dev) == PADCLONER) { error = fd_allocfile(&fp, &fd); if (error) { - config_detach(sc->sc_dev, 0); + if (existing == false) + config_detach(sc->sc_dev, 0); + mutex_exit(&padconfig); return error; } } @@ -373,7 +362,9 @@ pad_open(dev_t dev, int flags, int fmt, if (auconv_create_encodings(pad_formats, PAD_NFORMATS, &sc->sc_encodings) != 0) { aprint_error_dev(sc->sc_dev, "couldn't create encodings\n"); - config_detach(sc->sc_dev, 0); + if (existing == false) + config_detach(sc->sc_dev, 0); + mutex_exit(&padconfig); return EINVAL; } @@ -394,17 +385,52 @@ pad_open(dev_t dev, int flags, int fmt, KASSERT(error == EMOVEFD); } sc->sc_open = 1; + mutex_exit(&padconfig); return error; +bad: + mutex_exit(&padconfig); + return ENXIO; } static int pad_close(struct pad_softc *sc) { + int rc; + if (sc == NULL) return ENXIO; - return config_detach(sc->sc_dev, DETACH_FORCE); + mutex_enter(&padconfig); + config_deactivate(sc->sc_audiodev); + + /* Start draining existing accessors of the device. */ + if ((rc = config_detach_children(sc->sc_dev, + DETACH_SHUTDOWN|DETACH_FORCE)) != 0) { + mutex_exit(&padconfig); + return rc; + } + + mutex_enter(&sc->sc_lock); + sc->sc_dying = true; + cv_broadcast(&sc->sc_condvar); + mutex_exit(&sc->sc_lock); + + KASSERT(sc->sc_open > 0); + sc->sc_open = 0; + + pmf_device_deregister(sc->sc_dev); + + mutex_destroy(&sc->sc_lock); + mutex_destroy(&sc->sc_intr_lock); + cv_destroy(&sc->sc_condvar); + + auconv_delete_encodings(sc->sc_encodings); + + rc = config_detach(sc->sc_dev, 0); + mutex_exit(&padconfig); + + return rc; } static int @@ -942,6 +968,7 @@ pad_modcmd(modcmd_t cmd, void *arg) pad_cfattach, cfdata_ioconf_pad); break; } + mutex_init(&padconfig, MUTEX_DEFAULT, IPL_NONE); #endif break; @@ -959,6 +986,7 @@ pad_modcmd(modcmd_t cmd, void *arg) &pad_cdevsw, &cmajor); break; } + mutex_destroy(&padconfig); #endif break;