Skip to content

repart: Let systemd-repart size the generated root partition - #2532

Draft
LorbusChris wants to merge 3 commits into
bootc-dev:mainfrom
LorbusChris:repart-root-size-systemd-262
Draft

LorbusChris wants to merge 3 commits into
bootc-dev:mainfrom
LorbusChris:repart-root-size-systemd-262

Conversation

@LorbusChris

@LorbusChris LorbusChris commented Oct 2, 2026 •

Copy link
Copy Markdown

With systemd 262, bootc install to-disk fails for images whose repart.d definitions have no root partition, unless --root-size is given: systemd-repart now reports the free space as padding of the last partition (systemd 959c3286d00f), and the root size bootc derives from its dry run underflows.

This plans root with a second dry run of all definitions plus an unsized root definition, and pins it to the size systemd-repart plans for it. Root then shares free space by Weight= with any other definition that can grow. A generic image's install creates only root, the ESP and BIOS boot, so the latter two are pinned to their planned sizes as well, with drop-ins, keeping the space planned for the partitions created on first boot.

Two prep commits come first. Generated definitions now go to a temporary directory that systemd-repart reads through --definitions=, with the priority of /run/repart.d, instead of into /run/repart.d itself, which may be the host's in to-disk. An image definition named 50-root.conf, which would mask the generated one or be masked by it, is refused.

Testing

  • Unit tests, and a new variant of the repart tmt test with a growable ESP.
  • Replays of the flow on sparse images with systemd 252, 257, 259 and 262: generic install, simulated first boot, and non-generic install, leaving /run/repart.d untouched.
  • make validate passes, and each commit builds and passes the lib unit tests.
  • Upstream CI does not run systemd 262 yet. plan-52-install-repart fails on the Fedora 45 and rawhide legs of composefs: Install systemd-boot via bootupd to keep shim in boot path #2512 without this.

Generated-by: AI

I am familiar with the bootc concepts and have prior experience building atomic OS images. I am however not familiar with this codebase and used AI to generate these code changes.

@github-actions github-actions Bot added area/install Issues related to `bootc install` area/documentation Updates to the documentation labels Oct 2, 2026
@bootc-bot
bootc-bot Bot requested a review from jeckersb October 2, 2026 20:56
@LorbusChris
LorbusChris force-pushed the repart-root-size-systemd-262 branch from 4af0967 to a6966f8 Compare October 2, 2026 21:20
@cgwalters

Copy link
Copy Markdown
Collaborator

Thank you for testing bootc's development stream! Obviously #2314 just landed and this issue perhaps argues for disabling it by default for at least a cycle...

With systemd 262, bootc install to-disk fails for images whose repart.d definitions have no root partition, unless --root-size is given:

Thanks. I thought we covered this, but now that I re-read #2314 we didn't add tests for this.

@cgwalters cgwalters left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking yet

const REPART_FILTERED_DEFINITIONS_DIR: &str = "/tmp/repart.d";

/// The repart.d directory for definitions generated at runtime.
const REPART_RUNTIME_DIR: &str = "/run/repart.d";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should actually be careful here, I think in to-disk we may end up using the host's /run and we really absolutely should not touch any global state in /run (what if the host OS is using /run/repart.d)

I think the simplest thing to do here is for us to create a tempdir and overmount that dir if it exists - we're always in a mountns.

It's possible we could use --definitions to override, but that feels like it would involve a good bit more changes here.

#[serde(default)]
raw_size: u64,
#[serde(default)]
raw_padding: u64,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't we add this for something like c9s compatibility? Why are you dropping it?

Comment thread crates/lib/src/install/baseline.rs Outdated
Comment on lines +365 to +368
match root.raw_size / MIB {
0 => anyhow::bail!("systemd-repart planned less than 1 MiB for the root partition"),
size_mib => Ok(size_mib),
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More elegant to use NonZeroU64

Comment thread crates/lib/src/install/baseline.rs Outdated
Comment on lines +383 to +386
let name = Path::new(&p.file)
.file_name()
.and_then(OsStr::to_str)
.ok_or_else(|| anyhow::anyhow!("Invalid repart.d definition path {}", p.file))?;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pre-existing but if we require utf8 we should probably make p.file a Utf8PathBuf or so.

Here you could try converting to Utf8Path (borrowed) then get the anme from that

When the image's repart.d definitions have no root partition, bootc
wrote one to /run/repart.d/50-root.conf for systemd-repart. In `bootc
install to-disk`, /run may be the host's, where bootc must not change
any state. The file was also left behind, so a later install from the
same environment took it for one of the image's definitions and reused
the previous root size.

Write it to a temporary directory instead, which systemd-repart reads
through --definitions= along with the standard directories, with the
priority of /run/repart.d. Prep for the next commits, which generate
more definitions.

Generated-by: AI
Signed-off-by: Christian Glombek <c.glombek@cosa.systems>
bootc only generates its root definition, 50-root.conf, when the image's
repart.d definitions have no root partition, so a definition of the
image with that name is for some other partition. systemd-repart reads
only one of two same-named definitions: the generated one, read with the
priority of /run/repart.d, masks one in /run/repart.d,
/usr/local/lib/repart.d or /usr/lib/repart.d, whose partition then
silently goes missing from the layout, and one in /etc/repart.d masks
it.

Fail with an error that names the definition instead.

Generated-by: AI
Signed-off-by: Christian Glombek <c.glombek@cosa.systems>
With systemd 262, `bootc install to-disk` fails for images whose
repart.d definitions have no root partition, unless --root-size is
given: systemd-repart now reports the free space as padding of the last
partition (systemd 959c3286d00f), and the root size bootc derives from
its dry run underflows.

Plan root with a second dry run of all definitions plus an unsized root
definition, and pin it to the size systemd-repart plans for it. Root
then shares free space by Weight= with any other definition that can
grow. A generic image's install creates only root, the ESP and BIOS
boot, so pin the latter two to their planned sizes as well, with
drop-ins, keeping the space planned for the partitions created on first
boot.

Generated-by: AI
Signed-off-by: Christian Glombek <c.glombek@cosa.systems>
@LorbusChris
LorbusChris force-pushed the repart-root-size-systemd-262 branch from a6966f8 to 5f0864c Compare October 2, 2026 23:03

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/documentation Updates to the documentation area/install Issues related to `bootc install`

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants