aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lepore <ian@FreeBSD.org>2019-05-10 02:30:16 +0000
committerIan Lepore <ian@FreeBSD.org>2019-05-10 02:30:16 +0000
commit0eba88cf916d0f951410f1128db12d7737963297 (patch)
tree460dc74f3f5d22abf992de836f1f3ed6979790b7
parentafb7737237bc08596389e4352f66e3031316563c (diff)
downloadsrc-0eba88cf916d0f951410f1128db12d7737963297.tar.gz
src-0eba88cf916d0f951410f1128db12d7737963297.zip
Allow dcons(4) to be unloaded when loaded as a module.
When the module is unloaded, the tty devices are destroyed. That requires implementing the tsw_free callback to avoid a panic. This driver requires no particular cleanup to be done from the callback, but the module itself must remain in memory until the deferred tsw_free callbacks are invoked. These changes implement that by incrementing a reference count variable in the detach routine, and decrementing it in the tsw_free callback. The MOD_UNLOAD event handler doesn't return until the count drops to zero. PR: 237758
Notes
Notes: svn path=/head/; revision=347422
-rw-r--r--sys/dev/dcons/dcons_os.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/sys/dev/dcons/dcons_os.c b/sys/dev/dcons/dcons_os.c
index 3ccdfeade53b..6853515c6820 100644
--- a/sys/dev/dcons/dcons_os.c
+++ b/sys/dev/dcons/dcons_os.c
@@ -52,6 +52,7 @@
#include <sys/proc.h>
#include <sys/ucred.h>
+#include <machine/atomic.h>
#include <machine/bus.h>
#include <dev/dcons/dcons.h>
@@ -135,12 +136,16 @@ extern struct gdb_dbgport *gdb_cur;
#endif
static tsw_outwakeup_t dcons_outwakeup;
+static tsw_free_t dcons_free;
static struct ttydevsw dcons_ttydevsw = {
.tsw_flags = TF_NOPREFIX,
.tsw_outwakeup = dcons_outwakeup,
+ .tsw_free = dcons_free,
};
+static int dcons_close_refs;
+
#if (defined(GDB) || defined(DDB))
static int
dcons_check_break(struct dcons_softc *dc, int c)
@@ -198,6 +203,14 @@ dcons_os_putc(struct dcons_softc *dc, int c)
}
static void
+dcons_free(void *xsc __unused)
+{
+
+ /* Our deferred free has arrived, now we're waiting for one fewer. */
+ atomic_subtract_rel_int(&dcons_close_refs, 1);
+}
+
+static void
dcons_outwakeup(struct tty *tp)
{
struct dcons_softc *dc;
@@ -396,6 +409,8 @@ dcons_detach(int port)
dc = &sc[port];
tp = dc->tty;
+ /* tty_rel_gone() schedules a deferred free callback, count it. */
+ atomic_add_int(&dcons_close_refs, 1);
tty_lock(tp);
tty_rel_gone(tp);
@@ -430,6 +445,9 @@ dcons_modevent(module_t mode, int type, void *data)
contigfree(dg.buf, DCONS_BUF_SIZE, M_DEVBUF);
}
+ /* Wait for tty deferred free callbacks to complete. */
+ while (atomic_load_acq_int(&dcons_close_refs) > 0)
+ pause_sbt("dcunld", mstosbt(50), mstosbt(10), 0);
break;
case MOD_SHUTDOWN:
#if 0 /* Keep connection after halt */