FreeBSD/sys/geom/mirror/g_mirror.c
/*
 * Handle synchronization requests.
 * Every synchronization request is two-steps process: first, READ request is
 * send to active provider and then WRITE request (with read data) to the provider
 * being synchronized. When WRITE is finished, new synchronization request is
 * send.
 */
Handle synchronization requests.
Every synchronization request is two-steps process: first, READ request is
send to active provider and then WRITE request (with read data) to the provider
being synchronized. When WRITE is finished, new synchronization request is
send.
Handle synchronization requests . Every synchronization request is two - steps process : first READ request is send to active provider and then WRITE request ( with read data ) to the provider being synchronized . When WRITE is finished new synchronization request is send .
static void
g_mirror_sync_request(struct bio *bp)
{
	struct g_mirror_softc *sc;
	struct g_mirror_disk *disk;
	bp->bio_from->index--;
	sc = bp->bio_from->geom->softc;
	disk = bp->bio_from->private;
	if (disk == NULL) {
		sx_xunlock(&sc->sc_lock); 
		g_topology_lock();
		g_mirror_kill_consumer(sc, bp->bio_from);
		g_topology_unlock();
		free(bp->bio_data, M_MIRROR);
		g_destroy_bio(bp);
		sx_xlock(&sc->sc_lock);
		return;
	}
	switch (bp->bio_cmd) {
	case BIO_READ:
	    {
		struct g_consumer *cp;
		if (bp->bio_error != 0) {
			G_MIRROR_LOGREQ(0, bp,
			    "Synchronization request failed (error=%d).",
			    bp->bio_error);
			g_destroy_bio(bp);
			return;
		}
		G_MIRROR_LOGREQ(3, bp,
		    "Synchronization request half-finished.");
		bp->bio_cmd = BIO_WRITE;
		bp->bio_cflags = 0;
		cp = disk->d_consumer;
		KASSERT(cp->acr >= 1 && cp->acw >= 1 && cp->ace >= 1,
		    ("Consumer %s not opened (r%dw%de%d).", cp->provider->name,
		    cp->acr, cp->acw, cp->ace));
		cp->index++;
		g_io_request(bp, cp);
		return;
	    }
	case BIO_WRITE:
	    {
		struct g_mirror_disk_sync *sync;
		off_t offset;
		void *data;
		int i;
		if (bp->bio_error != 0) {
			G_MIRROR_LOGREQ(0, bp,
			    "Synchronization request failed (error=%d).",
			    bp->bio_error);
			g_destroy_bio(bp);
			sc->sc_bump_id |= G_MIRROR_BUMP_GENID;
			g_mirror_event_send(disk,
			    G_MIRROR_DISK_STATE_DISCONNECTED,
			    G_MIRROR_EVENT_DONTWAIT);
			return;
		}
		G_MIRROR_LOGREQ(3, bp, "Synchronization request finished.");
		sync = &disk->d_sync;
		if (sync->ds_offset >= sc->sc_mediasize ||
		    sync->ds_consumer == NULL ||
		    (sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
			sync->ds_inflight--;
			if (sync->ds_bios != NULL) {
				i = (int)(uintptr_t)bp->bio_caller1;
				sync->ds_bios[i] = NULL;
			}
			free(bp->bio_data, M_MIRROR);
			g_destroy_bio(bp);
			if (sync->ds_inflight > 0)
				return;
			if (sync->ds_consumer == NULL ||
			    (sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
				return;
			}
			g_mirror_event_send(disk, G_MIRROR_DISK_STATE_ACTIVE,
			    G_MIRROR_EVENT_DONTWAIT);
			return;
		}
		data = bp->bio_data;
		g_reset_bio(bp);
		bp->bio_cmd = BIO_READ;
		bp->bio_offset = sync->ds_offset;
		bp->bio_length = MIN(MAXPHYS, sc->sc_mediasize - bp->bio_offset);
		sync->ds_offset += bp->bio_length;
		bp->bio_done = g_mirror_sync_done;
		bp->bio_data = data;
		bp->bio_from = sync->ds_consumer;
		bp->bio_to = sc->sc_provider;
		G_MIRROR_LOGREQ(3, bp, "Sending synchronization request.");
		sync->ds_consumer->index++;
		if (g_mirror_regular_collision(sc, bp))
			g_mirror_sync_delay(sc, bp);
		else
			g_io_request(bp, sync->ds_consumer);
		g_mirror_regular_release(sc);
		offset = sc->sc_mediasize;
		for (i = 0; i < g_mirror_syncreqs; i++) {
			bp = sync->ds_bios[i];
			if (bp->bio_offset < offset)
				offset = bp->bio_offset;
		}
		if (sync->ds_offset_done + (MAXPHYS * 100) < offset) {
			sync->ds_offset_done = offset;
			g_mirror_update_metadata(disk);
		}
		return;
	    }
	default:
		KASSERT(1 == 0, ("Invalid command here: %u (device=%s)",
		    bp->bio_cmd, sc->sc_name));
		break;
	}
}
static void g_mirror_sync_request ( struct bio * bp ) { struct g_mirror_softc * sc ; struct g_mirror_disk * disk ; bp -> bio_from -> index -- ; sc = bp -> bio_from -> geom -> softc ; disk = bp -> bio_from -> private ; if ( disk == NULL ) { sx_xunlock ( & sc -> sc_lock ) ; g_topology_lock ( ) ; g_mirror_kill_consumer ( sc , bp -> bio_from ) ; g_topology_unlock ( ) ; free ( bp -> bio_data , M_MIRROR ) ; g_destroy_bio ( bp ) ; sx_xlock ( & sc -> sc_lock ) ; return ; } switch ( bp -> bio_cmd ) { case BIO_READ : { struct g_consumer * cp ; if ( bp -> bio_error != 0 ) { G_MIRROR_LOGREQ ( 0 , bp , " " , bp -> bio_error ) ; g_destroy_bio ( bp ) ; return ; } G_MIRROR_LOGREQ ( 3 , bp , " " ) ; bp -> bio_cmd = BIO_WRITE ; bp -> bio_cflags = 0 ; cp = disk -> d_consumer ; KASSERT ( cp -> acr >= 1 && cp -> acw >= 1 && cp -> ace >= 1 , ( " " , cp -> provider -> name , cp -> acr , cp -> acw , cp -> ace ) ) ; cp -> index ++ ; g_io_request ( bp , cp ) ; return ; } case BIO_WRITE : { struct g_mirror_disk_sync * sync ; off_t offset ; void * data ; int i ; if ( bp -> bio_error != 0 ) { G_MIRROR_LOGREQ ( 0 , bp , " " , bp -> bio_error ) ; g_destroy_bio ( bp ) ; sc -> sc_bump_id |= G_MIRROR_BUMP_GENID ; g_mirror_event_send ( disk , G_MIRROR_DISK_STATE_DISCONNECTED , G_MIRROR_EVENT_DONTWAIT ) ; return ; } G_MIRROR_LOGREQ ( 3 , bp , " " ) ; sync = & disk -> d_sync ; if ( sync -> ds_offset >= sc -> sc_mediasize || sync -> ds_consumer == NULL || ( sc -> sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY ) != 0 ) { sync -> ds_inflight -- ; if ( sync -> ds_bios != NULL ) { i = ( int ) ( uintptr_t ) bp -> bio_caller1 ; sync -> ds_bios [ i ] = NULL ; } free ( bp -> bio_data , M_MIRROR ) ; g_destroy_bio ( bp ) ; if ( sync -> ds_inflight > 0 ) return ; if ( sync -> ds_consumer == NULL || ( sc -> sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY ) != 0 ) { return ; } g_mirror_event_send ( disk , G_MIRROR_DISK_STATE_ACTIVE , G_MIRROR_EVENT_DONTWAIT ) ; return ; } data = bp -> bio_data ; g_reset_bio ( bp ) ; bp -> bio_cmd = BIO_READ ; bp -> bio_offset = sync -> ds_offset ; bp -> bio_length = MIN ( MAXPHYS , sc -> sc_mediasize - bp -> bio_offset ) ; sync -> ds_offset += bp -> bio_length ; bp -> bio_done = g_mirror_sync_done ; bp -> bio_data = data ; bp -> bio_from = sync -> ds_consumer ; bp -> bio_to = sc -> sc_provider ; G_MIRROR_LOGREQ ( 3 , bp , " " ) ; sync -> ds_consumer -> index ++ ; if ( g_mirror_regular_collision ( sc , bp ) ) g_mirror_sync_delay ( sc , bp ) ; else g_io_request ( bp , sync -> ds_consumer ) ; g_mirror_regular_release ( sc ) ; offset = sc -> sc_mediasize ; for ( i = 0 ; i < g_mirror_syncreqs ; i ++ ) { bp = sync -> ds_bios [ i ] ; if ( bp -> bio_offset < offset ) offset = bp -> bio_offset ; } if ( sync -> ds_offset_done + ( MAXPHYS * 100 ) < offset ) { sync -> ds_offset_done = offset ; g_mirror_update_metadata ( disk ) ; } return ; } default : KASSERT ( 1 == 0 , ( " " , bp -> bio_cmd , sc -> sc_name ) ) ; break ; } }
Handle synchronization requests.
Handle synchronization requests .
/* Avoid recursion on sc_lock. */ /*
	 * Synchronization request.
	 */ /* Don't send more synchronization requests. */ /* Disk up-to-date, activate it. */ /* Send next synchronization request. */ /*
		 * Delay the request if it is colliding with a regular request.
		 */ /* Release delayed requests if possible. */ /* Find the smallest offset */ /* Update offset_done on every 100 blocks. */