diff options
author | Ian Lepore <ian@FreeBSD.org> | 2019-05-10 02:30:16 +0000 |
---|---|---|
committer | Ian Lepore <ian@FreeBSD.org> | 2019-05-10 02:30:16 +0000 |
commit | 0eba88cf916d0f951410f1128db12d7737963297 (patch) | |
tree | 460dc74f3f5d22abf992de836f1f3ed6979790b7 /sys/dev/dcons | |
parent | afb7737237bc08596389e4352f66e3031316563c (diff) | |
download | src-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
Diffstat (limited to 'sys/dev/dcons')
-rw-r--r-- | sys/dev/dcons/dcons_os.c | 18 |
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 */ |