⬢ DragonFlyBSD Kernel Audit
DF-4714 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/vinum/vinumraid5.c
+++ b/sys/dev/raid/vinum/vinumraid5.c
@@ -401,21 +401,37 @@
 		    enum requeststatus s;
 
 		    s = checksdstate(sd, rq, *diskaddr, diskend); /* do we need to change state? */
-		    if (s && (m.badsdno >= 0)) {	    /* second bad disk, */
+		    if (m.badsdno >= 0) {		    /* second bad subdisk (incl. the parity sd) */
 			int sdno;
+			int sdord;			    /* ordinal of the involved subdisk */
 			/*
 			 * If the parity disk is down, there's
 			 * no recovery.  We make all involved
 			 * subdisks stale.  Otherwise, we
 			 * should be able to recover, but it's
 			 * like pulling teeth.  Fix it later.
+			 *
+			 * The guard must not depend on checksdstate()
+			 * failing: a reviving or reborn data subdisk
+			 * returns REQUEST_OK and would silently
+			 * overwrite m.badsdno below, defeating the
+			 * parityless-write conversion and accepting
+			 * writes with two unusable data columns.
 			 */
+			sdord = m.firstsdno;		    /* walk the involved ordinals */
 			for (sdno = 0; sdno < m.sdcount; sdno++) {
-			    struct sd *sd = &SD[plex->sdnos[sdno]];
+			    if (sdord == m.psdno)		    /* parity, */
+				sdord++;
+			    if (sdord == plex->subdisks)	    /* got to the end, */
+				sdord = 0;
+			    if (sdord == m.psdno)		    /* parity, */
+				sdord++;
+			    sd = &SD[plex->sdnos[sdord]];
+			    sdord++;
 			    if (sd->state >= sd_reborn)	    /* sort of up, */
 				set_sd_state(sd->sdno, sd_stale, setstate_force); /* make it stale */
 			}
-			return s;			    /* and crap out */
+			return (s != REQUEST_OK) ? s : REQUEST_DOWN; /* and crap out */
 		    }
 		    m.badsdno = mysdno;			    /* note which one is bad */
 		    m.flags |= XFR_DEGRADED_WRITE;	    /* we need recovery */