Changeset View
Standalone View
sys/geom/nop/g_nop.c
Show First 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | struct g_class g_nop_class = { | ||||
.access = g_nop_access, | .access = g_nop_access, | ||||
.dumpconf = g_nop_dumpconf, | .dumpconf = g_nop_dumpconf, | ||||
.orphan = g_nop_orphan, | .orphan = g_nop_orphan, | ||||
.providergone = g_nop_providergone, | .providergone = g_nop_providergone, | ||||
.resize = g_nop_resize, | .resize = g_nop_resize, | ||||
.start = g_nop_start, | .start = g_nop_start, | ||||
}; | }; | ||||
struct g_nop_delay { | |||||
struct callout dl_cal; | |||||
struct bio *dl_bio; | |||||
TAILQ_ENTRY(g_nop_delay) dl_next; | |||||
}; | |||||
static void | static void | ||||
g_nop_orphan(struct g_consumer *cp) | g_nop_orphan(struct g_consumer *cp) | ||||
{ | { | ||||
g_topology_assert(); | g_topology_assert(); | ||||
g_nop_destroy(cp->geom, 1); | g_nop_destroy(cp->geom, 1); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | g_nop_kerneldump(struct bio *bp, struct g_nop_softc *sc) | ||||
} | } | ||||
if (gkd->offset + gkd->length > sc->sc_explicitsize) | if (gkd->offset + gkd->length > sc->sc_explicitsize) | ||||
gkd->length = sc->sc_explicitsize - gkd->offset; | gkd->length = sc->sc_explicitsize - gkd->offset; | ||||
gkd->di.mediasize = gkd->length; | gkd->di.mediasize = gkd->length; | ||||
g_io_deliver(bp, 0); | g_io_deliver(bp, 0); | ||||
} | } | ||||
static void | 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) | g_nop_start(struct bio *bp) | ||||
{ | { | ||||
struct g_nop_softc *sc; | struct g_nop_softc *sc; | ||||
struct g_geom *gp; | struct g_geom *gp; | ||||
struct g_provider *pp; | struct g_provider *pp; | ||||
struct bio *cbp; | struct bio *cbp; | ||||
u_int failprob = 0; | u_int failprob, delayprob, delaytime; | ||||
failprob = delayprob = 0; | |||||
gp = bp->bio_to->geom; | gp = bp->bio_to->geom; | ||||
sc = gp->softc; | sc = gp->softc; | ||||
G_NOP_LOGREQ(bp, "Request received."); | G_NOP_LOGREQ(bp, "Request received."); | ||||
mtx_lock(&sc->sc_lock); | mtx_lock(&sc->sc_lock); | ||||
switch (bp->bio_cmd) { | switch (bp->bio_cmd) { | ||||
case BIO_READ: | case BIO_READ: | ||||
sc->sc_reads++; | sc->sc_reads++; | ||||
sc->sc_readbytes += bp->bio_length; | sc->sc_readbytes += bp->bio_length; | ||||
failprob = sc->sc_rfailprob; | failprob = sc->sc_rfailprob; | ||||
delayprob = sc->sc_rdelayprob; | |||||
delaytime = sc->sc_delaymsec; | |||||
break; | break; | ||||
case BIO_WRITE: | case BIO_WRITE: | ||||
sc->sc_writes++; | sc->sc_writes++; | ||||
sc->sc_wrotebytes += bp->bio_length; | sc->sc_wrotebytes += bp->bio_length; | ||||
failprob = sc->sc_wfailprob; | failprob = sc->sc_wfailprob; | ||||
delayprob = sc->sc_wdelayprob; | |||||
delaytime = sc->sc_delaymsec; | |||||
break; | break; | ||||
case BIO_DELETE: | case BIO_DELETE: | ||||
sc->sc_deletes++; | sc->sc_deletes++; | ||||
break; | break; | ||||
case BIO_GETATTR: | case BIO_GETATTR: | ||||
sc->sc_getattrs++; | sc->sc_getattrs++; | ||||
if (sc->sc_physpath && | if (sc->sc_physpath && | ||||
g_handleattr_str(bp, "GEOM::physpath", sc->sc_physpath)) | g_handleattr_str(bp, "GEOM::physpath", sc->sc_physpath)) | ||||
Show All 27 Lines | if (failprob > 0) { | ||||
rval = arc4random() % 100; | rval = arc4random() % 100; | ||||
if (rval < failprob) { | if (rval < failprob) { | ||||
G_NOP_LOGREQLVL(1, bp, "Returning error=%d.", sc->sc_error); | G_NOP_LOGREQLVL(1, bp, "Returning error=%d.", sc->sc_error); | ||||
g_io_deliver(bp, sc->sc_error); | g_io_deliver(bp, sc->sc_error); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
cbp = g_clone_bio(bp); | cbp = g_clone_bio(bp); | ||||
if (cbp == NULL) { | if (cbp == NULL) { | ||||
g_io_deliver(bp, ENOMEM); | g_io_deliver(bp, ENOMEM); | ||||
return; | return; | ||||
} | } | ||||
cbp->bio_done = g_std_done; | cbp->bio_done = g_std_done; | ||||
cbp->bio_offset = bp->bio_offset + sc->sc_offset; | cbp->bio_offset = bp->bio_offset + sc->sc_offset; | ||||
pp = LIST_FIRST(&gp->provider); | pp = LIST_FIRST(&gp->provider); | ||||
KASSERT(pp != NULL, ("NULL pp")); | KASSERT(pp != NULL, ("NULL pp")); | ||||
cbp->bio_to = 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) { | |||||
markj: Shouldn't we just pass the I/O through without delays in this case? | |||||
Done Inline ActionsInteresting question. oshogbo: Interesting question.
This is an test suit so I don't think there is really reason to fail at… | |||||
callout_init(&gndelay->dl_cal, 1); | |||||
gndelay->dl_bio = cbp; | |||||
mtx_lock(&sc->sc_lock); | |||||
Not Done Inline ActionsWhy does this require Giant? markj: Why does this require Giant? | |||||
Done Inline ActionsI implemented this first and then ask pjd about that. oshogbo: I implemented this first and then ask pjd about that.
TBH pjd told me that this lock is used… | |||||
Not Done Inline ActionsSorry, I don't follow. The lock is acquired when the callout fires. We should avoid introducing new users of Giant and instead either use the softc lock, or do not specify a lock at all. (I think the latter is fine.) markj: Sorry, I don't follow. The lock is acquired when the callout fires. We should avoid introducing… | |||||
TAILQ_INSERT_TAIL(&sc->sc_head_delay, gndelay, | |||||
dl_next); | |||||
mtx_unlock(&sc->sc_lock); | |||||
callout_reset(&gndelay->dl_cal, | |||||
MSEC_2_TICKS(delaytime), g_nop_pass_timeout, | |||||
gndelay); | |||||
return; | |||||
} | } | ||||
} | |||||
} | |||||
g_nop_pass(cbp, gp); | |||||
} | |||||
static int | static int | ||||
g_nop_access(struct g_provider *pp, int dr, int dw, int de) | g_nop_access(struct g_provider *pp, int dr, int dw, int de) | ||||
{ | { | ||||
struct g_geom *gp; | struct g_geom *gp; | ||||
struct g_consumer *cp; | struct g_consumer *cp; | ||||
int error; | int error; | ||||
gp = pp->geom; | gp = pp->geom; | ||||
cp = LIST_FIRST(&gp->consumer); | cp = LIST_FIRST(&gp->consumer); | ||||
error = g_access(cp, dr, dw, de); | error = g_access(cp, dr, dw, de); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, | g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, | ||||
int ioerror, u_int rfailprob, u_int wfailprob, off_t offset, off_t size, | int ioerror, u_int rfailprob, u_int wfailprob, u_int delaymsec, u_int rdelayprob, | ||||
u_int secsize, off_t stripesize, off_t stripeoffset, const char *physpath) | 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_nop_softc *sc; | ||||
struct g_geom *gp; | struct g_geom *gp; | ||||
struct g_provider *newpp; | struct g_provider *newpp; | ||||
struct g_consumer *cp; | struct g_consumer *cp; | ||||
char name[64]; | char name[64]; | ||||
int error; | int error; | ||||
off_t explicitsize; | off_t explicitsize; | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, | ||||
sc->sc_stripeoffset = stripeoffset; | sc->sc_stripeoffset = stripeoffset; | ||||
if (physpath && strcmp(physpath, G_NOP_PHYSPATH_PASSTHROUGH)) { | if (physpath && strcmp(physpath, G_NOP_PHYSPATH_PASSTHROUGH)) { | ||||
sc->sc_physpath = strndup(physpath, MAXPATHLEN, M_GEOM); | sc->sc_physpath = strndup(physpath, MAXPATHLEN, M_GEOM); | ||||
} else | } else | ||||
sc->sc_physpath = NULL; | sc->sc_physpath = NULL; | ||||
sc->sc_error = ioerror; | sc->sc_error = ioerror; | ||||
sc->sc_rfailprob = rfailprob; | sc->sc_rfailprob = rfailprob; | ||||
sc->sc_wfailprob = wfailprob; | sc->sc_wfailprob = wfailprob; | ||||
sc->sc_delaymsec = delaymsec; | |||||
sc->sc_rdelayprob = rdelayprob; | |||||
sc->sc_wdelayprob = wdelayprob; | |||||
sc->sc_reads = 0; | sc->sc_reads = 0; | ||||
sc->sc_writes = 0; | sc->sc_writes = 0; | ||||
sc->sc_deletes = 0; | sc->sc_deletes = 0; | ||||
sc->sc_getattrs = 0; | sc->sc_getattrs = 0; | ||||
sc->sc_flushes = 0; | sc->sc_flushes = 0; | ||||
sc->sc_cmd0s = 0; | sc->sc_cmd0s = 0; | ||||
sc->sc_cmd1s = 0; | sc->sc_cmd1s = 0; | ||||
sc->sc_cmd2s = 0; | sc->sc_cmd2s = 0; | ||||
sc->sc_readbytes = 0; | sc->sc_readbytes = 0; | ||||
sc->sc_wrotebytes = 0; | sc->sc_wrotebytes = 0; | ||||
TAILQ_INIT(&sc->sc_head_delay); | |||||
mtx_init(&sc->sc_lock, "gnop lock", NULL, MTX_DEF); | mtx_init(&sc->sc_lock, "gnop lock", NULL, MTX_DEF); | ||||
gp->softc = sc; | gp->softc = sc; | ||||
newpp = g_new_providerf(gp, "%s", gp->name); | newpp = g_new_providerf(gp, "%s", gp->name); | ||||
newpp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; | newpp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE; | ||||
newpp->mediasize = size; | newpp->mediasize = size; | ||||
newpp->sectorsize = secsize; | newpp->sectorsize = secsize; | ||||
newpp->stripesize = stripesize; | newpp->stripesize = stripesize; | ||||
Show All 24 Lines | |||||
} | } | ||||
static void | static void | ||||
g_nop_providergone(struct g_provider *pp) | g_nop_providergone(struct g_provider *pp) | ||||
{ | { | ||||
struct g_geom *gp = pp->geom; | struct g_geom *gp = pp->geom; | ||||
struct g_nop_softc *sc = gp->softc; | struct g_nop_softc *sc = gp->softc; | ||||
KASSERT(TAILQ_EMPTY(&sc->sc_head_delay), | |||||
Not Done Inline ActionsMaybe qualify: "delayed request list is not empty". markj: Maybe qualify: "delayed request list is not empty". | |||||
("delayed request list is not empty")); | |||||
Not Done Inline ActionsI think this loop should not be necessary: GEOM must not invoke providergone while I/O to the provider is still pending. Another way to think about it: suppose there are entries in the delay list. That means that gnop is still waiting for I/O requests to the lower layers to complete. But immediately after this queue is cleared, we free the gnop provider, so we cannot handle I/O completions. GEOM uses nstart and nend fields of the provider to track pending I/O, and doesn't call providergone while those numbers are not equal. And while there are entries pending in the delay queue, we must have nstart > nend. markj: I think this loop should not be necessary: GEOM must not invoke providergone while I/O to the… | |||||
Done Inline ActionsI was observing this behavior, but I wasn't sure what will happen when the provider will be orphaned (for example the memstick was removed). oshogbo: I was observing this behavior, but I wasn't sure what will happen when the provider will be… | |||||
Not Done Inline ActionsPending BIOs will bounce back through the provider with an error in that case. Regardless, this loop cannot be correct unless I am misunderstanding something. I believe you can simply assert that the queue is empty. If not, then there is some larger problem and this loop cannot be sufficient for handling it correctly, for the reason I stated above. markj: Pending BIOs will bounce back through the provider with an error in that case. Regardless, this… | |||||
gp->softc = NULL; | gp->softc = NULL; | ||||
Not Done Inline ActionsThis can all be written in one line: while ((dthis = TAILQ_FIRST(&sc->sc_head_delay)) != NULL) { markj: This can all be written in one line: `while ((dthis = TAILQ_FIRST(&sc->sc_head_delay)) != NULL)… | |||||
free(sc->sc_physpath, M_GEOM); | free(sc->sc_physpath, M_GEOM); | ||||
mtx_destroy(&sc->sc_lock); | mtx_destroy(&sc->sc_lock); | ||||
g_free(sc); | g_free(sc); | ||||
} | } | ||||
static int | static int | ||||
g_nop_destroy(struct g_geom *gp, boolean_t force) | g_nop_destroy(struct g_geom *gp, boolean_t force) | ||||
{ | { | ||||
Show All 12 Lines | if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { | ||||
} else { | } else { | ||||
G_NOP_DEBUG(1, "Device %s is still open (r%dw%de%d).", | G_NOP_DEBUG(1, "Device %s is still open (r%dw%de%d).", | ||||
pp->name, pp->acr, pp->acw, pp->ace); | pp->name, pp->acr, pp->acw, pp->ace); | ||||
return (EBUSY); | return (EBUSY); | ||||
} | } | ||||
} else { | } else { | ||||
G_NOP_DEBUG(0, "Device %s removed.", gp->name); | G_NOP_DEBUG(0, "Device %s removed.", gp->name); | ||||
} | } | ||||
Done Inline ActionsUnrelated change. markj: Unrelated change. | |||||
g_wither_geom(gp, ENXIO); | g_wither_geom(gp, ENXIO); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
g_nop_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) | g_nop_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) | ||||
{ | { | ||||
return (g_nop_destroy(gp, 0)); | return (g_nop_destroy(gp, 0)); | ||||
} | } | ||||
static void | static void | ||||
g_nop_ctl_create(struct gctl_req *req, struct g_class *mp) | g_nop_ctl_create(struct gctl_req *req, struct g_class *mp) | ||||
{ | { | ||||
struct g_provider *pp; | struct g_provider *pp; | ||||
intmax_t *error, *rfailprob, *wfailprob, *offset, *secsize, *size, | intmax_t *error, *rfailprob, *wfailprob, *offset, *secsize, *size, | ||||
*stripesize, *stripeoffset; | *stripesize, *stripeoffset, *delaymsec, *rdelayprob, *wdelayprob; | ||||
const char *name, *physpath; | const char *name, *physpath; | ||||
char param[16]; | char param[16]; | ||||
int i, *nargs; | int i, *nargs; | ||||
g_topology_assert(); | g_topology_assert(); | ||||
nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); | nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); | ||||
if (nargs == NULL) { | if (nargs == NULL) { | ||||
Show All 22 Lines | g_nop_ctl_create(struct gctl_req *req, struct g_class *mp) | ||||
if (wfailprob == NULL) { | if (wfailprob == NULL) { | ||||
gctl_error(req, "No '%s' argument", "wfailprob"); | gctl_error(req, "No '%s' argument", "wfailprob"); | ||||
return; | return; | ||||
} | } | ||||
if (*wfailprob < -1 || *wfailprob > 100) { | if (*wfailprob < -1 || *wfailprob > 100) { | ||||
gctl_error(req, "Invalid '%s' argument", "wfailprob"); | gctl_error(req, "Invalid '%s' argument", "wfailprob"); | ||||
return; | return; | ||||
} | } | ||||
delaymsec = gctl_get_paraml(req, "delaymsec", sizeof(*delaymsec)); | |||||
if (delaymsec == NULL) { | |||||
gctl_error(req, "No '%s' argument", "delaymsec"); | |||||
return; | |||||
} | |||||
if (*delaymsec < 1 && *delaymsec != -1) { | |||||
gctl_error(req, "Invalid '%s' argument", "delaymsec"); | |||||
return; | |||||
} | |||||
rdelayprob = gctl_get_paraml(req, "rdelayprob", sizeof(*rdelayprob)); | |||||
if (rdelayprob == NULL) { | |||||
gctl_error(req, "No '%s' argument", "rdelayprob"); | |||||
return; | |||||
} | |||||
if (*rdelayprob < -1 || *rdelayprob > 100) { | |||||
Not Done Inline ActionsWhy do you allow a delay probability of -1? markj: Why do you allow a delay probability of -1? | |||||
Done Inline ActionsIt the same as wfailprob. oshogbo: It the same as wfailprob.
it means 'do not change'.
Is set when the user will not provide the… | |||||
Not Done Inline ActionsAh, I see. It would be nice to use nvlists for GEOM configuration, so that absence of a key would indicate "do not change" instead. markj: Ah, I see. It would be nice to use nvlists for GEOM configuration, so that absence of a key… | |||||
gctl_error(req, "Invalid '%s' argument", "rdelayprob"); | |||||
return; | |||||
} | |||||
wdelayprob = gctl_get_paraml(req, "wdelayprob", sizeof(*wdelayprob)); | |||||
if (wdelayprob == NULL) { | |||||
gctl_error(req, "No '%s' argument", "wdelayprob"); | |||||
return; | |||||
} | |||||
if (*wdelayprob < -1 || *wdelayprob > 100) { | |||||
gctl_error(req, "Invalid '%s' argument", "wdelayprob"); | |||||
return; | |||||
} | |||||
offset = gctl_get_paraml(req, "offset", sizeof(*offset)); | offset = gctl_get_paraml(req, "offset", sizeof(*offset)); | ||||
if (offset == NULL) { | if (offset == NULL) { | ||||
gctl_error(req, "No '%s' argument", "offset"); | gctl_error(req, "No '%s' argument", "offset"); | ||||
return; | return; | ||||
} | } | ||||
if (*offset < 0) { | if (*offset < 0) { | ||||
gctl_error(req, "Invalid '%s' argument", "offset"); | gctl_error(req, "Invalid '%s' argument", "offset"); | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | if (pp == NULL) { | ||||
G_NOP_DEBUG(1, "Provider %s is invalid.", name); | G_NOP_DEBUG(1, "Provider %s is invalid.", name); | ||||
gctl_error(req, "Provider %s is invalid.", name); | gctl_error(req, "Provider %s is invalid.", name); | ||||
return; | return; | ||||
} | } | ||||
if (g_nop_create(req, mp, pp, | if (g_nop_create(req, mp, pp, | ||||
*error == -1 ? EIO : (int)*error, | *error == -1 ? EIO : (int)*error, | ||||
*rfailprob == -1 ? 0 : (u_int)*rfailprob, | *rfailprob == -1 ? 0 : (u_int)*rfailprob, | ||||
*wfailprob == -1 ? 0 : (u_int)*wfailprob, | *wfailprob == -1 ? 0 : (u_int)*wfailprob, | ||||
*delaymsec == -1 ? 1 : (u_int)*delaymsec, | |||||
*rdelayprob == -1 ? 0 : (u_int)*rdelayprob, | |||||
*wdelayprob == -1 ? 0 : (u_int)*wdelayprob, | |||||
(off_t)*offset, (off_t)*size, (u_int)*secsize, | (off_t)*offset, (off_t)*size, (u_int)*secsize, | ||||
(off_t)*stripesize, (off_t)*stripeoffset, | (off_t)*stripesize, (off_t)*stripeoffset, | ||||
physpath) != 0) { | physpath) != 0) { | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp) | g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp) | ||||
{ | { | ||||
struct g_nop_softc *sc; | struct g_nop_softc *sc; | ||||
struct g_provider *pp; | struct g_provider *pp; | ||||
intmax_t *error, *rfailprob, *wfailprob; | intmax_t *delaymsec, *error, *rdelayprob, *rfailprob, *wdelayprob, *wfailprob; | ||||
const char *name; | const char *name; | ||||
char param[16]; | char param[16]; | ||||
int i, *nargs; | int i, *nargs; | ||||
g_topology_assert(); | g_topology_assert(); | ||||
nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); | nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); | ||||
if (nargs == NULL) { | if (nargs == NULL) { | ||||
Show All 23 Lines | if (wfailprob == NULL) { | ||||
gctl_error(req, "No '%s' argument", "wfailprob"); | gctl_error(req, "No '%s' argument", "wfailprob"); | ||||
return; | return; | ||||
} | } | ||||
if (*wfailprob < -1 || *wfailprob > 100) { | if (*wfailprob < -1 || *wfailprob > 100) { | ||||
gctl_error(req, "Invalid '%s' argument", "wfailprob"); | gctl_error(req, "Invalid '%s' argument", "wfailprob"); | ||||
return; | return; | ||||
} | } | ||||
delaymsec = gctl_get_paraml(req, "delaymsec", sizeof(*delaymsec)); | |||||
if (delaymsec == NULL) { | |||||
gctl_error(req, "No '%s' argument", "delaymsec"); | |||||
return; | |||||
} | |||||
if (*delaymsec < 1 && *delaymsec != -1) { | |||||
gctl_error(req, "Invalid '%s' argument", "delaymsec"); | |||||
return; | |||||
} | |||||
rdelayprob = gctl_get_paraml(req, "rdelayprob", sizeof(*rdelayprob)); | |||||
if (rdelayprob == NULL) { | |||||
gctl_error(req, "No '%s' argument", "rdelayprob"); | |||||
return; | |||||
} | |||||
if (*rdelayprob < -1 || *rdelayprob > 100) { | |||||
gctl_error(req, "Invalid '%s' argument", "rdelayprob"); | |||||
return; | |||||
} | |||||
wdelayprob = gctl_get_paraml(req, "wdelayprob", sizeof(*wdelayprob)); | |||||
if (wdelayprob == NULL) { | |||||
gctl_error(req, "No '%s' argument", "wdelayprob"); | |||||
return; | |||||
} | |||||
if (*wdelayprob < -1 || *wdelayprob > 100) { | |||||
gctl_error(req, "Invalid '%s' argument", "wdelayprob"); | |||||
return; | |||||
} | |||||
for (i = 0; i < *nargs; i++) { | for (i = 0; i < *nargs; i++) { | ||||
snprintf(param, sizeof(param), "arg%d", i); | snprintf(param, sizeof(param), "arg%d", i); | ||||
name = gctl_get_asciiparam(req, param); | name = gctl_get_asciiparam(req, param); | ||||
if (name == NULL) { | if (name == NULL) { | ||||
gctl_error(req, "No 'arg%d' argument", i); | gctl_error(req, "No 'arg%d' argument", i); | ||||
return; | return; | ||||
} | } | ||||
if (strncmp(name, "/dev/", strlen("/dev/")) == 0) | if (strncmp(name, "/dev/", strlen("/dev/")) == 0) | ||||
name += strlen("/dev/"); | name += strlen("/dev/"); | ||||
pp = g_provider_by_name(name); | pp = g_provider_by_name(name); | ||||
if (pp == NULL || pp->geom->class != mp) { | if (pp == NULL || pp->geom->class != mp) { | ||||
G_NOP_DEBUG(1, "Provider %s is invalid.", name); | G_NOP_DEBUG(1, "Provider %s is invalid.", name); | ||||
gctl_error(req, "Provider %s is invalid.", name); | gctl_error(req, "Provider %s is invalid.", name); | ||||
return; | return; | ||||
} | } | ||||
sc = pp->geom->softc; | sc = pp->geom->softc; | ||||
if (*error != -1) | if (*error != -1) | ||||
sc->sc_error = (int)*error; | sc->sc_error = (int)*error; | ||||
if (*rfailprob != -1) | if (*rfailprob != -1) | ||||
sc->sc_rfailprob = (u_int)*rfailprob; | sc->sc_rfailprob = (u_int)*rfailprob; | ||||
if (*wfailprob != -1) | if (*wfailprob != -1) | ||||
sc->sc_wfailprob = (u_int)*wfailprob; | sc->sc_wfailprob = (u_int)*wfailprob; | ||||
if (*rdelayprob != -1) | |||||
sc->sc_rdelayprob = (u_int)*rdelayprob; | |||||
if (*wdelayprob != -1) | |||||
sc->sc_wdelayprob = (u_int)*wdelayprob; | |||||
if (*delaymsec != -1) | |||||
sc->sc_delaymsec = (u_int)*delaymsec; | |||||
} | } | ||||
} | } | ||||
static struct g_geom * | static struct g_geom * | ||||
g_nop_find_geom(struct g_class *mp, const char *name) | g_nop_find_geom(struct g_class *mp, const char *name) | ||||
{ | { | ||||
struct g_geom *gp; | struct g_geom *gp; | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | if (pp != NULL || cp != NULL) | ||||
return; | return; | ||||
sc = gp->softc; | sc = gp->softc; | ||||
sbuf_printf(sb, "%s<Offset>%jd</Offset>\n", indent, | sbuf_printf(sb, "%s<Offset>%jd</Offset>\n", indent, | ||||
(intmax_t)sc->sc_offset); | (intmax_t)sc->sc_offset); | ||||
sbuf_printf(sb, "%s<ReadFailProb>%u</ReadFailProb>\n", indent, | sbuf_printf(sb, "%s<ReadFailProb>%u</ReadFailProb>\n", indent, | ||||
sc->sc_rfailprob); | sc->sc_rfailprob); | ||||
sbuf_printf(sb, "%s<WriteFailProb>%u</WriteFailProb>\n", indent, | sbuf_printf(sb, "%s<WriteFailProb>%u</WriteFailProb>\n", indent, | ||||
sc->sc_wfailprob); | sc->sc_wfailprob); | ||||
sbuf_printf(sb, "%s<ReadDelayedProb>%u</ReadDelayedProb>\n", indent, | |||||
sc->sc_rdelayprob); | |||||
sbuf_printf(sb, "%s<WriteDelayedProb>%u</WriteDelayedProb>\n", indent, | |||||
sc->sc_wdelayprob); | |||||
sbuf_printf(sb, "%s<Delay>%d</Delay>\n", indent, sc->sc_delaymsec); | |||||
sbuf_printf(sb, "%s<Error>%d</Error>\n", indent, sc->sc_error); | sbuf_printf(sb, "%s<Error>%d</Error>\n", indent, sc->sc_error); | ||||
sbuf_printf(sb, "%s<Reads>%ju</Reads>\n", indent, sc->sc_reads); | 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<Writes>%ju</Writes>\n", indent, sc->sc_writes); | ||||
sbuf_printf(sb, "%s<Deletes>%ju</Deletes>\n", indent, sc->sc_deletes); | sbuf_printf(sb, "%s<Deletes>%ju</Deletes>\n", indent, sc->sc_deletes); | ||||
sbuf_printf(sb, "%s<Getattrs>%ju</Getattrs>\n", indent, sc->sc_getattrs); | sbuf_printf(sb, "%s<Getattrs>%ju</Getattrs>\n", indent, sc->sc_getattrs); | ||||
sbuf_printf(sb, "%s<Flushes>%ju</Flushes>\n", indent, sc->sc_flushes); | sbuf_printf(sb, "%s<Flushes>%ju</Flushes>\n", indent, sc->sc_flushes); | ||||
sbuf_printf(sb, "%s<Cmd0s>%ju</Cmd0s>\n", indent, sc->sc_cmd0s); | sbuf_printf(sb, "%s<Cmd0s>%ju</Cmd0s>\n", indent, sc->sc_cmd0s); | ||||
sbuf_printf(sb, "%s<Cmd1s>%ju</Cmd1s>\n", indent, sc->sc_cmd1s); | sbuf_printf(sb, "%s<Cmd1s>%ju</Cmd1s>\n", indent, sc->sc_cmd1s); | ||||
Show All 9 Lines |
Shouldn't we just pass the I/O through without delays in this case?