diff --git a/sys/dev/vinum/vinumrevive.c b/sys/dev/vinum/vinumrevive.c index 3339e426fdfa..e7cc3dd33a4d 100644 --- a/sys/dev/vinum/vinumrevive.c +++ b/sys/dev/vinum/vinumrevive.c @@ -33,7 +33,7 @@ * otherwise) arising in any way out of the use of this software, even if * advised of the possibility of such damage. * - * $Id: vinumrevive.c,v 1.6 1998/12/28 16:28:23 peter Exp $ + * $Id: vinumrevive.c,v 1.6 1999/01/17 06:20:44 grog Exp grog $ */ #define REALLYKERNEL @@ -41,87 +41,138 @@ #include #include -/* revive a block of a plex. Return an error +/* revive a block of a subdisk. Return an error * indication. EAGAIN means successful copy, but - * that more blocks remain to be copied. + * that more blocks remain to be copied. EINVAL means + * that the subdisk isn't associated with a plex (which + * means a programming error if we get here at all; + * FIXME) * XXX We should specify a block size here. At the moment, * just take a default value. FIXME */ int -revive_block(int plexno) +revive_block(int sdno) { - struct plex *plex = &PLEX[plexno]; + struct sd *sd; + struct plex *plex; + struct volume *vol; struct buf *bp; int error = EAGAIN; int size; /* size of revive block, bytes */ int s; /* priority level */ + daddr_t plexblkno; /* lblkno in plex */ - if (plex->revive_blocksize == 0) { + plexblkno = 0; /* to keep the compiler happy */ + sd = &SD[sdno]; + if (sd->plexno < 0) /* no plex? */ + return EINVAL; + plex = &PLEX[sd->plexno]; /* point to plex */ + if (plex->volno >= 0) + vol = &VOL[plex->volno]; + else + vol = NULL; + + if (sd->revive_blocksize == 0) { if (plex->stripesize != 0) /* we're striped, don't revive more than */ - plex->revive_blocksize = min(DEFAULT_REVIVE_BLOCKSIZE, /* one block at a time */ + sd->revive_blocksize = min(DEFAULT_REVIVE_BLOCKSIZE, /* one block at a time */ plex->stripesize << DEV_BSHIFT); else - plex->revive_blocksize = DEFAULT_REVIVE_BLOCKSIZE; + sd->revive_blocksize = DEFAULT_REVIVE_BLOCKSIZE; } - size = min(plex->revive_blocksize >> DEV_BSHIFT, plex->length - plex->revived) << DEV_BSHIFT; + size = min(sd->revive_blocksize >> DEV_BSHIFT, sd->sectors - sd->revived) << DEV_BSHIFT; s = splbio(); - /* Get a buffer */ - bp = geteblk(size); + + bp = geteblk(size); /* Get a buffer */ if (bp == NULL) { splx(s); return ENOMEM; } if (bp->b_qindex != 0) /* on a queue, */ - bremfree(bp); /* remove it */ + bremfree(bp); /* remove it XXX how can this happen? */ splx(s); /* Amount to transfer: block size, unless it * would overlap the end */ bp->b_bufsize = size; bp->b_bcount = bp->b_bufsize; - bp->b_resid = 0x0; - bp->b_blkno = plex->revived; /* we've got this far */ + bp->b_resid = 0; - /* XXX what about reviving anonymous plexes? */ + /* Now decide where to read from */ - /* First, read the data from the volume. We don't - * care which plex, that's bre's job */ - bp->b_dev = VINUMBDEV(plex->volno, 0, 0, VINUM_VOLUME_TYPE); /* create the device number */ - bp->b_flags = B_BUSY | B_READ; - vinumstart(bp, 1); - biowait(bp); + switch (plex->organization) { + daddr_t stripeoffset; /* offset in stripe */ + + case plex_concat: + plexblkno = sd->revived + sd->plexoffset; /* corresponding address in plex */ + break; + + case plex_striped: + stripeoffset = sd->revived % plex->stripesize; /* offset from beginning of stripe */ + plexblkno = sd->plexoffset /* base */ + + (sd->revived - stripeoffset) * plex->subdisks /* offset to beginning of stripe */ + + sd->revived % plex->stripesize; /* offset from beginning of stripe */ + break; + + case plex_raid5: + case plex_disorg: /* to keep the compiler happy */ + } + + { + bp->b_blkno = plexblkno; /* start here */ + if (vol != NULL) /* it's part of a volume, */ + /* First, read the data from the volume. We don't + * care which plex, that's bre's job */ + bp->b_dev = VINUMBDEV(plex->volno, 0, 0, VINUM_VOLUME_TYPE); /* create the device number */ + else /* it's an unattached plex */ + bp->b_dev = VINUMRBDEV(sd->plexno, VINUM_RAWPLEX_TYPE); /* create the device number */ + + bp->b_flags = B_BUSY | B_READ; /* either way, read it */ + vinumstart(bp, 1); + biowait(bp); + } if (bp->b_flags & B_ERROR) error = bp->b_error; else - /* Now write to the plex */ + /* Now write to the subdisk */ { s = splbio(); if (bp->b_qindex != 0) /* on a queue, */ bremfree(bp); /* remove it */ splx(s); - bp->b_dev = VINUMBDEV(plex->volno, plex->volplexno, 0, VINUM_PLEX_TYPE); /* create the device number */ - bp->b_flags = B_BUSY; /* make this a write */ + bp->b_dev = VINUMRBDEV(sdno, VINUM_RAWSD_TYPE); /* create the device number */ + bp->b_flags = B_BUSY | B_ORDERED; /* and make this an ordered write */ bp->b_resid = 0x0; - vinumstart(bp, 1); + bp->b_blkno = sd->revived; /* write it to here */ + sdio(bp); /* perform the I/O */ biowait(bp); if (bp->b_flags & B_ERROR) error = bp->b_error; else { - plex->revived += bp->b_bcount >> DEV_BSHIFT; /* moved this much further down */ - if (plex->revived >= plex->length) { /* finished */ - plex->revived = 0; - plex->state = plex_up; /* do we need to do more? */ - if (plex->volno >= 0) /* we have a volume, */ - set_volume_state(plex->volno, volume_up, 0); - printf("vinum: plex %s is %s\n", plex->name, plex_state(plex->state)); + sd->revived += bp->b_bcount >> DEV_BSHIFT; /* moved this much further down */ + if (sd->revived >= sd->sectors) { /* finished */ + sd->revived = 0; + set_sd_state(sdno, sd_up, setstate_force); /* bring the sd up */ + printf("vinum: %s is %s\n", sd->name, sd_state(sd->state)); save_config(); /* and save the updated configuration */ error = 0; /* we're done */ } } - while (plex->waitlist) { /* we have waiting requests */ - launch_requests(plex->waitlist, 1); /* do them now */ - plex->waitlist = plex->waitlist->next; /* and move on to the next */ + while (sd->waitlist) { /* we have waiting requests */ +#if VINUMDEBUG + struct request *rq = sd->waitlist; + + if (debug & DEBUG_REVIVECONFLICT) + printf("Relaunch revive conflict sd %d: %x\n%s dev 0x%x, offset 0x%x, length %ld\n", + rq->sdno, + (u_int) rq, + rq->bp->b_flags & B_READ ? "Read" : "Write", + rq->bp->b_dev, + rq->bp->b_blkno, + rq->bp->b_bcount); +#endif + launch_requests(sd->waitlist, 1); /* do them now */ + sd->waitlist = sd->waitlist->next; /* and move on to the next */ } } if (bp->b_qindex == 0) /* not on a queue, */