Index: lib/geom/nop/gnop.8 =================================================================== --- lib/geom/nop/gnop.8 +++ lib/geom/nop/gnop.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 17, 2018 +.Dd July 24, 2019 .Dt GNOP 8 .Os .Sh NAME @@ -34,22 +34,28 @@ .Nm .Cm create .Op Fl v +.Op Fl d Ar delaymsec .Op Fl e Ar error .Op Fl o Ar offset .Op Fl p Ar stripesize .Op Fl P Ar stripeoffset +.Op Fl q Ar rdelayprob .Op Fl r Ar rfailprob .Op Fl s Ar size .Op Fl S Ar secsize .Op Fl w Ar wfailprob +.Op Fl x Ar wdelayprob .Op Fl z Ar physpath .Ar dev ... .Nm .Cm configure .Op Fl v +.Op Fl d Ar delaymsec .Op Fl e Ar error +.Op Fl q Ar rdelayprob .Op Fl r Ar rfailprob .Op Fl w Ar wfailprob +.Op Fl x Ar wdelayprob .Ar prov ... .Nm .Cm destroy @@ -113,26 +119,32 @@ .Pp Additional options: .Bl -tag -width ".Fl r Ar rfailprob" +.It Fl d Ar delaymsec +Specifies the delay of the requests in millisecond. .It Fl e Ar error Specifies the error number to return on failure. .It Fl f Force the removal of the specified provider. .It Fl o Ar offset Where to begin on the original provider. -.It Fl p Ar stripesize -Value of the stripesize property of the transparent provider. +.it fl p ar stripesize +value of the stripesize property of the transparent provider. .It Fl P Ar stripeoffset Value of the stripeoffset property of the transparent provider. +.It Fl q Ar rdelayprob +Specifies read delay probability in percent. .It Fl r Ar rfailprob Specifies read failure probability in percent. .It Fl s Ar size Size of the transparent provider. .It Fl S Ar secsize Sector size of the transparent provider. -.It Fl w Ar wfailprob +.it fl w ar wfailprob Specifies write failure probability in percent. .It Fl v Be more verbose. +.It Fl x Ar wdelayprob +Specifies write delay probability in percent. .It Fl z Ar physpath Physical path of the transparent provider. .El Index: sys/geom/nop/g_nop.h =================================================================== --- sys/geom/nop/g_nop.h +++ sys/geom/nop/g_nop.h @@ -62,26 +62,38 @@ } \ } while (0) +struct g_nop_delay { + struct callout dl_cal; + struct bio *dl_bio; + TAILQ_ENTRY(g_nop_delay) dl_next; +}; + +TAILQ_HEAD(g_nop_delay_head, g_nop_delay); + struct g_nop_softc { - int sc_error; - off_t sc_offset; - off_t sc_explicitsize; - off_t sc_stripesize; - off_t sc_stripeoffset; - u_int sc_rfailprob; - u_int sc_wfailprob; - uintmax_t sc_reads; - uintmax_t sc_writes; - uintmax_t sc_deletes; - uintmax_t sc_getattrs; - uintmax_t sc_flushes; - uintmax_t sc_cmd0s; - uintmax_t sc_cmd1s; - uintmax_t sc_cmd2s; - uintmax_t sc_readbytes; - uintmax_t sc_wrotebytes; - char* sc_physpath; - struct mtx sc_lock; + int sc_error; + off_t sc_offset; + off_t sc_explicitsize; + off_t sc_stripesize; + off_t sc_stripeoffset; + u_int sc_rfailprob; + u_int sc_wfailprob; + u_int sc_delaymsec; + u_int sc_rdelayprob; + u_int sc_wdelayprob; + uintmax_t sc_reads; + uintmax_t sc_writes; + uintmax_t sc_deletes; + uintmax_t sc_getattrs; + uintmax_t sc_flushes; + uintmax_t sc_cmd0s; + uintmax_t sc_cmd1s; + uintmax_t sc_cmd2s; + uintmax_t sc_readbytes; + uintmax_t sc_wrotebytes; + char* sc_physpath; + struct mtx sc_lock; + struct g_nop_delay_head sc_head_delay; }; #endif /* _KERNEL */ Index: sys/geom/nop/g_nop.c =================================================================== --- sys/geom/nop/g_nop.c +++ sys/geom/nop/g_nop.c @@ -142,6 +142,35 @@ g_io_deliver(bp, 0); } +static void +g_nop_pass(struct bio *cbp, struct g_geom *gp) +{ + + G_NOP_LOGREQ(cbp, "Sending request."); + g_io_request(cbp, LIST_FIRST(&gp->consumer)); +} + +static void +g_nop_pass_timeout(void *data) +{ + struct g_nop_softc *sc; + struct g_geom *gp; + struct g_nop_delay *gndelay; + + gndelay = (struct g_nop_delay *)data; + + gp = gndelay->dl_bio->bio_to->geom; + sc = gp->softc; + + mtx_lock(&sc->sc_lock); + TAILQ_REMOVE(&sc->sc_head_delay, gndelay, dl_next); + mtx_unlock(&sc->sc_lock); + + g_nop_pass(gndelay->dl_bio, gp); + + g_free(data); +} + static void g_nop_start(struct bio *bp) { @@ -149,10 +178,13 @@ struct g_geom *gp; struct g_provider *pp; struct bio *cbp; - u_int failprob = 0; + u_int failprob, delayprob; + + failprob = delayprob = 0; gp = bp->bio_to->geom; sc = gp->softc; + G_NOP_LOGREQ(bp, "Request received."); mtx_lock(&sc->sc_lock); switch (bp->bio_cmd) { @@ -160,11 +192,13 @@ sc->sc_reads++; sc->sc_readbytes += bp->bio_length; failprob = sc->sc_rfailprob; + delayprob = sc->sc_rdelayprob; break; case BIO_WRITE: sc->sc_writes++; sc->sc_wrotebytes += bp->bio_length; failprob = sc->sc_wfailprob; + delayprob = sc->sc_wdelayprob; break; case BIO_DELETE: sc->sc_deletes++; @@ -208,6 +242,7 @@ return; } } + cbp = g_clone_bio(bp); if (cbp == NULL) { g_io_deliver(bp, ENOMEM); @@ -218,8 +253,35 @@ pp = LIST_FIRST(&gp->provider); KASSERT(pp != NULL, ("NULL pp")); cbp->bio_to = pp; - G_NOP_LOGREQ(cbp, "Sending request."); - g_io_request(cbp, LIST_FIRST(&gp->consumer)); + + if (delayprob > 0) { + struct g_nop_delay *gndelay; + u_int rval; + + rval = arc4random() % 100; + if (rval < delayprob) { + gndelay = g_malloc(sizeof(*gndelay), M_NOWAIT | M_ZERO); + if (gndelay == NULL) { + g_io_deliver(bp, ENOMEM); + g_destroy_bio(cbp); + return; + } + callout_init(&gndelay->dl_cal, 0); + + gndelay->dl_bio = cbp; + + mtx_lock(&sc->sc_lock); + TAILQ_INSERT_TAIL(&sc->sc_head_delay, gndelay, dl_next); + mtx_unlock(&sc->sc_lock); + + callout_reset(&gndelay->dl_cal, + MSEC_2_TICKS(sc->sc_delaymsec), + g_nop_pass_timeout, gndelay); + return; + } + } + + g_nop_pass(cbp, gp); } static int @@ -331,9 +393,9 @@ sc->sc_cmd2s = 0; sc->sc_readbytes = 0; sc->sc_wrotebytes = 0; + TAILQ_INIT(&sc->sc_head_delay); mtx_init(&sc->sc_lock, "gnop lock", NULL, MTX_DEF); gp->softc = sc; - newpp = g_new_providerf(gp, "%s", gp->name); newpp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; newpp->mediasize = size; @@ -368,9 +430,20 @@ static void g_nop_providergone(struct g_provider *pp) { + struct g_nop_delay *dthis; struct g_geom *gp = pp->geom; struct g_nop_softc *sc = gp->softc; + for (;;) { + dthis = TAILQ_FIRST(&sc->sc_head_delay); + if (dthis == NULL) + break; + TAILQ_REMOVE(&sc->sc_head_delay, dthis, dl_next); + + callout_drain(&dthis->dl_cal); + g_free(dthis); + } + gp->softc = NULL; free(sc->sc_physpath, M_GEOM); mtx_destroy(&sc->sc_lock); @@ -400,6 +473,7 @@ } else { G_NOP_DEBUG(0, "Device %s removed.", gp->name); } + g_wither_geom(gp, ENXIO); return (0); @@ -826,7 +900,7 @@ sc->sc_wfailprob); sbuf_printf(sb, "%s%u\n", indent, sc->sc_rdelayprob); - sbuf_printf(sb, "%s%u%u\n", indent, sc->sc_wdelayprob); sbuf_printf(sb, "%s%d\n", indent, sc->sc_delaymsec); sbuf_printf(sb, "%s%d\n", indent, sc->sc_error);