Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 May 2019 17:50:17 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r347624 - stable/12/sys/dev/dcons
Message-ID:  <201905151750.x4FHoH10048043@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ian
Date: Wed May 15 17:50:17 2019
New Revision: 347624
URL: https://svnweb.freebsd.org/changeset/base/347624

Log:
  MFC r347422:
  
  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

Modified:
  stable/12/sys/dev/dcons/dcons_os.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/dev/dcons/dcons_os.c
==============================================================================
--- stable/12/sys/dev/dcons/dcons_os.c	Wed May 15 17:48:11 2019	(r347623)
+++ stable/12/sys/dev/dcons/dcons_os.c	Wed May 15 17:50:17 2019	(r347624)
@@ -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 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905151750.x4FHoH10048043>