Changeset View
Changeset View
Standalone View
Standalone View
head/sys/geom/nop/g_nop.c
/*- | /*- | ||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD | ||||
* | * | ||||
* Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> | * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> | ||||
* Copyright (c) 2019 Mariusz Zaborski <oshogbo@FreeBSD.org> | |||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
Show All 12 Lines | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/ctype.h> | |||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/bio.h> | #include <sys/bio.h> | ||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
Show All 35 Lines | |||||
}; | }; | ||||
struct g_nop_delay { | struct g_nop_delay { | ||||
struct callout dl_cal; | struct callout dl_cal; | ||||
struct bio *dl_bio; | struct bio *dl_bio; | ||||
TAILQ_ENTRY(g_nop_delay) dl_next; | TAILQ_ENTRY(g_nop_delay) dl_next; | ||||
}; | }; | ||||
static bool | |||||
g_nop_verify_nprefix(const char *name) | |||||
{ | |||||
int i; | |||||
for (i = 0; i < strlen(name); i++) { | |||||
if (isalpha(name[i]) == 0 && isdigit(name[i]) == 0) { | |||||
return (false); | |||||
} | |||||
} | |||||
return (true); | |||||
} | |||||
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 215 Lines • ▼ Show 20 Lines | g_nop_access(struct g_provider *pp, int dr, int dw, int de) | ||||
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 count_until_fail, u_int rfailprob, u_int wfailprob, | const char *gnopname, int ioerror, u_int count_until_fail, | ||||
u_int delaymsec, u_int rdelayprob, u_int wdelayprob, off_t offset, | u_int rfailprob, u_int wfailprob, u_int delaymsec, u_int rdelayprob, | ||||
off_t size, u_int secsize, off_t stripesize, off_t stripeoffset, | u_int wdelayprob, off_t offset, off_t size, u_int secsize, off_t stripesize, | ||||
const char *physpath) | 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, n; | ||||
off_t explicitsize; | off_t explicitsize; | ||||
g_topology_assert(); | g_topology_assert(); | ||||
gp = NULL; | gp = NULL; | ||||
newpp = NULL; | newpp = NULL; | ||||
cp = NULL; | cp = NULL; | ||||
Show All 34 Lines | g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, | ||||
if ((stripeoffset % pp->sectorsize) != 0) { | if ((stripeoffset % pp->sectorsize) != 0) { | ||||
gctl_error(req, "Invalid stripeoffset for provider %s.", pp->name); | gctl_error(req, "Invalid stripeoffset for provider %s.", pp->name); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
if (stripesize != 0 && stripeoffset >= stripesize) { | if (stripesize != 0 && stripeoffset >= stripesize) { | ||||
gctl_error(req, "stripeoffset is too big."); | gctl_error(req, "stripeoffset is too big."); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
snprintf(name, sizeof(name), "%s%s", pp->name, G_NOP_SUFFIX); | if (gnopname != NULL && !g_nop_verify_nprefix(gnopname)) { | ||||
gctl_error(req, "Name %s is invalid.", gnopname); | |||||
return (EINVAL); | |||||
} | |||||
if (gnopname != NULL) { | |||||
n = snprintf(name, sizeof(name), "%s%s", gnopname, | |||||
G_NOP_SUFFIX); | |||||
} else { | |||||
n = snprintf(name, sizeof(name), "%s%s", pp->name, | |||||
G_NOP_SUFFIX); | |||||
} | |||||
if (n <= 0 || n >= sizeof(name)) { | |||||
gctl_error(req, "Invalid provider name."); | |||||
return (EINVAL); | |||||
} | |||||
LIST_FOREACH(gp, &mp->geom, geom) { | LIST_FOREACH(gp, &mp->geom, geom) { | ||||
if (strcmp(gp->name, name) == 0) { | if (strcmp(gp->name, name) == 0) { | ||||
gctl_error(req, "Provider %s already exists.", name); | gctl_error(req, "Provider %s already exists.", name); | ||||
return (EEXIST); | return (EEXIST); | ||||
} | } | ||||
} | } | ||||
gp = g_new_geomf(mp, "%s", name); | gp = g_new_geomf(mp, "%s", name); | ||||
sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); | sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | |||||
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 *val, error, rfailprob, wfailprob, count_until_fail, offset, | intmax_t *val, error, rfailprob, wfailprob, count_until_fail, offset, | ||||
secsize, size, stripesize, stripeoffset, delaymsec, | secsize, size, stripesize, stripeoffset, delaymsec, | ||||
rdelayprob, wdelayprob; | rdelayprob, wdelayprob; | ||||
const char *name, *physpath; | const char *name, *physpath, *gnopname; | ||||
char param[16]; | char param[16]; | ||||
int i, *nargs; | int i, *nargs; | ||||
g_topology_assert(); | g_topology_assert(); | ||||
error = -1; | error = -1; | ||||
rfailprob = -1; | rfailprob = -1; | ||||
wfailprob = -1; | wfailprob = -1; | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | if (val != NULL) { | ||||
stripeoffset = *val; | stripeoffset = *val; | ||||
if (stripeoffset < 0) { | if (stripeoffset < 0) { | ||||
gctl_error(req, "Invalid '%s' argument", | gctl_error(req, "Invalid '%s' argument", | ||||
"stripeoffset"); | "stripeoffset"); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
physpath = gctl_get_asciiparam(req, "physpath"); | physpath = gctl_get_asciiparam(req, "physpath"); | ||||
gnopname = gctl_get_asciiparam(req, "gnopname"); | |||||
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) { | 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, | ||||
gnopname, | |||||
error == -1 ? EIO : (int)error, | error == -1 ? EIO : (int)error, | ||||
count_until_fail == -1 ? 0 : (u_int)count_until_fail, | count_until_fail == -1 ? 0 : (u_int)count_until_fail, | ||||
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, | delaymsec == -1 ? 1 : (u_int)delaymsec, | ||||
rdelayprob == -1 ? 0 : (u_int)rdelayprob, | rdelayprob == -1 ? 0 : (u_int)rdelayprob, | ||||
wdelayprob == -1 ? 0 : (u_int)wdelayprob, | wdelayprob == -1 ? 0 : (u_int)wdelayprob, | ||||
(off_t)offset, (off_t)size, (u_int)secsize, | (off_t)offset, (off_t)size, (u_int)secsize, | ||||
▲ Show 20 Lines • Show All 303 Lines • Show Last 20 Lines |