mkimg: Add per-partition alignment

This adds a "%align" field to partition specifications, resulting in
the start of a partition being shifted to the next aligned position.
When both :offset and %align are used, a relative offset is treated as
a minimum value, while an unaligned absolute offset is an error.

Reviewed by:	imp (earlier version)
MFC after:	1 week
Sponsored by:	Amazon
Differential Revision:	https://reviews.freebsd.org/D60450
This commit is contained in:
Colin Percival committed 2026-10-21 12:42:43 -07:00
1 parent e7f84fe6cf
commit 729883c93e
1 file changed
+50 -12
+50 -12
View File
@@ -178,13 +178,15 @@ usage(const char *why)
print_schemes(1);
fputc('\n', stderr);
fprintf(stderr, " partition specification:\n");
fprintf(stderr, "\t<type>[/<label>]::<size>[:[+]<offset>]\t- "
"empty partition of given size and\n\t\t\t\t\t"
" optional relative or absolute offset\n");
fprintf(stderr, "\t<type>[/<label>]:=<file>[:[+]offset]\t- partition "
"content and size are\n\t\t\t\t\t"
" determined by the named file and\n"
"\t\t\t\t\t optional relative or absolute offset\n");
fprintf(stderr, "\t<type>[/<label>]::<size>[:[+]<offset>][%%<align>]\n"
"\t\t\t\t\t- empty partition of given size and\n"
"\t\t\t\t\t optional relative or absolute offset\n"
"\t\t\t\t\t and alignment\n");
fprintf(stderr, "\t<type>[/<label>]:=<file>[:[+]<offset>][%%<align>]\n"
"\t\t\t\t\t- partition content and size are\n"
"\t\t\t\t\t determined by the named file and\n"
"\t\t\t\t\t optional relative or absolute offset\n"
"\t\t\t\t\t and alignment\n");
fprintf(stderr, "\t<type>[/<label>]:-<cmd>\t\t- partition content and size "
"are taken\n\t\t\t\t\t from the output of the command to run\n");
fprintf(stderr, "\t-\t\t\t\t- unused partition entry\n");
@@ -448,9 +450,9 @@ mkimg(void)
struct part *part;
struct stat sb;
char *p;
lba_t block, blkoffset;
uint64_t bytesize, byteoffset;
char *size, *offset;
lba_t block, blkoffset, blkalign;
uint64_t bytesize, byteoffset, bytealign;
char *size, *offset, *align;
bool abs_offset;
int error, fd;
@@ -466,10 +468,16 @@ mkimg(void)
TAILQ_FOREACH(part, &partlist, link) {
byteoffset = blkoffset = 0;
abs_offset = false;
align = NULL;
/* Look for an offset. Set size too if we can. */
switch (part->kind) {
case PART_KIND_SIZE:
p = strrchr(part->contents, '%');
if (p != NULL) {
*p = '\0';
align = p + 1;
}
offset = part->contents;
size = strsep(&offset, ":");
if (expand_number(size, &bytesize) == -1)
@@ -477,6 +485,13 @@ mkimg(void)
break;
case PART_KIND_FILE:
size = part->contents;
if (stat(part->contents, &sb) == -1) {
p = strrchr(part->contents, '%');
if (p != NULL) {
*p = '\0';
align = p + 1;
}
}
if (stat(part->contents, &sb) == 0) {
if (S_ISDIR(sb.st_mode)) {
errc(EX_IOERR, EISDIR, "partition %d",
@@ -498,6 +513,18 @@ mkimg(void)
break;
}
if (align != NULL) {
if (expand_number(align, &bytealign) == -1)
err(EX_DATAERR, "partition %d",
part->index + 1);
if ((bytealign == 0) || (bytealign % secsz != 0))
errx(EX_DATAERR, "partition %d: "
"invalid alignment", part->index + 1);
blkalign = bytealign / secsz;
} else {
blkalign = 1;
}
if (offset != NULL) {
if (*offset != '+')
abs_offset = true;
@@ -509,12 +536,17 @@ mkimg(void)
/* Work out exactly where the partition starts. */
blkoffset = (byteoffset + secsz - 1) / secsz;
if (abs_offset)
if (abs_offset) {
block = scheme_metadata(SCHEME_META_PART_ABSOLUTE,
blkoffset);
else
if (block % blkalign)
errx(EX_DATAERR, "partition %d: absolute "
"offset incompatible with alignment",
part->index + 1);
} else
block = scheme_metadata(SCHEME_META_PART_BEFORE,
block + blkoffset);
block = ((block + blkalign - 1) / blkalign) * blkalign;
part->block = block;
if (verbose)
@@ -559,6 +591,12 @@ mkimg(void)
(long long)byteoffset,
(long long)blkoffset);
}
if (blkalign > 1) {
fprintf(stderr,
" alignment %llu bytes (%llu blocks)\n",
(long long)bytealign,
(long long)blkalign);
}
}
block = scheme_metadata(SCHEME_META_PART_AFTER,
part->block + part->size);