⬢ DragonFlyBSD Kernel Audit
DF-4801 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/vinum/vinumrevive.c
+++ b/sys/dev/raid/vinum/vinumrevive.c
@@ -232,10 +244,46 @@
     }
     Free(bp->b_data);
     relpbuf(bp, &vinum_conf.physbufs);
+    atomic_store_int(&sd->revive_busy, 0);		    /* DF-4800 fix */
     return error;
 }
 
 /*
+ * DF-4801 fix: drain a subdisk's revive waitlist when the revive is
+ * being abandoned.  Queued requests were built against a reviving
+ * subdisk and nobody else will ever launch them: leaving them queued
+ * hangs the writers forever (biowait without PCATCH) and leaks the
+ * requests.  If the subdisk is (or just became) up, relaunch them --
+ * that is what revive_block()'s own drain would have done; otherwise
+ * fail them with EIO.
+ */
+void
+drain_sd_waitlist(int sdno)
+{
+    struct sd *sd = &SD[sdno];
+    struct request *rq;
+
+    if (sd->waitlist == NULL)
+	return;
+    rq = (struct request *)
+	atomic_swap_long((volatile unsigned long *)&sd->waitlist, 0);
+    while (rq) {
+	struct request *next = rq->next;		    /* unlink first: launches can free */
+
+	if (sd->state == sd_up) {
+	    rq->next = NULL;
+	    launch_requests(rq, 1);			    /* revive completed: run them */
+	} else {					    /* revive abandoned: fail them */
+	    rq->bio->bio_buf->b_error = EIO;
+	    rq->bio->bio_buf->b_flags |= B_ERROR;
+	    biodone(rq->bio);
+	    freerq(rq);
+	}
+	rq = next;
+    }
+}
+
+/*
  * Check or rebuild the parity blocks of a RAID-4
  * or RAID-5 plex.
  *
--- a/sys/dev/raid/vinum/vinumstate.c
+++ b/sys/dev/raid/vinumstate.c
@@ -284,6 +284,9 @@
     }
     if (status == 1) {					    /* we can do it, */
 	sd->state = newstate;
+	if ((oldstate == sd_reviving)			    /* DF-4801 fix: a revive just */
+	&&(newstate != sd_reviving))			    /* ended or was aborted: drain */
+	    drain_sd_waitlist(sdno);			    /* the requests waiting on it */
 	if (flags & setstate_force)
 	    log(LOG_INFO, "vinum: %s is %s by force\n", sd->name, sd_state(sd->state));
 	else
--- a/sys/dev/raid/vinum/vinumext.h
+++ b/sys/dev/raid/vinum/vinumext.h
@@ -198,6 +198,7 @@
 int revive_read(struct sd *sd);
 int revive_block(int sdno);
 void parityops(struct vinum_ioctl_msg *);
+void drain_sd_waitlist(int sdno);			    /* DF-4801 fix */
 
 /* Auxiliary functions */
 enum sdstates sdstatemap(struct plex *plex);