Rough implementation of the create and add verbs. The verbs cause

in-memory changes only and as such are only useful for prototyping
and regression testing purposes.
This commit is contained in:
Marcel Moolenaar 2005-10-09 17:10:35 +00:00
parent 1030a78a12
commit ada6a4d2b7
2 changed files with 355 additions and 44 deletions

View File

@ -117,6 +117,170 @@ static struct uuid g_gpt_unused = GPT_ENT_TYPE_UNUSED;
* Support functions.
*/
static void g_gpt_wither(struct g_geom *, int);
static struct g_provider *
g_gpt_ctl_add(struct gctl_req *req, struct g_geom *gp, struct uuid *type,
uint64_t start, uint64_t end)
{
struct g_provider *pp;
struct g_gpt_softc *softc;
struct g_gpt_part *last, *part;
int idx;
G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
g_topology_assert();
pp = LIST_FIRST(&gp->consumer)->provider;
softc = gp->softc;
last = NULL;
idx = 0;
LIST_FOREACH(part, &softc->parts, parts) {
if (part->index == idx) {
idx = part->index + 1;
last = part;
}
/* XXX test for overlap */
}
part = g_malloc(sizeof(struct g_gpt_part), M_WAITOK | M_ZERO);
part->index = idx;
part->offset = start * pp->sectorsize;
if (last == NULL)
LIST_INSERT_HEAD(&softc->parts, part, parts);
else
LIST_INSERT_AFTER(last, part, parts);
part->ent.ent_type = *type;
kern_uuidgen(&part->ent.ent_uuid, 1);
part->ent.ent_lba_start = start;
part->ent.ent_lba_end = end;
/* XXX ent_attr */
/* XXX ent_name */
part->provider = g_new_providerf(gp, "%s%c%d", gp->name,
!memcmp(type, &g_gpt_freebsd, sizeof(struct uuid)) ? 's' : 'p',
idx + 1);
part->provider->index = idx;
part->provider->private = part; /* Close the circle. */
part->provider->mediasize = (end - start + 1) * pp->sectorsize;
part->provider->sectorsize = pp->sectorsize;
part->provider->flags = pp->flags & G_PF_CANDELETE;
if (pp->stripesize > 0) {
part->provider->stripesize = pp->stripesize;
part->provider->stripeoffset =
(pp->stripeoffset + part->offset) % pp->stripesize;
}
g_error_provider(part->provider, 0);
if (bootverbose) {
printf("GEOM: %s: partition ", part->provider->name);
printf_uuid(&part->ent.ent_uuid);
printf(".\n");
}
return (part->provider);
}
static struct g_geom *
g_gpt_ctl_create(struct gctl_req *req, struct g_class *mp,
struct g_provider *pp, uint32_t entries)
{
struct uuid uuid;
struct g_consumer *cp;
struct g_geom *gp;
struct g_gpt_softc *softc;
struct gpt_hdr *hdr;
uint64_t last;
size_t tblsz;
int error, i;
G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name));
g_topology_assert();
tblsz = (entries * sizeof(struct gpt_ent) + pp->sectorsize - 1) /
pp->sectorsize;
/*
* Sanity-check the size of the provider. This test is very similar
* to the one in g_gpt_taste(). Here we want to make sure that the
* size of the provider is large enough to hold a GPT that has the
* requested number of entries, plus as many available sectors for
* partitions of minimal size. The latter test is not exactly needed
* but it helps keep the table size proportional to the media size.
* Thus, a GPT with 128 entries must at least have 128 sectors of
* usable partition space. Therefore, the absolute minimal size we
* allow is (1 + 2 * (1 + 32) + 128) = 195 sectors. This is more
* restrictive than what g_gpt_taste() requires.
*/
if (pp->sectorsize < 512 ||
pp->sectorsize % sizeof(struct gpt_ent) != 0 ||
pp->mediasize < (3 + 2 * tblsz + entries) * pp->sectorsize) {
gctl_error(req, "%d provider", ENOSPC);
return (NULL);
}
/* We don't nest. See also g_gpt_taste(). */
if (pp->geom->class == &g_gpt_class) {
gctl_error(req, "%d provider", ENODEV);
return (NULL);
}
/* Create a GEOM. */
gp = g_new_geomf(mp, "%s", pp->name);
softc = g_malloc(sizeof(struct g_gpt_softc), M_WAITOK | M_ZERO);
gp->softc = softc;
LIST_INIT(&softc->parts);
cp = g_new_consumer(gp);
error = g_attach(cp, pp);
if (error == 0)
error = g_access(cp, 1, 0, 0);
if (error != 0) {
g_gpt_wither(gp, error);
gctl_error(req, "%d geom '%s'", error, pp->name);
return (NULL);
}
last = (pp->mediasize / pp->sectorsize) - 1;
kern_uuidgen(&uuid, 1);
/* Construct an in-memory GPT. */
for (i = GPT_HDR_PRIMARY; i < GPT_HDR_COUNT; i++) {
hdr = softc->hdr + i;
bcopy(GPT_HDR_SIG, hdr->hdr_sig, sizeof(hdr->hdr_sig));
hdr->hdr_revision = GPT_HDR_REVISION;
hdr->hdr_size = offsetof(struct gpt_hdr, padding);
hdr->hdr_lba_self = (i == GPT_HDR_PRIMARY) ? 1 : last;
hdr->hdr_lba_alt = (i == GPT_HDR_PRIMARY) ? last : 1;
hdr->hdr_lba_start = 2 + tblsz;
hdr->hdr_lba_end = last - (1 + tblsz);
hdr->hdr_uuid = uuid;
hdr->hdr_lba_table = (i == GPT_HDR_PRIMARY) ? 2 : last - tblsz;
hdr->hdr_entries = entries;
hdr->hdr_entsz = sizeof(struct gpt_ent);
softc->state[i] = GPT_HDR_OK;
}
if (0)
goto fail;
if (bootverbose) {
printf("GEOM: %s: GPT ", pp->name);
printf_uuid(&softc->hdr[GPT_HDR_PRIMARY].hdr_uuid);
printf(".\n");
}
g_access(cp, -1, 0, 0);
return (gp);
fail:
g_access(cp, -1, 0, 0);
g_gpt_wither(gp, error);
gctl_error(req, "%d geom '%s'", error, pp->name);
return (NULL);
}
static int
g_gpt_has_pmbr(struct g_consumer *cp, int *error)
{
@ -391,7 +555,132 @@ g_gpt_wither(struct g_geom *gp, int error)
static void
g_gpt_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb)
{
/* XXX todo */
struct uuid type;
struct g_geom *gp;
struct g_provider *pp;
struct g_gpt_softc *softc;
char const *s;
uint64_t start, end;
long entries;
int error;
G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb));
g_topology_assert();
if (!strcmp(verb, "add")) {
/*
* Add a partition entry to a GPT.
* Required parameters/attributes:
* geom
* type
* start
* end
* Optional parameters/attributes:
* label
*/
s = gctl_get_asciiparam(req, "geom");
if (s == NULL) {
gctl_error(req, "%d geom", ENOATTR);
return;
}
/* Get the GPT geom with the given name. */
LIST_FOREACH(gp, &mp->geom, geom) {
if (!strcmp(s, gp->name))
break;
}
if (gp == NULL) {
gctl_error(req, "%d geom '%s'", EINVAL, s);
return;
}
softc = gp->softc;
if (softc->state[GPT_HDR_PRIMARY] != GPT_HDR_OK ||
softc->state[GPT_HDR_SECONDARY] != GPT_HDR_OK) {
gctl_error(req, "%d geom '%s'", ENXIO, s);
return;
}
s = gctl_get_asciiparam(req, "type");
if (s == NULL) {
gctl_error(req, "%d type", ENOATTR);
return;
}
error = parse_uuid(s, &type);
if (error != 0) {
gctl_error(req, "%d type '%s'", error, s);
return;
}
s = gctl_get_asciiparam(req, "start");
if (s == NULL) {
gctl_error(req, "%d start", ENOATTR);
return;
}
start = strtoq(s, (char **)(uintptr_t)&s, 0);
if (start < softc->hdr[GPT_HDR_PRIMARY].hdr_lba_start ||
start > softc->hdr[GPT_HDR_PRIMARY].hdr_lba_end ||
*s != '\0') {
gctl_error(req, "%d start %jd", EINVAL,
(intmax_t)start);
return;
}
s = gctl_get_asciiparam(req, "end");
if (s == NULL) {
gctl_error(req, "%d end", ENOATTR);
return;
}
end = strtoq(s, (char **)(uintptr_t)&s, 0);
if (end < start ||
end > softc->hdr[GPT_HDR_PRIMARY].hdr_lba_end ||
*s != '\0') {
gctl_error(req, "%d end %jd", EINVAL,
(intmax_t)end);
return;
}
pp = g_gpt_ctl_add(req, gp, &type, start, end);
} else if (!strcmp(verb, "create")) {
/*
* Create a GPT on a pristine disk-like provider.
* Required parameters/attributes:
* provider
* Optional parameters/attributes:
* entries
*/
s = gctl_get_asciiparam(req, "provider");
if (s == NULL) {
gctl_error(req, "%d provider", ENOATTR);
return;
}
pp = g_provider_by_name(s);
if (pp == NULL) {
gctl_error(req, "%d provider '%s'", EINVAL, s);
return;
}
/* Check that there isn't already a GPT on the provider. */
LIST_FOREACH(gp, &mp->geom, geom) {
if (!strcmp(s, gp->name)) {
gctl_error(req, "%d geom '%s'", EEXIST, s);
return;
}
}
s = gctl_get_asciiparam(req, "entries");
if (s != NULL) {
entries = strtol(s, (char **)(uintptr_t)&s, 0);
if (entries < 128 || *s != '\0') {
gctl_error(req, "%d entries %ld", EINVAL,
entries);
return;
}
} else
entries = 128; /* Documented mininum */
gp = g_gpt_ctl_create(req, mp, pp, entries);
} else if (!strcmp(verb, "destroy")) {
/* Destroy a GPT completely. */
} else if (!strcmp(verb, "modify")) {
/* Modify a partition entry. */
} else if (!strcmp(verb, "recover")) {
/* Recover a downgraded GPT. */
} else if (!strcmp(verb, "remove")) {
/* Remove a partition entry from a GPT. */
} else
gctl_error(req, "%d verb '%s'", EINVAL, verb);
}
static int
@ -400,7 +689,6 @@ g_gpt_destroy_geom(struct gctl_req *req, struct g_class *mp,
{
G_GPT_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name));
g_topology_assert();
g_gpt_wither(gp, EINVAL);

View File

@ -35,39 +35,53 @@ my $disk = "/tmp/disk-$$";
my $unit = "";
my %steps = (
"1" => "gctl",
"2" => "gctl",
"3" => "gctl",
"4" => "gctl",
"5" => "mdcfg",
"6" => "gctl",
"7" => "gctl",
"8" => "gctl",
"9" => "mdcfg",
);
my %args = (
"1" => "",
"2" => "verb=invalid",
"3" => "verb=create",
"4" => "verb=create provider=invalid",
"5" => "create",
"6" => "verb=create provider=md%unit% entries=-1",
"7" => "verb=create provider=md%unit%",
"8" => "verb=create provider=md%unit%",
"9" => "destroy",
"000" => "gctl",
"001" => "gctl verb=bogus",
"010" => "gctl verb=create",
"011" => "gctl verb=create provider=bogus",
"020" => "mdcfg create pristine",
"021" => "gctl verb=create provider=md%unit% entries=-1",
"022" => "gctl verb=create provider=md%unit% entries=128",
"023" => "gctl verb=create provider=md%unit%",
"024" => "conf",
"030" => "gctl verb=add",
"031" => "gctl verb=add geom=bogus",
"032" => "gctl verb=add geom=md%unit%",
"033" => "gctl verb=add geom=md%unit% type=bogus",
"034" => "gctl verb=add geom=md%unit% type=ed0101b0-2a71-11da-ba81-003048416ace",
"035" => "gctl verb=add geom=md%unit% type=ed0101b0-2a71-11da-ba81-003048416ace start=1",
"036" => "gctl verb=add geom=md%unit% type=ed0101b0-2a71-11da-ba81-003048416ace start=34",
"037" => "gctl verb=add geom=md%unit% type=ed0101b0-2a71-11da-ba81-003048416ace start=34 end=12345678",
"038" => "gctl verb=add geom=md%unit% type=ed0101b0-2a71-11da-ba81-003048416ace start=34 end=546",
"100" => "mdcfg destroy",
"110" => "mdcfg create corrupted",
"111" => "gctl verb=add geom=md%unit%",
"120" => "mdcfg destroy",
);
my %result = (
"1" => "FAIL Verb missing",
"2" => "FAIL 22 verb 'invalid'",
"3" => "FAIL 87 provider",
"4" => "FAIL 22 provider 'invalid'",
#
"6" => "FAIL 22 entries -1",
"7" => "PASS",
"8" => "FAIL 17 geom 'md0'",
#
"000" => "FAIL Verb missing",
"001" => "FAIL 22 verb 'bogus'",
"010" => "FAIL 87 provider",
"011" => "FAIL 22 provider 'bogus'",
"020" => "",
"021" => "FAIL 22 entries -1",
"022" => "PASS",
"023" => "FAIL 17 geom 'md%unit%'",
"024" => "",
"030" => "FAIL 87 geom",
"031" => "FAIL 22 geom 'bogus'",
"032" => "FAIL 87 type",
"033" => "FAIL 22 type 'bogus'",
"034" => "FAIL 87 start",
"035" => "FAIL 22 start 1",
"036" => "FAIL 87 end",
"037" => "FAIL 22 end 12345678",
"038" => "PASS",
"100" => "",
"110" => "",
"111" => "FAIL 6 geom 'md%unit%'",
"120" => "",
);
my $verbose = "";
@ -92,33 +106,42 @@ if (`$cmd` =~ "^FAIL Permission denied") {
$count = keys (%steps);
print "1..$count\n";
foreach my $nr (sort keys %steps) {
my $action = $steps{$nr};
my $arg = $args{$nr};
my $nr = 1;
foreach my $key (sort keys %steps) {
my ($action, $args) = split(/ /, $steps{$key}, 2);
$args = "" if (not defined $args);
if ($action =~ "gctl") {
$arg =~ s/%unit%/$unit/g;
system("$cmd $verbose $arg | tee $out 2>&1");
$args =~ s/%unit%/$unit/g;
system("$cmd $verbose $args | tee $out 2>&1");
$st = `tail -1 $out`;
if ($st =~ "^$result{$nr}") {
print "ok $nr\n";
my $res = $result{$key};
$res =~ s/%unit%/$unit/g;
if ($st =~ "^$res") {
print "ok $nr \# gctl($key)\n";
} else {
print "not ok $nr \# $st\n";
print "not ok $nr \# gctl($key) - $st\n";
}
unlink $out;
} elsif ($action =~ "mdcfg") {
if ($arg =~ "create") {
if ($args =~ "create") {
system("dd if=/dev/zero of=$disk count=1024 2>&1");
if ($args =~ "corrupted") {
system("gpt create -p $disk");
}
$unit = `mdconfig -a -t vnode -f $disk`;
chomp $unit;
$unit =~ s/md//g;
} elsif ($arg =~ "destroy") {
} elsif ($args =~ "destroy") {
system("mdconfig -d -u $unit");
unlink $disk;
$unit = "";
}
print "ok $nr\n";
print "ok $nr \# mdcfg($key)\n";
} elsif ($action =~ "conf") {
`sysctl -b kern.geom.confxml 2>&1`;
print "ok $nr \# conf($key)\n";
}
$nr += 1;
}
unlink $cmd;