svn commit: r223880 - stable/8/sbin/geom/class/part

Andrey V. Elsukov ae at FreeBSD.org
Sat Jul 9 12:02:42 UTC 2011


Author: ae
Date: Sat Jul  9 12:02:40 2011
New Revision: 223880
URL: http://svn.freebsd.org/changeset/base/223880

Log:
  MFC r221363,221967,222263,222264,222630,222631,222819,223158,223355:
  
  r221363:
    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.
  
  r221967:
    Some partitioning schemes want to have partitions that are aligned
    with geometry. And they do recalculation of user specified parameters.
    MBR, PC98, VTOC8, EBR schemes are doing that. For these schemes an
    auto alignment feature (ie. gpart add -a alignment) would not work.
    But it can work for GPT and BSD schemes. BSD scheme usualy is created
    inside MBR, so we can use knowledge about offset of MBR partition to
    calculate aligned values for BSD partitions.
  
    Use "offset" attribute of the parent provider for better alignment.
  
  r222263:
    Fix calculation of alignment for odd values. Also do not change value
    when it is already aligned.
  
  r222264:
    Simplify ALIGNDOWN macro.
  
  r222630:
    Use stripesize and stripeoffset in the automatic calculation of
    partition offsets. If user requests specific alignment and
    provider's stripesize is not zero, then use a least common multiple
    from the stripesize and user specified value.
    Also fix "gpart resize" implementation: do not try to align the partition
    size, because the start offset may be not aligned. Instead align the
    end offset and then calculate size. Also use stripesize and stripeoffset
    for "gpart resize" command.
  
  r222631:
    Always use LCM when stripesize > 0.
  
  r222819:
    Do not use LCM from stripesize and user specified alignment value.
    When user wants have specific alignment - do what user wants.
    Use stripesize as alignment value in case, when some of gpart's
    arguments are ommitted for automatic calculation.
  
    Suggested by:	mav
  
  r223158:
    Add "alignment" param to the request before calling gpart_autofill().
  
  r223355:
    The "size" param needs no adjusting to stripeoffset.
  
    Reported by:	Kris Moore

Modified:
  stable/8/sbin/geom/class/part/geom_part.c
  stable/8/sbin/geom/class/part/gpart.8
Directory Properties:
  stable/8/sbin/geom/class/part/   (props changed)

Modified: stable/8/sbin/geom/class/part/geom_part.c
==============================================================================
--- stable/8/sbin/geom/class/part/geom_part.c	Sat Jul  9 11:22:23 2011	(r223879)
+++ stable/8/sbin/geom/class/part/geom_part.c	Sat Jul  9 12:02:40 2011	(r223880)
@@ -94,6 +94,7 @@ static void gpart_restore(struct gctl_re
 
 struct g_command PUBSYM(class_commands)[] = {
 	{ "add", 0, gpart_issue, {
+		{ 'a', "alignment", autofill, G_TYPE_STRING },
 		{ 'b', "start", autofill, G_TYPE_STRING },
 		{ 's', "size", autofill, G_TYPE_STRING },
 		{ 't', "type", NULL, G_TYPE_STRING },
@@ -164,6 +165,7 @@ struct g_command PUBSYM(class_commands)[
 	  "geom", NULL
 	},
 	{ "resize", 0, gpart_issue, {
+		{ 'a', "alignment", autofill, G_TYPE_STRING },
 		{ 's', "size", autofill, G_TYPE_STRING },
 		{ 'i', index_param, NULL, G_TYPE_ASCNUM },
 		{ 'f', "flags", flags, G_TYPE_STRING },
@@ -294,6 +296,9 @@ fmtattrib(struct gprovider *pp)
 	return (buf);
 }
 
+#define	ALIGNDOWN(d, a)	((d) - (d) % (a))
+#define	ALIGNUP(d, a)	((d) % (a) ? (d) - (d) % (a) + (a): (d))
+
 static int
 gpart_autofill_resize(struct gctl_req *req)
 {
@@ -302,7 +307,7 @@ gpart_autofill_resize(struct gctl_req *r
 	struct ggeom *gp;
 	struct gprovider *pp;
 	off_t last, size, start, new_size;
-	off_t lba, new_lba;
+	off_t lba, new_lba, alignment, offset;
 	const char *s;
 	char *val;
 	int error, idx;
@@ -331,6 +336,23 @@ gpart_autofill_resize(struct gctl_req *r
 	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");
+	} else {
+		lba = pp->lg_stripesize / pp->lg_sectorsize;
+		if (lba > 0)
+			alignment = lba;
+	}
+	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;
@@ -339,9 +361,11 @@ gpart_autofill_resize(struct gctl_req *r
 		if (error)
 			errc(EXIT_FAILURE, error, "Invalid size param");
 		/* no autofill necessary. */
-		goto done;
+		if (alignment == 1)
+			goto done;
 	}
 
+	offset = pp->lg_stripeoffset / pp->lg_sectorsize;
 	last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0);
 	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
 		s = find_provcfg(pp, "index");
@@ -362,20 +386,28 @@ gpart_autofill_resize(struct gctl_req *r
 	s = find_provcfg(pp, "end");
 	if (s == NULL) {
 		s = find_provcfg(pp, "length");
-		lba = start +
+		lba = start - 1 +
 		    (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize;
 	} else
-		lba = (off_t)strtoimax(s, NULL, 0) + 1;
+		lba = (off_t)strtoimax(s, NULL, 0);
+	size = lba - start + 1;
 
-	if (lba > last) {
-		geom_deletetree(&mesh);
-		return (ENOSPC);
+	if (new_size > 0 && new_size <= size) {
+		/* The start offset may be not aligned, so we align the end
+		 * offset and then calculate the size.
+		 */
+		new_size = ALIGNDOWN(start + offset + new_size,
+		    alignment) - start - offset;
+		goto done;
 	}
-	size = lba - start;
-	pp = find_provider(gp, lba);
-	if (pp == NULL)
-		new_size = last - start + 1;
-	else {
+
+	pp = find_provider(gp, lba + 1);
+	if (pp == NULL) {
+		new_size = ALIGNDOWN(last + offset + 1, alignment) -
+		    start - offset;
+		if (new_size < size)
+			return (ENOSPC);
+	} else {
 		s = find_provcfg(pp, "start");
 		if (s == NULL) {
 			s = find_provcfg(pp, "offset");
@@ -387,6 +419,7 @@ gpart_autofill_resize(struct gctl_req *r
 		 * Is there any free space between current and
 		 * next providers?
 		 */
+		new_lba = ALIGNDOWN(new_lba + offset, alignment) - offset;
 		if (new_lba > lba)
 			new_size = new_lba - start;
 		else {
@@ -408,12 +441,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, offset;
 	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)
@@ -440,6 +473,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;
@@ -459,12 +506,24 @@ gpart_autofill(struct gctl_req *req)
 	}
 
 	/* No autofill necessary. */
-	if (has_size && has_start)
+	if (has_size && has_start && !has_alignment)
 		goto done;
 
+	len = pp->lg_stripesize / pp->lg_sectorsize;
+	if (len > 0 && !has_alignment)
+		alignment = len;
+
+	/* Adjust parameters to stripeoffset */
+	offset = pp->lg_stripeoffset / pp->lg_sectorsize;
+	start = ALIGNUP(start + offset, alignment);
+	if (size > alignment)
+		size = ALIGNDOWN(size, alignment);
+
 	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 + offset, alignment);
+	last = ALIGNDOWN(last + offset, alignment);
 	while ((pp = find_provider(gp, first)) != NULL) {
 		s = find_provcfg(pp, "start");
 		if (s == NULL) {
@@ -473,23 +532,24 @@ gpart_autofill(struct gctl_req *req)
 		} else
 			lba = (off_t)strtoimax(s, NULL, 0);
 
-		if (first < lba) {
+		a_lba = ALIGNDOWN(lba + offset, 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;
 				}
@@ -503,35 +563,35 @@ 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 + offset, 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;
 			}
 		}
 	}
-
 	if (grade == ~0ULL) {
 		geom_deletetree(&mesh);
 		return (ENOSPC);
 	}
-
+	start -= offset;	/* Return back to real offset */
 done:
 	snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)size);
 	gctl_change_param(req, "size", -1, ssize);
@@ -907,6 +967,7 @@ gpart_restore(struct gctl_req *req, unsi
 			gctl_ro_param(r, "size", -1, argv[3]);
 			if (rl != 0 && label != NULL)
 				gctl_ro_param(r, "label", -1, argv[4]);
+			gctl_ro_param(r, "alignment", -1, autofill);
 			gctl_ro_param(r, "geom", -1, s);
 			error = gpart_autofill(r);
 			if (error != 0)

Modified: stable/8/sbin/geom/class/part/gpart.8
==============================================================================
--- stable/8/sbin/geom/class/part/gpart.8	Sat Jul  9 11:22:23 2011	(r223879)
+++ stable/8/sbin/geom/class/part/gpart.8	Sat Jul  9 12:02:40 2011	(r223880)
@@ -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 t
 .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
@@ -833,6 +853,13 @@ partition that would contain UFS where t
 /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


More information about the svn-src-stable mailing list