Module Name:    src
Committed By:   riastradh
Date:           Mon Jun 14 00:21:09 UTC 2021

Modified Files:
        src/sys/dev/pad: pad.c

Log Message:
pad(4): Some incomplete tidying.

- Put pseudo-device softc setup/teardown back in pad_attach/detach,
  not in the cdev/fops operations which are about file descriptors.
- Remove unnecessary sc_dying flag.
- Omit needless config_deactivate(sc->sc_audiodev); the only effect
  of this is already done by config_detach anyway, which is done in
  the same context.
- Issue config_detach_children and free softc stuff in the right
  order.
- Omit needless `if (sc == NULL) return ENXIO'.

Survives eight parallel t_mixerctl tests many times over on an
8-thread/4-core machine.

XXX TODO:
- Remove padconfig; it is not appropriate to hold a mutex over
  sleeping allocation or autoconf config_attach operations.  This
  should be done another way.
- Fix agreement of sc_condvar with locks: is it sc_cond_lock or
  sc_intr_lock?  Can't be both; unclear why both exist.
- Determine whether both cdev and fops are really needed -- it is
  confusing to have two types of paths into all this logic, and it
  seems to me only one of them should be necessary.


To generate a diff of this commit:
cvs rdiff -u -r1.67 -r1.68 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.67 src/sys/dev/pad/pad.c:1.68
--- src/sys/dev/pad/pad.c:1.67	Sun Jun 13 23:09:22 2021
+++ src/sys/dev/pad/pad.c	Mon Jun 14 00:21:09 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: pad.c,v 1.67 2021/06/13 23:09:22 riastradh Exp $ */
+/* $NetBSD: pad.c,v 1.68 2021/06/14 00:21:09 riastradh 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.67 2021/06/13 23:09:22 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.68 2021/06/14 00:21:09 riastradh Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -218,21 +218,50 @@ pad_match(device_t parent, cfdata_t data
 static void
 pad_attach(device_t parent, device_t self, void *opaque)
 {
+	struct pad_softc *sc = device_private(self);
 
 	aprint_normal_dev(self, "outputs: 44100Hz, 16-bit, stereo\n");
+
+	sc->sc_dev = self;
+	sc->sc_dying = false;
+
+	cv_init(&sc->sc_condvar, device_xname(sc->sc_dev));
+	mutex_init(&sc->sc_cond_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
+	callout_init(&sc->sc_pcallout, 0/*XXX?*/);
+
+	sc->sc_swvol = 255;
+	sc->sc_buflen = 0;
+	sc->sc_rpos = sc->sc_wpos = 0;
+	sc->sc_audiodev = audio_attach_mi(&pad_hw_if, sc, sc->sc_dev);
+
+	if (!pmf_device_register(sc->sc_dev, NULL, NULL))
+		aprint_error_dev(sc->sc_dev,
+		    "couldn't establish power handler\n");
 }
 
 static int
 pad_detach(device_t self, int flags)
 {
-	struct pad_softc *sc;
+	struct pad_softc *sc = device_private(self);
 	int cmaj, mn;
+	int error;
+
+	error = config_detach_children(self, flags);
+	if (error)
+		return error;
 
-	sc = device_private(self);
 	cmaj = cdevsw_lookup_major(&pad_cdevsw);
 	mn = device_unit(sc->sc_dev);
-	if (!sc->sc_dying)
-		vdevgone(cmaj, mn, mn, VCHR);
+	vdevgone(cmaj, mn, mn, VCHR);
+
+	pmf_device_deregister(sc->sc_dev);
+
+	mutex_destroy(&sc->sc_cond_lock);
+	mutex_destroy(&sc->sc_lock);
+	mutex_destroy(&sc->sc_intr_lock);
+	cv_destroy(&sc->sc_condvar);
 
 	return 0;
 }
@@ -242,7 +271,8 @@ pad_childdet(device_t self, device_t chi
 {
 	struct pad_softc *sc = device_private(self);
 
-	sc->sc_audiodev = NULL;
+	if (child == sc->sc_audiodev)
+		sc->sc_audiodev = NULL;
 }
 
 static int
@@ -340,40 +370,17 @@ cdev_pad_open(dev_t dev, int flags, int 
 		return EBUSY;
 	}
 
-	sc->sc_dev = paddev;
-	sc->sc_dying = false;
-
 	if (PADUNIT(dev) == PADCLONER) {
 		error = fd_allocfile(&fp, &fd);
 		if (error) {
 			if (existing == false)
-				config_detach(sc->sc_dev, 0);
+				config_detach(paddev, 0);
 			mutex_exit(&padconfig);
 			return error;
 		}
-	}
-
-	cv_init(&sc->sc_condvar, device_xname(sc->sc_dev));
-	mutex_init(&sc->sc_cond_lock, MUTEX_DEFAULT, IPL_NONE);
-	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
-	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
-	callout_init(&sc->sc_pcallout, 0/*XXX?*/);
-
-	sc->sc_swvol = 255;
-	sc->sc_buflen = 0;
-	sc->sc_rpos = sc->sc_wpos = 0;
-	KERNEL_LOCK(1, NULL);
-	sc->sc_audiodev = audio_attach_mi(&pad_hw_if, sc, sc->sc_dev);
-	KERNEL_UNLOCK_ONE(NULL);
-
-	if (!pmf_device_register(sc->sc_dev, NULL, NULL))
-		aprint_error_dev(sc->sc_dev,
-		    "couldn't establish power handler\n");
-
-	if (PADUNIT(dev) == PADCLONER) {
 		error = fd_clone(fp, fd, flags, &pad_fileops, sc);
 		KASSERT(error == EMOVEFD);
-	}	
+	}
 	sc->sc_open = 1;
 	mutex_exit(&padconfig);
 
@@ -386,65 +393,42 @@ bad:
 static int
 pad_close(struct pad_softc *sc)
 {
-	int rc;
-
-	if (sc == NULL)
-		return ENXIO;
-
-	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_cond_lock);
-	mutex_destroy(&sc->sc_lock);
-	mutex_destroy(&sc->sc_intr_lock);
-	cv_destroy(&sc->sc_condvar);
+	int rc __diagused;
 
-	rc = config_detach(sc->sc_dev, 0);
-	mutex_exit(&padconfig);
+	/* XXX Defend against concurrent drvctl detach.  */
+	rc = config_detach(sc->sc_dev, DETACH_FORCE);
+	KASSERT(rc == 0);
 
-	return rc;
+	return 0;
 }
 
 static int
 fops_pad_close(struct file *fp)
 {
-	struct pad_softc *sc;
-	int error;
-
-	sc = fp->f_pad;
+	struct pad_softc *sc = fp->f_pad;
 
-	error = pad_close(sc);
+	pad_close(sc);
+	fp->f_pad = NULL;
 
-	if (error == 0)
-		fp->f_pad = NULL;
-
-	return error;
+	return 0;
 }
 
 int
 cdev_pad_close(dev_t dev, int flags, int ifmt, struct lwp *l)
 {
 	struct pad_softc *sc;
-	sc = device_private(device_lookup(&pad_cd, PADUNIT(dev)));
 
-	return pad_close(sc);
+	/*
+	 * XXX Defend against concurrent drvctl detach.  Simply testing
+	 * sc == NULL here is not enough -- it could be detached after
+	 * we look it up but before we've issued our own config_detach.
+	 */
+	sc = device_lookup_private(&pad_cd, PADUNIT(dev));
+	if (sc == NULL)
+		return 0;
+	pad_close(sc);
+
+	return 0;
 }
 
 static int
@@ -457,12 +441,8 @@ fops_pad_poll(struct file *fp, int event
 static int
 fops_pad_kqfilter(struct file *fp, struct knote *kn)
 {
-	struct pad_softc *sc;
+	struct pad_softc *sc = fp->f_pad;
 	dev_t dev;
-	
-	sc = fp->f_pad;
-	if (sc == NULL)
-		return EIO;
 
 	dev = makedev(cdevsw_lookup_major(&pad_cdevsw),
 	    device_unit(sc->sc_dev));
@@ -480,11 +460,7 @@ fops_pad_ioctl(struct file *fp, u_long c
 static int
 fops_pad_stat(struct file *fp, struct stat *st)
 {
-	struct pad_softc *sc;
-	
-	sc = fp->f_pad;
-	if (sc == NULL)
-		return EIO;
+	struct pad_softc *sc = fp->f_pad;
 
 	memset(st, 0, sizeof(*st));
 
@@ -522,11 +498,7 @@ static int
 fops_pad_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
     int ioflag)
 {
-	struct pad_softc *sc;
-
-	sc = fp->f_pad;
-	if (sc == NULL)
-		return ENXIO;
+	struct pad_softc *sc = fp->f_pad;
 
 	return pad_read(sc, offp, uio, cred, ioflag);
 }

Reply via email to