Module Name: src Committed By: riastradh Date: Mon Jun 14 18:44:53 UTC 2021
Modified Files: src/sys/dev/pad: pad.c Log Message: pad(4): Explain what's wrong with using device pointers like this. ...and why the kernel lock is not enough. To generate a diff of this commit: cvs rdiff -u -r1.74 -r1.75 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.74 src/sys/dev/pad/pad.c:1.75 --- src/sys/dev/pad/pad.c:1.74 Mon Jun 14 18:44:45 2021 +++ src/sys/dev/pad/pad.c Mon Jun 14 18:44:53 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: pad.c,v 1.74 2021/06/14 18:44:45 riastradh Exp $ */ +/* $NetBSD: pad.c,v 1.75 2021/06/14 18:44:53 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.74 2021/06/14 18:44:45 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.75 2021/06/14 18:44:53 riastradh Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -386,6 +386,36 @@ pad_close(struct pad_softc *sc) device_t self = sc->sc_dev; cfdata_t cf = device_cfdata(self); + /* + * XXX This is not quite enough to prevent racing with drvctl + * detach. What can happen: + * + * cpu0 cpu1 + * + * pad_close + * take kernel lock + * sc->sc_open = 0 + * drop kernel lock + * wait for config_misc_lock + * drvctl detach + * take kernel lock + * drop kernel lock + * wait for config_misc_lock + * retake kernel lock + * drop config_misc_lock + * take config_misc_lock + * wait for kernel lock + * pad_detach (sc_open=0 already) + * free device + * drop kernel lock + * use device after free + * + * We need a way to grab a reference to the device so it won't + * be freed until we're done -- it's OK if we config_detach + * twice as long as it's idempotent, but not OK if the first + * config_detach frees the struct device before the second one + * has finished handling it. + */ KERNEL_LOCK(1, NULL); KASSERT(sc->sc_open); sc->sc_open = 0;