MFC: Sync with HEAD.
This commit is contained in:
parent
947bbe05ee
commit
b11d89f3f9
@ -68,5 +68,8 @@ struct g_command class_commands[] = {
|
||||
},
|
||||
"[-fv] prov ..."
|
||||
},
|
||||
{ "reset", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
|
||||
"[-v] prov ..."
|
||||
},
|
||||
G_CMD_SENTINEL
|
||||
};
|
||||
|
@ -49,6 +49,10 @@
|
||||
.Op Fl fv
|
||||
.Ar prov ...
|
||||
.Nm
|
||||
.Cm reset
|
||||
.Op Fl v
|
||||
.Ar prov ...
|
||||
.Nm
|
||||
.Cm list
|
||||
.Nm
|
||||
.Cm status
|
||||
@ -62,7 +66,10 @@ The
|
||||
utility is used for setting up transparent providers on existing ones.
|
||||
Its main purpose is testing other GEOM classes, as it allows forced provider
|
||||
removal and I/O error simulation with a given probability.
|
||||
It is also a good starting point for implementing new GEOM classes.
|
||||
It also gathers the following statistics: number of read requests, number of
|
||||
write requests, number of read bytes and number of wrote bytes.
|
||||
In addition, it can be used as a good starting point for implementing new GEOM
|
||||
class.
|
||||
.Pp
|
||||
The first argument to
|
||||
.Nm
|
||||
@ -77,13 +84,11 @@ The kernel module
|
||||
will be loaded if it is not loaded already.
|
||||
.It Cm configure
|
||||
Configure existing transparent provider.
|
||||
At the moment it is only used
|
||||
for changing failure probability.
|
||||
The kernel module
|
||||
.Pa geom_nop.ko
|
||||
will be loaded if it is not loaded already.
|
||||
At the moment it is only used for changing failure probability.
|
||||
.It Cm destroy
|
||||
Turn off the given transparent providers.
|
||||
.It Cm reset
|
||||
Reset statistics for the given transparent providers.
|
||||
.It Cm list
|
||||
See
|
||||
.Xr geom 8 .
|
||||
@ -139,6 +144,17 @@ with 50% failure probability, and how to destroy it.
|
||||
gnop create -v -f 50 da0
|
||||
gnop destroy -v da0.nop
|
||||
.Ed
|
||||
.Pp
|
||||
The traffic statistics for the given transparent providers we can get with
|
||||
.Cm list
|
||||
command.
|
||||
Example below shows how can we obtain number of bytes written with
|
||||
.Xr newfs 8 :
|
||||
.Bd -literal -offset indent
|
||||
gnop create da0
|
||||
newfs /dev/da0.nop
|
||||
gnop list
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr geom 4 ,
|
||||
.Xr geom 8
|
||||
|
@ -81,20 +81,31 @@ g_nop_start(struct bio *bp)
|
||||
gp = bp->bio_to->geom;
|
||||
sc = gp->softc;
|
||||
G_NOP_LOGREQ(bp, "Request received.");
|
||||
cbp = g_clone_bio(bp);
|
||||
if (cbp == NULL) {
|
||||
g_io_deliver(bp, ENOMEM);
|
||||
return;
|
||||
switch (bp->bio_cmd) {
|
||||
case BIO_READ:
|
||||
sc->sc_reads++;
|
||||
sc->sc_readbytes += bp->bio_length;
|
||||
break;
|
||||
case BIO_WRITE:
|
||||
sc->sc_writes++;
|
||||
sc->sc_wrotebytes += bp->bio_length;
|
||||
break;
|
||||
}
|
||||
if (sc->sc_failprob > 0) {
|
||||
u_int rval;
|
||||
|
||||
rval = arc4random() % 100;
|
||||
if (rval < sc->sc_failprob) {
|
||||
G_NOP_LOGREQ(bp, "Returning EIO.");
|
||||
g_io_deliver(bp, EIO);
|
||||
return;
|
||||
}
|
||||
}
|
||||
cbp = g_clone_bio(bp);
|
||||
if (cbp == NULL) {
|
||||
g_io_deliver(bp, ENOMEM);
|
||||
return;
|
||||
}
|
||||
cbp->bio_done = g_std_done;
|
||||
cbp->bio_offset = bp->bio_offset + sc->sc_offset;
|
||||
cbp->bio_data = bp->bio_data;
|
||||
@ -176,6 +187,10 @@ g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
|
||||
sc = g_malloc(sizeof(*sc), M_WAITOK);
|
||||
sc->sc_offset = offset;
|
||||
sc->sc_failprob = failprob;
|
||||
sc->sc_reads = 0;
|
||||
sc->sc_writes = 0;
|
||||
sc->sc_readbytes = 0;
|
||||
sc->sc_wrotebytes = 0;
|
||||
gp->softc = sc;
|
||||
gp->start = g_nop_start;
|
||||
gp->orphan = g_nop_orphan;
|
||||
@ -448,6 +463,50 @@ g_nop_ctl_destroy(struct gctl_req *req, struct g_class *mp)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_nop_ctl_reset(struct gctl_req *req, struct g_class *mp)
|
||||
{
|
||||
struct g_nop_softc *sc;
|
||||
struct g_provider *pp;
|
||||
const char *name;
|
||||
char param[16];
|
||||
int i, *nargs;
|
||||
|
||||
g_topology_assert();
|
||||
|
||||
nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
|
||||
if (nargs == NULL) {
|
||||
gctl_error(req, "No '%s' argument", "nargs");
|
||||
return;
|
||||
}
|
||||
if (*nargs <= 0) {
|
||||
gctl_error(req, "Missing device(s).");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < *nargs; i++) {
|
||||
snprintf(param, sizeof(param), "arg%d", i);
|
||||
name = gctl_get_asciiparam(req, param);
|
||||
if (name == NULL) {
|
||||
gctl_error(req, "No 'arg%d' argument", i);
|
||||
return;
|
||||
}
|
||||
if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
|
||||
name += strlen("/dev/");
|
||||
pp = g_provider_by_name(name);
|
||||
if (pp == NULL || pp->geom->class != mp) {
|
||||
G_NOP_DEBUG(1, "Provider %s is invalid.", name);
|
||||
gctl_error(req, "Provider %s is invalid.", name);
|
||||
return;
|
||||
}
|
||||
sc = pp->geom->softc;
|
||||
sc->sc_reads = 0;
|
||||
sc->sc_writes = 0;
|
||||
sc->sc_readbytes = 0;
|
||||
sc->sc_wrotebytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_nop_config(struct gctl_req *req, struct g_class *mp, const char *verb)
|
||||
{
|
||||
@ -474,6 +533,9 @@ g_nop_config(struct gctl_req *req, struct g_class *mp, const char *verb)
|
||||
} else if (strcmp(verb, "destroy") == 0) {
|
||||
g_nop_ctl_destroy(req, mp);
|
||||
return;
|
||||
} else if (strcmp(verb, "reset") == 0) {
|
||||
g_nop_ctl_reset(req, mp);
|
||||
return;
|
||||
}
|
||||
|
||||
gctl_error(req, "Unknown verb.");
|
||||
@ -490,7 +552,13 @@ g_nop_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
|
||||
sc = gp->softc;
|
||||
sbuf_printf(sb, "%s<Offset>%jd</Offset>\n", indent,
|
||||
(intmax_t)sc->sc_offset);
|
||||
sbuf_printf(sb, "%s<Failprob>%u</Failprob>\n", indent, sc->sc_failprob);
|
||||
sbuf_printf(sb, "%s<FailProb>%u</FailProb>\n", indent, sc->sc_failprob);
|
||||
sbuf_printf(sb, "%s<Reads>%ju</Reads>\n", indent, sc->sc_reads);
|
||||
sbuf_printf(sb, "%s<Writes>%ju</Writes>\n", indent, sc->sc_writes);
|
||||
sbuf_printf(sb, "%s<ReadBytes>%ju</ReadBytes>\n", indent,
|
||||
sc->sc_readbytes);
|
||||
sbuf_printf(sb, "%s<WroteBytes>%ju</WroteBytes>\n", indent,
|
||||
sc->sc_wrotebytes);
|
||||
}
|
||||
|
||||
DECLARE_GEOM_CLASS(g_nop_class, g_nop);
|
||||
|
@ -55,8 +55,12 @@
|
||||
} while (0)
|
||||
|
||||
struct g_nop_softc {
|
||||
off_t sc_offset;
|
||||
u_int sc_failprob;
|
||||
off_t sc_offset;
|
||||
u_int sc_failprob;
|
||||
uintmax_t sc_reads;
|
||||
uintmax_t sc_writes;
|
||||
uintmax_t sc_readbytes;
|
||||
uintmax_t sc_wrotebytes;
|
||||
};
|
||||
#endif /* _KERNEL */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user