repart: add FixedOffsetBytes= to pin a partition at an explicit disk offset#42418
repart: add FixedOffsetBytes= to pin a partition at an explicit disk offset#42418naraghavan2186 wants to merge 1 commit into
Conversation
|
Tested the change with the below repart configs As per the output first-lba: 64 - GPT header now advertises sector 64 as the first usable LBA, down from the hardcoded 2048. disk.img1 : start=64, size=512 - uboot at exactly sector 64 (32768 bytes), 512 sectors = 256KB. No grain-size rounding applied. disk.img2 : start=576, size=131072 - root starts at sector 576. uboot ends at sector 64 + 512 = 576 |
5f953b5 to
f3ac519
Compare
|
please mark the review items you have addressed as "resolved". in systemd we generally want that the reviewer opens the items, and the PR owener then closes them after addressing them. just leave the ones open that reuqire further discussion |
f3ac519 to
fba0d83
Compare
fba0d83 to
bba8ded
Compare
bba8ded to
f61f3be
Compare
f61f3be to
cc27f61
Compare
cc27f61 to
a3b5ebe
Compare
…offset There are certain use cases require a partition to start at a specific byte offset rather than being placed automatically by the allocation algorithm. Add FixedOffsetBytes= to repart.conf to support this so that the partition is placed at the exact configured offset without grain-size rounding, and the GPT first_usable_lba is lowered to accommodate offsets below the default 2048-sector boundary. SizeMinBytes= is optional when set it is used to reserve the exact space for the fixed region, otherwise the grain size is used as a conservative minimum. Auto-placed partitions and --grain-size= are unaffected.
a3b5ebe to
0cb5cf3
Compare
| p->definition_path, p->fixed_offset, | ||
| sym_fdisk_get_first_lba(context->fdisk_context) * context->sector_size); | ||
|
|
||
| p->offset = p->fixed_offset; |
There was a problem hiding this comment.
Claude: must-fix: On an existing (non-from-scratch) disk a new fixed-offset partition is pinned here (p->offset = p->fixed_offset) with no check that [fixed_offset, fixed_offset+new_size) is clear of existing on-disk partitions; context_scan_fixed_partitions() only validates fixed-vs-fixed overlap and the disk bounds. Two consequences:
-
Data loss. In
context_write_partition_table()the destructive steps —context_wipe_and_discard()(blkid wipe + BLKDISCARD),context_copy_blocks(),context_mkfs()— all run atp->offsetbeforecontext_mangle_partitions()callsfdisk_add_partition(), which is the only place an overlap is rejected. So when a fixed offset overlaps an existing partition, that partition is wiped/discarded/overwritten and only then is the GPT write refused — the data is already gone. This refutes the earlier dismissal thatfdisk_add_partition()returning an error makes overlap safe. The below-first-usable-LBA case is worse: it only logs "adding it will likely fail, proceeding anyway" and proceeds into the same destructive path. -
Overlap with auto-placed partitions. Only the leading free area is clipped by
context->start = fixed_end_aligned; free areas built from an existing partition's trailing padding are not bounded by the fixed region, and fixed partitions never consume free-area budget, so a fixed offset landing inside such a gap is assigned the same range as an auto-placed partition.
Validate each fixed offset+size against existing partition extents (and refuse the below-first-usable-LBA case) before any wipe, and exclude the fixed region from every free area, not just the leading one.
|
|
||
| if (parsed == 0) | ||
| return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), | ||
| "FixedOffsetBytes= must not be zero."); |
There was a problem hiding this comment.
Claude: suggestion: config_parse_offset_bytes() rejects only parsed == 0, but parse_size() accepts the literal 18446744073709551615 and returns exactly UINT64_MAX — which is the in-band "auto-placed" sentinel for p->fixed_offset (set in partition_new() and tested everywhere as == UINT64_MAX). Such an assignment is silently accepted and the partition is then treated as having no fixed offset at all, with no diagnostic and none of the downstream alignment/bounds checks ever running on it. Reject parsed == UINT64_MAX alongside the existing zero check so the sentinel value cannot be produced from input.
| else | ||
| p->new_size = partition_min_size(context, p); | ||
| } | ||
| if (p->new_padding == UINT64_MAX) |
There was a problem hiding this comment.
Claude: suggestion: For fixed-offset new partitions this branch unconditionally sets new_padding = 0, so any PaddingMinBytes=/PaddingMaxBytes= the user configured is silently discarded (auto-placed partitions honor them via partition_min_padding()), and context_scan_fixed_partitions() reserves only [fixed_offset, fixed_offset+size) with no room for padding. A fixed-offset partition with PaddingMinBytes= set is accepted but its padding is neither applied nor reserved. Either reject PaddingMinBytes=/PaddingMaxBytes= combined with FixedOffsetBytes= in partition_read_definition() (mirroring the Priority=/SupplementFor= guards), or honor and reserve the padding.
| /* Verify the fixed offset is within the GPT's usable range. For from scratch | ||
| * disks this is guaranteed (we lowered first_lba to match). For existing disks | ||
| * it may not be, producing a error from libfdisk later otherwise. */ | ||
| if (p->fixed_offset < sym_fdisk_get_first_lba(context->fdisk_context) * context->sector_size) |
There was a problem hiding this comment.
Claude: nit: sym_fdisk_get_first_lba(context->fdisk_context) * context->sector_size is computed twice in a row — in this if condition and again in the log_warning() arguments just below. Hoist it into a single local (e.g. uint64_t first_usable = …;) and reuse it, as the identical expression is evaluated once at the other call sites.
There are certain use cases require a partition to start at a specific byte offset rather than being placed automatically by the allocation algorithm. Add FixedOffsetBytes= to repart.con to support this so that the partition is placed at the exact configured offset without grain-size rounding, and the GPT first_usable_lba is lowered to accommodate offsets below the default 2048-sector boundary. SizeMinBytes= must be set alongside it since there is no free area to grow into. Auto-placed partitions and --grain-size= are unaffected.
Fixes 40907