Index: head/lib/geom/nop/geom_nop.c =================================================================== --- head/lib/geom/nop/geom_nop.c +++ head/lib/geom/nop/geom_nop.c @@ -43,6 +43,7 @@ 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 @@ { '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 @@ { '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, { Index: head/lib/geom/nop/gnop.8 =================================================================== --- head/lib/geom/nop/gnop.8 +++ head/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 @@ .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. Index: head/sys/geom/nop/g_nop.h =================================================================== --- head/sys/geom/nop/g_nop.h +++ head/sys/geom/nop/g_nop.h @@ -62,6 +62,7 @@ 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; Index: head/sys/geom/nop/g_nop.c =================================================================== --- head/sys/geom/nop/g_nop.c +++ head/sys/geom/nop/g_nop.c @@ -195,6 +195,10 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ } 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 @@ { 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 @@ 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 @@ 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 @@ 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);