--- 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);