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 <[email protected]>
@@ -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;