FreeBSD/sys/geom/vinum/geom_vinum_raid5.c
/* Rebuild a degraded RAID5 plex. */
Rebuild a degraded RAID5 plex.
Rebuild a degraded RAID5 plex .
static int
gv_raid5_rebuild(struct gv_plex *p, struct gv_raid5_packet *wp, struct bio *bp,
    caddr_t addr, off_t boff, off_t bcount)
{
	struct gv_sd *broken, *s;
	struct gv_bioq *bq;
	struct bio *cbp;
	off_t real_len, real_off;
	if (p == NULL || LIST_EMPTY(&p->subdisks))
		return (ENXIO);
	gv_raid5_offset(p, boff, bcount, &real_off, &real_len, NULL, NULL, 1);
	broken = NULL;
	LIST_FOREACH(s, &p->subdisks, in_plex) {
		if (s->state != GV_SD_UP)
			broken = s;
	}
	if (broken == NULL)
		return (ENXIO);
	switch (broken->state) {
	case GV_SD_UP:
		return (EINVAL);
	case GV_SD_STALE:
		if (!(bp->bio_pflags & GV_BIO_REBUILD))
			return (ENXIO);
		G_VINUM_DEBUG(1, "sd %s is reviving", broken->name);
		gv_set_sd_state(broken, GV_SD_REVIVING, GV_SETSTATE_FORCE);
		broken->flags |= GV_SD_CANGOUP;
		break;
	case GV_SD_REVIVING:
		break;
	default:
		return (ENXIO);
	}
	wp->length = real_len;
	wp->data = addr;
	wp->lockbase = real_off;
	KASSERT(wp->length >= 0, ("gv_rebuild_raid5: wp->length < 0"));
	LIST_FOREACH(s, &p->subdisks, in_plex) {
		if (s == broken)
			continue;
		if (s->flags & GV_SD_GROW)
			continue;
		cbp = gv_raid5_clone_bio(bp, s, wp, NULL, 1);
		if (cbp == NULL)
			return (ENOMEM);
		cbp->bio_cmd = BIO_READ;
		bioq_insert_tail(p->bqueue, cbp);
		bq = g_malloc(sizeof(*bq), M_WAITOK | M_ZERO);
		bq->bp = cbp;
		TAILQ_INSERT_TAIL(&wp->bits, bq, queue);
	}
	cbp = gv_raid5_clone_bio(bp, broken, wp, NULL, 1);
	if (cbp == NULL)
		return (ENOMEM);
	wp->parity = cbp;
	p->synced = boff;
	return (0);
}
static int gv_raid5_rebuild ( struct gv_plex * p , struct gv_raid5_packet * wp , struct bio * bp , caddr_t addr , off_t boff , off_t bcount ) { struct gv_sd * broken , * s ; struct gv_bioq * bq ; struct bio * cbp ; off_t real_len , real_off ; if ( p == NULL || LIST_EMPTY ( & p -> subdisks ) ) return ( ENXIO ) ; gv_raid5_offset ( p , boff , bcount , & real_off , & real_len , NULL , NULL , 1 ) ; broken = NULL ; LIST_FOREACH ( s , & p -> subdisks , in_plex ) { if ( s -> state != GV_SD_UP ) broken = s ; } if ( broken == NULL ) return ( ENXIO ) ; switch ( broken -> state ) { case GV_SD_UP : return ( EINVAL ) ; case GV_SD_STALE : if ( ! ( bp -> bio_pflags & GV_BIO_REBUILD ) ) return ( ENXIO ) ; G_VINUM_DEBUG ( 1 , " " , broken -> name ) ; gv_set_sd_state ( broken , GV_SD_REVIVING , GV_SETSTATE_FORCE ) ; broken -> flags |= GV_SD_CANGOUP ; break ; case GV_SD_REVIVING : break ; default : return ( ENXIO ) ; } wp -> length = real_len ; wp -> data = addr ; wp -> lockbase = real_off ; KASSERT ( wp -> length >= 0 , ( " " ) ) ; LIST_FOREACH ( s , & p -> subdisks , in_plex ) { if ( s == broken ) continue ; if ( s -> flags & GV_SD_GROW ) continue ; cbp = gv_raid5_clone_bio ( bp , s , wp , NULL , 1 ) ; if ( cbp == NULL ) return ( ENOMEM ) ; cbp -> bio_cmd = BIO_READ ; bioq_insert_tail ( p -> bqueue , cbp ) ; bq = g_malloc ( sizeof ( * bq ) , M_WAITOK | M_ZERO ) ; bq -> bp = cbp ; TAILQ_INSERT_TAIL ( & wp -> bits , bq , queue ) ; } cbp = gv_raid5_clone_bio ( bp , broken , wp , NULL , 1 ) ; if ( cbp == NULL ) return ( ENOMEM ) ; wp -> parity = cbp ; p -> synced = boff ; return ( 0 ) ; }
Rebuild a degraded RAID5 plex.
Rebuild a degraded RAID5 plex .
/* Find the right subdisk. */ /* Broken stripe not found. */ /* Set this bit now, but should be set at end. */ /* All other subdisk states mean it's not accessible. */ /* Read all subdisks. */ /* Skip the broken subdisk. */ /* Skip growing subdisks. */ /* Write the parity data. */ /* Post notification that we're finished. */