From d9711c28efc4ec89ba5ea11f8fd63e9d0a7fc81b Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Tue, 3 May 2011 07:33:39 +0000 Subject: [PATCH] Add "-a alignment" option to gpart(8). When it specified gpart(8) tries to align partition start offset and size to be multiple of alignment value. MFC after: 2 weeks --- sbin/geom/class/part/geom_part.c | 93 +++++++++++++++++++++++--------- sbin/geom/class/part/gpart.8 | 33 ++++++++++-- 2 files changed, 99 insertions(+), 27 deletions(-) diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c index 8593d20891c0..ed7b8f830cc7 100644 --- a/sbin/geom/class/part/geom_part.c +++ b/sbin/geom/class/part/geom_part.c @@ -93,6 +93,7 @@ static void gpart_restore(struct gctl_req *, unsigned int); struct g_command PUBSYM(class_commands)[] = { { "add", 0, gpart_issue, { + { 'a', "alignment", GPART_AUTOFILL, G_TYPE_STRING }, { 'b', "start", GPART_AUTOFILL, G_TYPE_STRING }, { 's', "size", GPART_AUTOFILL, G_TYPE_STRING }, { 't', "type", NULL, G_TYPE_STRING }, @@ -100,7 +101,8 @@ struct g_command PUBSYM(class_commands)[] = { { 'l', "label", G_VAL_OPTIONAL, G_TYPE_STRING }, { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, G_OPT_SENTINEL }, - "[-b start] [-s size] -t type [-i index] [-l label] [-f flags] geom" + "[-a alignment] [-b start] [-s size] -t type [-i index] " + "[-l label] [-f flags] geom" }, { "backup", 0, gpart_backup, G_NULL_OPTS, "geom" @@ -168,11 +170,12 @@ struct g_command PUBSYM(class_commands)[] = { "-a attrib -i index [-f flags] geom" }, { "resize", 0, gpart_issue, { + { 'a', "alignment", GPART_AUTOFILL, G_TYPE_STRING }, { 's', "size", GPART_AUTOFILL, G_TYPE_STRING }, { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER }, { 'f', "flags", GPART_FLAGS, G_TYPE_STRING }, G_OPT_SENTINEL }, - "[-s size] -i index [-f flags] geom" + "[-a alignment] [-s size] -i index [-f flags] geom" }, { "restore", 0, gpart_restore, { { 'F', "force", NULL, G_TYPE_BOOL }, @@ -298,6 +301,9 @@ fmtattrib(struct gprovider *pp) return (buf); } +#define ALIGNDOWN(d, a) (-(a) & (d)) +#define ALIGNUP(d, a) (-(-(a) & -(d))) + static int gpart_autofill_resize(struct gctl_req *req) { @@ -306,7 +312,7 @@ gpart_autofill_resize(struct gctl_req *req) struct ggeom *gp; struct gprovider *pp; off_t last, size, start, new_size; - off_t lba, new_lba; + off_t lba, new_lba, alignment; const char *s; int error, idx; @@ -333,6 +339,19 @@ gpart_autofill_resize(struct gctl_req *req) if (pp == NULL) errx(EXIT_FAILURE, "Provider for geom %s not found.", s); + s = gctl_get_ascii(req, "alignment"); + alignment = 1; + if (*s != '*') { + error = g_parse_lba(s, pp->lg_sectorsize, &alignment); + if (error) + errc(EXIT_FAILURE, error, "Invalid alignment param"); + if (alignment == 0) + errx(EXIT_FAILURE, "Invalid alignment param"); + } + error = gctl_delete_param(req, "alignment"); + if (error) + errc(EXIT_FAILURE, error, "internal error"); + s = gctl_get_ascii(req, "size"); if (*s == '*') new_size = 0; @@ -341,10 +360,14 @@ gpart_autofill_resize(struct gctl_req *req) if (error) errc(EXIT_FAILURE, error, "Invalid size param"); /* no autofill necessary. */ - goto done; + if (alignment == 1) + goto done; + if (new_size > alignment) + new_size = ALIGNDOWN(new_size, alignment); } last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0); + last = ALIGNDOWN(last, alignment); LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { s = find_provcfg(pp, "index"); if (s == NULL) @@ -376,7 +399,7 @@ gpart_autofill_resize(struct gctl_req *req) size = lba - start; pp = find_provider(gp, lba); if (pp == NULL) - new_size = last - start + 1; + new_size = ALIGNDOWN(last - start + 1, alignment); else { s = find_provcfg(pp, "start"); if (s == NULL) { @@ -389,6 +412,7 @@ gpart_autofill_resize(struct gctl_req *req) * Is there any free space between current and * next providers? */ + new_lba = ALIGNUP(new_lba, alignment); if (new_lba > lba) new_size = new_lba - start; else { @@ -410,12 +434,12 @@ gpart_autofill(struct gctl_req *req) struct gclass *cp; struct ggeom *gp; struct gprovider *pp; - off_t first, last; - off_t size, start; - off_t lba, len; + off_t first, last, a_first; + off_t size, start, a_lba; + off_t lba, len, alignment; uintmax_t grade; const char *s; - int error, has_size, has_start; + int error, has_size, has_start, has_alignment; s = gctl_get_ascii(req, "verb"); if (strcmp(s, "resize") == 0) @@ -442,6 +466,20 @@ gpart_autofill(struct gctl_req *req) if (pp == NULL) errx(EXIT_FAILURE, "Provider for geom %s not found.", s); + s = gctl_get_ascii(req, "alignment"); + has_alignment = (*s == '*') ? 0 : 1; + alignment = 1; + if (has_alignment) { + error = g_parse_lba(s, pp->lg_sectorsize, &alignment); + if (error) + errc(EXIT_FAILURE, error, "Invalid alignment param"); + if (alignment == 0) + errx(EXIT_FAILURE, "Invalid alignment param"); + } + error = gctl_delete_param(req, "alignment"); + if (error) + errc(EXIT_FAILURE, error, "internal error"); + s = gctl_get_ascii(req, "size"); has_size = (*s == '*') ? 0 : 1; size = 0; @@ -449,6 +487,8 @@ gpart_autofill(struct gctl_req *req) error = g_parse_lba(s, pp->lg_sectorsize, &size); if (error) errc(EXIT_FAILURE, error, "Invalid size param"); + if (size > alignment) + size = ALIGNDOWN(size, alignment); } s = gctl_get_ascii(req, "start"); @@ -458,15 +498,18 @@ gpart_autofill(struct gctl_req *req) error = g_parse_lba(s, pp->lg_sectorsize, &start); if (error) errc(EXIT_FAILURE, error, "Invalid start param"); + start = ALIGNUP(start, alignment); } /* No autofill necessary. */ - if (has_size && has_start) + if (has_size && has_start && !has_alignment) goto done; first = (off_t)strtoimax(find_geomcfg(gp, "first"), NULL, 0); last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0); grade = ~0ULL; + a_first = ALIGNUP(first, alignment); + last = ALIGNDOWN(last, alignment); while ((pp = find_provider(gp, first)) != NULL) { s = find_provcfg(pp, "start"); if (s == NULL) { @@ -475,23 +518,24 @@ gpart_autofill(struct gctl_req *req) } else lba = (off_t)strtoimax(s, NULL, 0); - if (first < lba) { + a_lba = ALIGNDOWN(lba, alignment); + if (first < a_lba && a_first < a_lba) { /* Free space [first, lba> */ - len = lba - first; + len = a_lba - a_first; if (has_size) { if (len >= size && (uintmax_t)(len - size) < grade) { - start = first; + start = a_first; grade = len - size; } } else if (has_start) { - if (start >= first && start < lba) { - size = lba - start; - grade = start - first; + if (start >= a_first && start < a_lba) { + size = a_lba - start; + grade = start - a_first; } } else { if (grade == ~0ULL || len > size) { - start = first; + start = a_first; size = len; grade = 0; } @@ -505,24 +549,25 @@ gpart_autofill(struct gctl_req *req) (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize; } else first = (off_t)strtoimax(s, NULL, 0) + 1; + a_first = ALIGNUP(first, alignment); } - if (first <= last) { + if (a_first <= last) { /* Free space [first-last] */ - len = last - first + 1; + len = ALIGNDOWN(last - a_first + 1, alignment); if (has_size) { if (len >= size && (uintmax_t)(len - size) < grade) { - start = first; + start = a_first; grade = len - size; } } else if (has_start) { - if (start >= first && start <= last) { - size = last - start + 1; - grade = start - first; + if (start >= a_first && start <= last) { + size = ALIGNDOWN(last - start + 1, alignment); + grade = start - a_first; } } else { if (grade == ~0ULL || len > size) { - start = first; + start = a_first; size = len; grade = 0; } diff --git a/sbin/geom/class/part/gpart.8 b/sbin/geom/class/part/gpart.8 index 51b1af5cba51..436a1a041712 100644 --- a/sbin/geom/class/part/gpart.8 +++ b/sbin/geom/class/part/gpart.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 12, 2011 +.Dd May 03, 2011 .Dt GPART 8 .Os .Sh NAME @@ -91,6 +91,7 @@ utility: .Nm .Cm add .Fl t Ar type +.Op Fl a Ar alignment .Op Fl b Ar start .Op Fl s Ar size .Op Fl i Ar index @@ -148,6 +149,7 @@ utility: .Nm .Cm resize .Fl i Ar index +.Op Fl a Ar alignment .Op Fl s Ar size .Op Fl f Ar flags .Ar geom @@ -209,7 +211,17 @@ Partition types are discussed below in the section entitled .Sx "PARTITION TYPES" . .Pp Additional options include: -.Bl -tag -width 10n +.Bl -tag -width 12n +.It Fl a Ar alignment +If specified, then +.Nm +utility tries to align +.Ar start +offset and partition +.Ar size +to be multiple of +.Ar alignment +value. .It Fl i Ar index The index in the partition table at which the new partition is to be placed. @@ -416,7 +428,15 @@ to maximum available from given geom .Ar geom . .Pp Additional options include: -.Bl -tag -width 10n +.Bl -tag -width 12n +.It Fl a Ar alignment +If specified, then +.Nm +utility tries to align partition +.Ar size +to be multiple of +.Ar alignment +value. .It Fl f Ar flags Additional operational flags. See the section entitled @@ -834,6 +854,13 @@ partition that would contain UFS where the system boots from. /sbin/gpart add -s 512M -t freebsd-ufs da0 .Ed .Pp +Create a 15GB-sized +.Cm freebsd-ufs +partition that would contain UFS and aligned on 4KB boundaries: +.Bd -literal -offset indent +/sbin/gpart add -s 15G -t freebsd-ufs -a 4k da0 +.Ed +.Pp After having created all required partitions, embed bootstrap code into them. .Bd -literal -offset indent /sbin/gpart bootcode -p /boot/boot1 da0