Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 31 Mar 2019 21:34:58 +0000 (UTC)
From:      Kirk McKusick <mckusick@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r345758 - head/sys/dev/md
Message-ID:  <201903312134.x2VLYwO9018669@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mckusick
Date: Sun Mar 31 21:34:58 2019
New Revision: 345758
URL: https://svnweb.freebsd.org/changeset/base/345758

Log:
  When using the force option to shut down a memory-disk device,
  I/O operations already in its queue were not being properly drained.
  The GEOM framework does the queue draining, but the device driver
  needs to wait for the draining to happen. The waiting is done by
  adding a g_md_providergone() function to wait for the I/O operations
  to finish up.
  
  It is likely that every GEOM provider that implements orphaning
  attached GEOM consumers needs to use the "providergone" mechanism
  for this same reason, but some of them do not do so. Apparently
  Kenneth Merry (ken@) added the drain for just such races, but he
  missed adding it to some of the device drivers that needed it.
  
  Submitted by: Chuck Silvers
  Reviewed by:  imp
  Tested by:    Chuck Silvers
  MFC after:    1 week
  Sponsored by: Netflix

Modified:
  head/sys/dev/md/md.c

Modified: head/sys/dev/md/md.c
==============================================================================
--- head/sys/dev/md/md.c	Sun Mar 31 19:27:44 2019	(r345757)
+++ head/sys/dev/md/md.c	Sun Mar 31 21:34:58 2019	(r345758)
@@ -110,6 +110,7 @@
 
 #define MD_SHUTDOWN	0x10000		/* Tell worker thread to terminate. */
 #define	MD_EXITING	0x20000		/* Worker thread is exiting. */
+#define MD_PROVIDERGONE	0x40000		/* Safe to free the softc */
 
 #ifndef MD_NSECT
 #define MD_NSECT (10000 * 2)
@@ -199,6 +200,7 @@ static g_start_t g_md_start;
 static g_access_t g_md_access;
 static void g_md_dumpconf(struct sbuf *sb, const char *indent,
     struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp);
+static g_provgone_t g_md_providergone;
 
 static struct cdev *status_dev = NULL;
 static struct sx md_sx;
@@ -220,6 +222,7 @@ struct g_class g_md_class = {
 	.start = g_md_start,
 	.access = g_md_access,
 	.dumpconf = g_md_dumpconf,
+	.providergone = g_md_providergone,
 };
 
 DECLARE_GEOM_CLASS(g_md_class, g_md);
@@ -481,8 +484,8 @@ g_md_start(struct bio *bp)
 	}
 	mtx_lock(&sc->queue_mtx);
 	bioq_disksort(&sc->bio_queue, bp);
-	mtx_unlock(&sc->queue_mtx);
 	wakeup(sc);
+	mtx_unlock(&sc->queue_mtx);
 }
 
 #define	MD_MALLOC_MOVE_ZERO	1
@@ -1496,17 +1499,30 @@ bad:
 	return (error);
 }
 
+static void
+g_md_providergone(struct g_provider *pp)
+{
+	struct md_s *sc = pp->geom->softc;
+
+	mtx_lock(&sc->queue_mtx);
+	sc->flags |= MD_PROVIDERGONE;
+	wakeup(&sc->flags);
+	mtx_unlock(&sc->queue_mtx);
+}
+
 static int
 mddestroy(struct md_s *sc, struct thread *td)
 {
 
 	if (sc->gp) {
-		sc->gp->softc = NULL;
 		g_topology_lock();
 		g_wither_geom(sc->gp, ENXIO);
 		g_topology_unlock();
-		sc->gp = NULL;
-		sc->pp = NULL;
+
+		mtx_lock(&sc->queue_mtx);
+		while (!(sc->flags & MD_PROVIDERGONE))
+			msleep(&sc->flags, &sc->queue_mtx, PRIBIO, "mddestroy", 0);
+		mtx_unlock(&sc->queue_mtx);
 	}
 	if (sc->devstat) {
 		devstat_remove_entry(sc->devstat);



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