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);