FreeBSD/sys/geom/vinum/geom_vinum_plex.c
/*
 * Handle a completed request to a RAID-5 plex.
 */
Handle a completed request to a RAID-5 plex.
Handle a completed request to a RAID - 5 plex .
void
gv_plex_raid5_done(struct gv_plex *p, struct bio *bp)
{
	struct gv_softc *sc;
	struct bio *cbp, *pbp;
	struct gv_bioq *bq, *bq2;
	struct gv_raid5_packet *wp;
	off_t completed;
	int i;
	completed = 0;
	sc = p->vinumconf;
	wp = bp->bio_caller2;
	switch (bp->bio_parent->bio_cmd) {
	case BIO_READ:
		if (wp == NULL) {
			completed = bp->bio_completed;
			break;
		}
		TAILQ_FOREACH_SAFE(bq, &wp->bits, queue, bq2) {
			if (bq->bp != bp)
				continue;
			TAILQ_REMOVE(&wp->bits, bq, queue);
			g_free(bq);
			for (i = 0; i < wp->length; i++)
				wp->data[i] ^= bp->bio_data[i];
			break;
		}
		if (TAILQ_EMPTY(&wp->bits)) {
			completed = wp->length;
			if (wp->lockbase != -1) {
				TAILQ_REMOVE(&p->packets, wp, list);
				pbp = bioq_takefirst(p->wqueue);
				while (pbp != NULL) {
					gv_post_bio(sc, pbp);
					pbp = bioq_takefirst(p->wqueue);
				}
			}
			g_free(wp);
		}
		break;
 	case BIO_WRITE:
		if (wp == NULL) {
			completed = bp->bio_completed;
			break;
		}
		TAILQ_FOREACH_SAFE(bq, &wp->bits, queue, bq2) {
			if (bq->bp != bp)
				continue;
			TAILQ_REMOVE(&wp->bits, bq, queue);
			g_free(bq);
			cbp = wp->parity;
			if (cbp != NULL) {
				for (i = 0; i < wp->length; i++)
					cbp->bio_data[i] ^= bp->bio_data[i];
			}
			break;
		}
		if (TAILQ_EMPTY(&wp->bits)) {
			if (bp->bio_parent->bio_pflags & GV_BIO_CHECK)
				i = gv_check_parity(p, bp, wp);
			else
				i = gv_normal_parity(p, bp, wp);
			if (i) {
				completed = wp->length;
				TAILQ_REMOVE(&p->packets, wp, list);
				pbp = bioq_takefirst(p->wqueue);
				while (pbp != NULL) {
					gv_post_bio(sc, pbp);
					pbp = bioq_takefirst(p->wqueue);
				}
				g_free(wp);
			}
		}
		break;
	}
	pbp = bp->bio_parent;
	if (pbp->bio_error == 0)
		pbp->bio_error = bp->bio_error;
	pbp->bio_completed += completed;
	pbp->bio_inbed++;
	if (pbp->bio_inbed == pbp->bio_children) {
		if (pbp->bio_cmd == BIO_WRITE &&
		    (pbp->bio_pflags & GV_BIO_CHECK)) {
			gv_parity_complete(p, pbp);
		} else if (pbp->bio_cmd == BIO_WRITE &&
		    (pbp->bio_pflags & GV_BIO_REBUILD)) {
			gv_rebuild_complete(p, pbp);
		} else if (pbp->bio_pflags & GV_BIO_INIT) {
			gv_init_complete(p, pbp);
		} else if (pbp->bio_pflags & GV_BIO_SYNCREQ) {
			gv_sync_complete(p, pbp);
		} else if (pbp->bio_pflags & GV_BIO_GROW) {
			gv_grow_complete(p, pbp);
		} else {
			g_io_deliver(pbp, pbp->bio_error);
		}
	}
	if (bp->bio_cflags & GV_BIO_MALLOC)
		g_free(bp->bio_data);
	g_destroy_bio(bp);
}
void gv_plex_raid5_done ( struct gv_plex * p , struct bio * bp ) { struct gv_softc * sc ; struct bio * cbp , * pbp ; struct gv_bioq * bq , * bq2 ; struct gv_raid5_packet * wp ; off_t completed ; int i ; completed = 0 ; sc = p -> vinumconf ; wp = bp -> bio_caller2 ; switch ( bp -> bio_parent -> bio_cmd ) { case BIO_READ : if ( wp == NULL ) { completed = bp -> bio_completed ; break ; } TAILQ_FOREACH_SAFE ( bq , & wp -> bits , queue , bq2 ) { if ( bq -> bp != bp ) continue ; TAILQ_REMOVE ( & wp -> bits , bq , queue ) ; g_free ( bq ) ; for ( i = 0 ; i < wp -> length ; i ++ ) wp -> data [ i ] ^= bp -> bio_data [ i ] ; break ; } if ( TAILQ_EMPTY ( & wp -> bits ) ) { completed = wp -> length ; if ( wp -> lockbase != -1 ) { TAILQ_REMOVE ( & p -> packets , wp , list ) ; pbp = bioq_takefirst ( p -> wqueue ) ; while ( pbp != NULL ) { gv_post_bio ( sc , pbp ) ; pbp = bioq_takefirst ( p -> wqueue ) ; } } g_free ( wp ) ; } break ; case BIO_WRITE : if ( wp == NULL ) { completed = bp -> bio_completed ; break ; } TAILQ_FOREACH_SAFE ( bq , & wp -> bits , queue , bq2 ) { if ( bq -> bp != bp ) continue ; TAILQ_REMOVE ( & wp -> bits , bq , queue ) ; g_free ( bq ) ; cbp = wp -> parity ; if ( cbp != NULL ) { for ( i = 0 ; i < wp -> length ; i ++ ) cbp -> bio_data [ i ] ^= bp -> bio_data [ i ] ; } break ; } if ( TAILQ_EMPTY ( & wp -> bits ) ) { if ( bp -> bio_parent -> bio_pflags & GV_BIO_CHECK ) i = gv_check_parity ( p , bp , wp ) ; else i = gv_normal_parity ( p , bp , wp ) ; if ( i ) { completed = wp -> length ; TAILQ_REMOVE ( & p -> packets , wp , list ) ; pbp = bioq_takefirst ( p -> wqueue ) ; while ( pbp != NULL ) { gv_post_bio ( sc , pbp ) ; pbp = bioq_takefirst ( p -> wqueue ) ; } g_free ( wp ) ; } } break ; } pbp = bp -> bio_parent ; if ( pbp -> bio_error == 0 ) pbp -> bio_error = bp -> bio_error ; pbp -> bio_completed += completed ; pbp -> bio_inbed ++ ; if ( pbp -> bio_inbed == pbp -> bio_children ) { if ( pbp -> bio_cmd == BIO_WRITE && ( pbp -> bio_pflags & GV_BIO_CHECK ) ) { gv_parity_complete ( p , pbp ) ; } else if ( pbp -> bio_cmd == BIO_WRITE && ( pbp -> bio_pflags & GV_BIO_REBUILD ) ) { gv_rebuild_complete ( p , pbp ) ; } else if ( pbp -> bio_pflags & GV_BIO_INIT ) { gv_init_complete ( p , pbp ) ; } else if ( pbp -> bio_pflags & GV_BIO_SYNCREQ ) { gv_sync_complete ( p , pbp ) ; } else if ( pbp -> bio_pflags & GV_BIO_GROW ) { gv_grow_complete ( p , pbp ) ; } else { g_io_deliver ( pbp , pbp -> bio_error ) ; } } if ( bp -> bio_cflags & GV_BIO_MALLOC ) g_free ( bp -> bio_data ) ; g_destroy_bio ( bp ) ; }
Handle a completed request to a RAID-5 plex.
Handle a completed request to a RAID - 5 plex .
/* Bring the waiting bios back into the game. */ /* XXX can this ever happen? */ /* Check if we need to handle parity data. */ /* Handle parity data. */ /* All of our sub-requests have finished. */ /* Bring the waiting bios back into the game. */ /* When the original request is finished, we deliver it. */ /* Hand it over for checking or delivery. */ /* Clean up what we allocated. */