feat(resize-data): expand data partition to fill disk on first boot#8
feat(resize-data): expand data partition to fill disk on first boot#8JoergZeidler wants to merge 23 commits into
Conversation
The scaffold tests only verify that detect() is reachable with and without a bootloader. A TODO block documents what the full matrix must cover once the first non-Normal variant lands, so the tests do not quietly stay green without expansion. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
- BootContext doc: trimmed to essential pre-conditions - BootMode/detect: removed PR-version scaffolding, kept variant hints - mode test block: removed future-variant TODO - lib.rs: removed single_match scaffolding comment - omnect_device_service.rs: removed 'legacy bash' phrasing from doc - grub.rs: removed 'matches legacy behaviour' from inline comments - types.rs: removed 'legacy bash script encoding' phrasing - boot_sequence.rs: removed 'Legacy bash never runs' phrasing - project-context.md: added planned BootMode variants (§8) + doc standards (§9) Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
…t_remaining Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
- Remove forward-scaffolding sentence from mount_remaining_partitions docstring about resize_data_if_needed - Rename FSCK_LOG_DIR to FSCK_LOG_SUBDIR and compose path from mount_points::DATA_PARTITION - Remove what-narrating comments (mount factory, mount data) - Simplify mount_core_partitions docstring to not enumerate partitions - Add safety comments to TempDir::new().unwrap() calls in tests Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
- Add src/mode/resize_data.rs with resize_if_needed, partition_number, find_extended_partition, ensure_mtab, run_e2fsck, run_cmd - Register pub mod resize_data in src/mode/mod.rs (cfg resize-data) - Add BootloaderEnvKey::ResizedData variant to src/bootloader/mod.rs (guards omnect_resized_data env var used to run exactly once) - GPT: moves backup header before resizepart (sgdisk -e) - DOS: resizes extended container before logical data partition Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
- Add NonUtf8Path error variant to ResizeDataError for non-UTF-8 device paths
- Replace all unwrap_or("") path conversions with proper error propagation
- Move PartitionName import to top-level use block
- Extract parse_extended_partition_nr helper; tests call real parsing logic
- Fix trailing space in run_cmd log when args is empty
- Update ensure_mtab docstring to be more accurate
- Add justification comment to _rootfs parameter
Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
…rmal Call resize_if_needed (feature-gated) before mounting data, then mount_remaining_partitions with deferred propagation so persist_fsck_results always runs regardless of mount outcome. Remove #[allow(dead_code)] from layout field now that it is actively used. resize_if_needed now takes &mut Option<Box<dyn Bootloader>> rather than Option<&mut dyn Bootloader> to avoid the NLL drop-check extending the borrow to the owner's destructor. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
resize-data is implemented as a first-boot step within Normal, not a separate boot mode. The placeholder comment was misleading. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
- Mark resize-data as implemented in README feature table - Remove data partition auto-resize from "not yet implemented" list - Add resize-data test combinations to README and project-context - Add resize_data.rs to module structure in project-context - Add resize-data to feature flags table in project-context - Remove Resize BootMode variant from planned features (resize runs as a first-boot step within Normal, not as a separate boot mode) Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
JanZachmann
left a comment
There was a problem hiding this comment.
Code review of the resize-data feature. Functionally sound and well-isolated behind the feature flag. The two items I would block on are the cert/factory mount-order change (intentional? please document) and the redundant .map_err(InitramfsError::ResizeData) calls (cleanup, since #[from] already does the conversion). Other comments are minor style/test-coverage items. See inline.
- Restore factory → cert mount order in mount_remaining_partitions - Remove redundant .map_err(); use ? with #[from] ResizeDataError - Fix module doc-comment: use actual env key omnect_resized_data - Remove unused _rootfs parameter from resize_if_needed - Hoist CLI argument literals to named constants - Add one-shot guard tests and ensure_mtab branch tests - Remove duplicated // safe: TempDir::new() comments in tests Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
…ests Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
JanZachmann
left a comment
There was a problem hiding this comment.
All 8 review findings addressed. Verified at f50a030:
- factory → cert mount order restored ✓
- module doc-comment uses
omnect_resized_data✓ _rootfsparameter removed (signature + caller inmode/normal.rs) ✓- redundant
.map_err(InitramfsError::ResizeData)removed throughout — bare?via#[from]✓ - CLI literals hoisted to
SGDISK_MOVE_BACKUP_HEADER,PARTED_RESIZEPART,PARTED_RESIZE_FULL,PARTED_PRINT,E2FSCK_FIX,RESIZE2FS_FORCE✓ - one-shot guard tests added with
MockBootloader✓ - 6× duplicated
safe: TempDircomments removed ✓
cargo test clean across all four resize-data feature combinations (grub,gpt,resize-data, grub,dos,resize-data, uboot,gpt,resize-data, uboot,dos,resize-data).
One non-blocking follow-up note left on the ensure_mtab thread — the new tests there don't actually call ensure_mtab(). Approving since that finding was originally optional and the function itself is correct.
Extract ensure_mtab_at(mtab, target) so tests can pass controlled paths. Thin ensure_mtab() wrapper supplies the production consts. Update tests to actually invoke ensure_mtab_at() instead of re-implementing the logic inline. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
|
|
||
| /// Mount all required partitions in the correct order. | ||
| pub fn mount_partitions( | ||
| /// Mount the core partitions required before the bootloader can be created. |
There was a problem hiding this comment.
that reads funny: the bootloader loaded kernel and the kernel loaded omnect-os-init.
the init process will not create a bootloader. please ask your agent for renaming options.
There was a problem hiding this comment.
AI answer to choose the correct method name.
The function constructs a Box<dyn Bootloader> — a Rust object that reads/writes the bootloader
environment (grubenv file or U-Boot fw_printenv/fw_setenv). It does not create a bootloader.
Naming options:
| Name | Notes |
|---|---|
open_bootloader_env() |
Most precise — it opens the env storage |
init_bootloader() |
Common systems pattern, slightly ambiguous |
bootloader_env() |
Short noun-form factory |
platform_bootloader() |
Emphasizes the build-time selection |
Recommendation: open_bootloader_env() — directly describes what happens and aligns with the
existing BootloaderEnvKey / get_env / set_env naming in the codebase. Call site reads naturally:
let bootloader_opt = match open_bootloader_env() { ... }open_bootloader_env sounds good to me. Documentation will be updated after finalize the method name.
There was a problem hiding this comment.
changed to open_bootloader_env...
| ], | ||
| )?; | ||
|
|
||
| // resize2fs requires a valid mtab entry; create a symlink to /proc/self/mounts |
There was a problem hiding this comment.
why wouldn't it exist. what was the reasoning for that? imho very unlikely it isn't there. please ask your agent.
not a change request, though.
There was a problem hiding this comment.
AI answer:
In initramfs we're running before switch_root. The initramfs root is a minimal tmpfs/ramfs — /etc/mtab is not part of it. The real rootfs (where /etc/mtab
lives as a symlink to /proc/self/mounts) hasn't been switched to yet. resize2fs reads /etc/mtab to check whether the device is currently mounted; without
it, the check silently degrades or errors. The guard creates the symlink on first run so resize2fs can do its mount-state check correctly.
| Ok(bl) => Some(bl), | ||
| Err(e) => { | ||
| warn!("Bootloader unavailable: {e}; fsck results will not be persisted"); | ||
| warn!("Bootloader unavailable: {e}; ODS update-validation will be skipped"); |
There was a problem hiding this comment.
imho that warning makes no sense. we don't want to skip update-validation. imho that is not a warning its an unrecoverable error. you probably even don't have a valid root then. if not now, then at least at the next boot.
also the naming "Bootloader" is not good.
There was a problem hiding this comment.
in case we have no access to the bootloader environment, we have no idea about performing update-validation or not. Should we stay in init process, or reboot the device, or try to boot the rootfs.
There was a problem hiding this comment.
warning message is changed
| let mount_result = mount_partitions(&layout, rootfs, &mut ods_status); | ||
| mount_core_partitions(&layout, rootfs, &mut ods_status)?; | ||
|
|
||
| // Best-effort: a corrupted grubenv is a recoverable degraded-boot condition. |
There was a problem hiding this comment.
why does it comment that for grubenv only? ... this is not the grub path, correct? its for all implementations of bootloader environment.
There was a problem hiding this comment.
that's true, comment changed.
| } | ||
|
|
||
| #[test] | ||
| fn test_ensure_mtab_creates_symlink_when_missing() { |
There was a problem hiding this comment.
3 tests for the mtab handling, which is most probably not necessary.
There was a problem hiding this comment.
mtab currently used. the parameterized helper exists and the tests are real — removing them would decrease coverage with no code benefit.
| /// e2fsck exit code 1 means "errors were corrected" — that is a success | ||
| /// outcome for our purposes; we just need the filesystem to be consistent | ||
| /// before resize2fs runs. | ||
| fn run_e2fsck(dev: &Path) -> ResizeResult<()> { |
There was a problem hiding this comment.
this feels like code duplication. why can't you reuse the available fsck implementation? in case errors where corrected, you have no fsck result.
There was a problem hiding this comment.
crate::filesystem::fsck implementation records CORRECTED as a distinct state in the bootloader
environment and requires a bootloader reference.
Here we need neither, this is a transient pre-resize check with no persistent result.
| } = ctx; | ||
|
|
||
| #[cfg(feature = "resize-data")] | ||
| crate::mode::resize_data::resize_if_needed(layout, &mut bootloader)?; |
There was a problem hiding this comment.
so modes are not mutual exclusive?
why is the resizing part of the "normal" bootmode? what is a bootmode which is not normal then?
There was a problem hiding this comment.
resize-data is a transparent first-boot operation that runs during normal boot. New boot-mode will be present in features factory-reset/flash-mode...
| pub enum BootMode { | ||
| Normal, | ||
| // FactoryReset(FactoryResetConfig) | ||
| // Resize |
There was a problem hiding this comment.
so wie only have normal bootmode?
There was a problem hiding this comment.
yes, now we have only normal mode, resize-data is part during first-boot in normal mode. Next feature factory-reset will be added as own mode.
| @@ -0,0 +1,417 @@ | |||
| //! Data partition auto-resize | |||
There was a problem hiding this comment.
why is that in the mode dir?
it seems it didn't get a mode, as suggested by the previous PR.
There was a problem hiding this comment.
resize_data.rs is in mode/ because it was designed alongside the boot-mode dispatch architecture. Since resize is not a BootMode variant, a case could be made for moving it to filesystem/ or a standalone resize/ module. However, it uses Bootloader and PartitionLayout the same way mode handlers do — and future modes (factory-reset) follow the same pattern.
boot_sequence.rs: doc comment on mount_core_partitions no longer scopes the ordering requirement to GRUB only — the function runs on all builds. lib.rs: grubenv → bootloader environment in degraded-boot comment; inline comment retains GRUB-specific parenthetical as explanation. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
The function opens the platform bootloader environment interface; it does not create a bootloader. The new name aligns with the existing get_env / set_env / BootloaderEnvKey naming in the codebase. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
…v rename Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
Rephrase the degraded-boot comment to say 'unavailable' rather than 'corrupted' (the cause may be anything), and remove the inline list of skipped subsystems from the warning message — the message is already self-describing via the 'booting in degraded mode' suffix. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
The stubs for FactoryReset and FlashMode are added by their respective feature branches. Remove them here to reduce noise. Signed-off-by: Joerg Zeidler <62105035+JoergZeidler@users.noreply.github.com>
Summary
resize-dataCargo feature that expands the datapartition and its ext4 filesystem to fill available disk space on first
boot, guarded by the
resized-databootloader environment variable soit runs exactly once.
mount_partitionsintomount_core_partitions(rootfs + boot)and
mount_remaining_partitions(factory / cert / etc / data) so thebootloader can be created after boot is mounted but before the data
partition is touched.
src/mode/resize_data.rswith GPT (sgdisk -e) and DOS(extended partition resize via
parted) branches selected atcompile time via
#[cfg(feature = "gpt|dos")].mode::normal::run, calledbefore
mount_remaining_partitions.Reason
When an omnect OS image is flashed to a disk larger than the image itself
the data partition occupies only the space baked into the image; the
remaining disk space is wasted unless the partition and its filesystem are
expanded on first boot. This ports and integrates the existing
resize_databranch implementation into thefeat/boot-mode-dispatcharchitecture.
Verification
All eight feature combinations pass:
Spec/Plan
Used Spec:
2026-05-04-resize-data-design.md
Used Plan:
2026-05-04-resize-data.md