summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/geom/geom_gpt.c292
-rw-r--r--tools/regression/geom_gpt/gctl.t107
2 files changed, 355 insertions, 44 deletions
diff --git a/sys/geom/geom_gpt.c b/sys/geom/geom_gpt.c
index a437984..e6a52a8 100644
--- a/sys/geom/geom_gpt.c
+++ b/sys/geom/geom_gpt.c
@@ -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);
diff --git a/tools/regression/geom_gpt/gctl.t b/tools/regression/geom_gpt/gctl.t
index c369026..615f198 100644
--- a/tools/regression/geom_gpt/gctl.t
+++ b/tools/regression/geom_gpt/gctl.t
@@ -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;
OpenPOWER on IntegriCloud