Author: smh
Date: Tue Dec 15 21:11:41 2015
New Revision: 292289
URL: https://svnweb.freebsd.org/changeset/base/292289

Log:
  Prevent g_access calls to bad multipath members
  
  When a multipath member is orphaned its access members are zeroed before its
  removed if marked for wither, so prevent any future calls to g_access on
  such members.
  
  This prevents a panic on debug kernels which validates the resultant values
  aren't negative.
  
  Reviewed by:  mav
  MFC after:    2 weeks
  Sponsored by: Multiplay
  Differential Revision:        https://reviews.freebsd.org/D4416

Modified:
  head/sys/geom/multipath/g_multipath.c

Modified: head/sys/geom/multipath/g_multipath.c
==============================================================================
--- head/sys/geom/multipath/g_multipath.c       Tue Dec 15 21:02:53 2015        
(r292288)
+++ head/sys/geom/multipath/g_multipath.c       Tue Dec 15 21:11:41 2015        
(r292289)
@@ -107,8 +107,9 @@ struct g_class g_multipath_class = {
 #define        MP_NEW          0x00000004
 #define        MP_POSTED       0x00000008
 #define        MP_BAD          (MP_FAIL | MP_LOST | MP_NEW)
-#define MP_IDLE                0x00000010
-#define MP_IDLE_MASK   0xfffffff0
+#define        MP_WITHER       0x00000010
+#define        MP_IDLE         0x00000020
+#define        MP_IDLE_MASK    0xffffffe0
 
 static int
 g_multipath_good(struct g_geom *gp)
@@ -204,6 +205,7 @@ g_mpd(void *arg, int flags __unused)
                g_access(cp, -cp->acr, -cp->acw, -cp->ace);
                if (w > 0 && cp->provider != NULL &&
                    (cp->provider->geom->flags & G_GEOM_WITHER) == 0) {
+                       cp->index |= MP_WITHER;
                        g_post_event(g_mpd, cp, M_WAITOK, NULL);
                        return;
                }
@@ -467,23 +469,37 @@ g_multipath_access(struct g_provider *pp
 
        gp = pp->geom;
 
+       /* Error used if we have no valid consumers. */
+       error = ENXIO;
+
        LIST_FOREACH(cp, &gp->consumer, consumer) {
+               if (cp->index & MP_WITHER)
+                       continue;
+
                error = g_access(cp, dr, dw, de);
                if (error) {
                        badcp = cp;
                        goto fail;
                }
        }
+
+       if (error != 0)
+               return (error);
+
        sc = gp->softc;
        sc->sc_opened += dr + dw + de;
        if (sc->sc_stopping && sc->sc_opened == 0)
                g_multipath_destroy(gp);
+
        return (0);
 
 fail:
        LIST_FOREACH(cp, &gp->consumer, consumer) {
                if (cp == badcp)
                        break;
+               if (cp->index & MP_WITHER)
+                       continue;
+
                (void) g_access(cp, -dr, -dw, -de);
        }
        return (error);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to