diff --git a/lib/geom/nop/geom_nop.c b/lib/geom/nop/geom_nop.c
index ea7afdce0ca0..346a721d3127 100644
--- a/lib/geom/nop/geom_nop.c
+++ b/lib/geom/nop/geom_nop.c
@@ -43,6 +43,7 @@ uint32_t version = G_NOP_VERSION;
struct g_command class_commands[] = {
{ "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
{
+ { 'c', "count_until_fail", "-1", G_TYPE_NUMBER },
{ 'd', "delaymsec", "-1", G_TYPE_NUMBER },
{ 'e', "error", "-1", G_TYPE_NUMBER },
{ 'o', "offset", "0", G_TYPE_NUMBER },
@@ -57,12 +58,14 @@ struct g_command class_commands[] = {
{ 'z', "physpath", G_NOP_PHYSPATH_PASSTHROUGH, G_TYPE_STRING },
G_OPT_SENTINEL
},
- "[-v] [-d delaymsec] [-e error] [-o offset] [-p stripesize] "
- "[-P stripeoffset] [-q rdelayprob] [-r rfailprob] [-s size] "
- "[-S secsize] [-w wfailprob] [-x wdelayprob] [-z physpath] dev ..."
+ "[-v] [-c count_until_fail] [-d delaymsec] [-e error] [-o offset] "
+ "[-p stripesize] [-P stripeoffset] [-q rdelayprob] [-r rfailprob] "
+ "[-s size] [-S secsize] [-w wfailprob] [-x wdelayprob] "
+ "[-z physpath] dev ..."
},
{ "configure", G_FLAG_VERBOSE, NULL,
{
+ { 'c', "count_until_fail", "-1", G_TYPE_NUMBER },
{ 'd', "delaymsec", "-1", G_TYPE_NUMBER },
{ 'e', "error", "-1", G_TYPE_NUMBER },
{ 'q', "rdelayprob", "-1", G_TYPE_NUMBER },
@@ -71,8 +74,9 @@ struct g_command class_commands[] = {
{ 'x', "wdelayprob", "-1", G_TYPE_NUMBER },
G_OPT_SENTINEL
},
- "[-v] [-d delaymsec] [-e error] [-q rdelayprob] [-r rfailprob] "
- "[-w wfailprob] [-x wdelayprob] prov ..."
+ "[-v] [-c count_until_fail] [-d delaymsec] [-e error] "
+ "[-q rdelayprob] [-r rfailprob] [-w wfailprob] [-x wdelayprob] "
+ "prov ..."
},
{ "destroy", G_FLAG_VERBOSE, NULL,
{
diff --git a/lib/geom/nop/gnop.8 b/lib/geom/nop/gnop.8
index ef6c44bc5297..12e609728566 100644
--- a/lib/geom/nop/gnop.8
+++ b/lib/geom/nop/gnop.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 31, 2019
+.Dd September 13, 2019
.Dt GNOP 8
.Os
.Sh NAME
@@ -34,6 +34,7 @@
.Nm
.Cm create
.Op Fl v
+.Op Fl c Ar count_until_fail
.Op Fl d Ar delaymsec
.Op Fl e Ar error
.Op Fl o Ar offset
@@ -50,6 +51,7 @@
.Nm
.Cm configure
.Op Fl v
+.Op Fl c Ar count_until_fail
.Op Fl d Ar delaymsec
.Op Fl e Ar error
.Op Fl q Ar rdelayprob
@@ -118,7 +120,10 @@ See
.El
.Pp
Additional options:
-.Bl -tag -width ".Fl r Ar rfailprob"
+.Bl -tag -width "-c count_until_fail"
+.It Fl c Ar count_until_fail
+Specifies the number of I/O requests to allow before setting the read and write
+failure probabilities to 100%.
.It Fl d Ar delaymsec
Specifies the delay of the requests in milliseconds.
Note that requests will be delayed before they are sent to the backing device.
diff --git a/sys/geom/nop/g_nop.c b/sys/geom/nop/g_nop.c
index 6c7706b52cd3..e8152030f518 100644
--- a/sys/geom/nop/g_nop.c
+++ b/sys/geom/nop/g_nop.c
@@ -195,6 +195,10 @@ g_nop_start(struct bio *bp)
G_NOP_LOGREQ(bp, "Request received.");
mtx_lock(&sc->sc_lock);
+ if (sc->sc_count_until_fail != 0 && --sc->sc_count_until_fail == 0) {
+ sc->sc_rfailprob = 100;
+ sc->sc_wfailprob = 100;
+ }
switch (bp->bio_cmd) {
case BIO_READ:
sc->sc_reads++;
@@ -308,9 +312,10 @@ g_nop_access(struct g_provider *pp, int dr, int dw, int de)
static int
g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
- int ioerror, u_int rfailprob, u_int wfailprob, u_int delaymsec, u_int rdelayprob,
- u_int wdelayprob, off_t offset, off_t size, u_int secsize, off_t stripesize,
- off_t stripeoffset, const char *physpath)
+ int ioerror, u_int count_until_fail, u_int rfailprob, u_int wfailprob,
+ u_int delaymsec, u_int rdelayprob, u_int wdelayprob, off_t offset,
+ off_t size, u_int secsize, off_t stripesize, off_t stripeoffset,
+ const char *physpath)
{
struct g_nop_softc *sc;
struct g_geom *gp;
@@ -386,6 +391,7 @@ g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
} else
sc->sc_physpath = NULL;
sc->sc_error = ioerror;
+ sc->sc_count_until_fail = count_until_fail;
sc->sc_rfailprob = rfailprob;
sc->sc_wfailprob = wfailprob;
sc->sc_delaymsec = delaymsec;
@@ -491,8 +497,9 @@ static void
g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
{
struct g_provider *pp;
- intmax_t *error, *rfailprob, *wfailprob, *offset, *secsize, *size,
- *stripesize, *stripeoffset, *delaymsec, *rdelayprob, *wdelayprob;
+ intmax_t *error, *rfailprob, *wfailprob, *count_until_fail, *offset,
+ *secsize, *size, *stripesize, *stripeoffset, *delaymsec,
+ *rdelayprob, *wdelayprob;
const char *name, *physpath;
char param[16];
int i, *nargs;
@@ -558,6 +565,16 @@ g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "Invalid '%s' argument", "wdelayprob");
return;
}
+ count_until_fail = gctl_get_paraml(req, "count_until_fail",
+ sizeof(*count_until_fail));
+ if (count_until_fail == NULL) {
+ gctl_error(req, "No '%s' argument", "count_until_fail");
+ return;
+ }
+ if (*count_until_fail < -1) {
+ gctl_error(req, "Invalid '%s' argument", "count_until_fail");
+ return;
+ }
offset = gctl_get_paraml(req, "offset", sizeof(*offset));
if (offset == NULL) {
gctl_error(req, "No '%s' argument", "offset");
@@ -622,6 +639,7 @@ g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
}
if (g_nop_create(req, mp, pp,
*error == -1 ? EIO : (int)*error,
+ *count_until_fail == -1 ? 0 : (u_int)*count_until_fail,
*rfailprob == -1 ? 0 : (u_int)*rfailprob,
*wfailprob == -1 ? 0 : (u_int)*wfailprob,
*delaymsec == -1 ? 1 : (u_int)*delaymsec,
@@ -640,7 +658,8 @@ g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp)
{
struct g_nop_softc *sc;
struct g_provider *pp;
- intmax_t *delaymsec, *error, *rdelayprob, *rfailprob, *wdelayprob, *wfailprob;
+ intmax_t *delaymsec, *error, *rdelayprob, *rfailprob, *wdelayprob,
+ *wfailprob, *count_until_fail;
const char *name;
char param[16];
int i, *nargs;
@@ -661,6 +680,12 @@ g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "No '%s' argument", "error");
return;
}
+ count_until_fail = gctl_get_paraml(req, "count_until_fail",
+ sizeof(*count_until_fail));
+ if (count_until_fail == NULL) {
+ gctl_error(req, "No '%s' argument", "count_until_fail");
+ return;
+ }
rfailprob = gctl_get_paraml(req, "rfailprob", sizeof(*rfailprob));
if (rfailprob == NULL) {
gctl_error(req, "No '%s' argument", "rfailprob");
@@ -736,6 +761,8 @@ g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp)
sc->sc_wdelayprob = (u_int)*wdelayprob;
if (*delaymsec != -1)
sc->sc_delaymsec = (u_int)*delaymsec;
+ if (*count_until_fail != -1)
+ sc->sc_count_until_fail = (u_int)*count_until_fail;
}
}
@@ -904,6 +931,8 @@ g_nop_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
sbuf_printf(sb, "%s%u\n", indent,
sc->sc_wdelayprob);
sbuf_printf(sb, "%s%d\n", indent, sc->sc_delaymsec);
+ sbuf_printf(sb, "%s%u\n", indent,
+ sc->sc_count_until_fail);
sbuf_printf(sb, "%s%d\n", indent, sc->sc_error);
sbuf_printf(sb, "%s%ju\n", indent, sc->sc_reads);
sbuf_printf(sb, "%s%ju\n", indent, sc->sc_writes);
diff --git a/sys/geom/nop/g_nop.h b/sys/geom/nop/g_nop.h
index d7649ac1c23f..f65a7544c4ca 100644
--- a/sys/geom/nop/g_nop.h
+++ b/sys/geom/nop/g_nop.h
@@ -62,6 +62,7 @@ struct g_nop_softc {
u_int sc_delaymsec;
u_int sc_rdelayprob;
u_int sc_wdelayprob;
+ u_int sc_count_until_fail;
uintmax_t sc_reads;
uintmax_t sc_writes;
uintmax_t sc_deletes;