Skip to content

install: Initialize separately mounted /var filesystems from the image - #2521

Draft
jmarrero wants to merge 3 commits into
bootc-dev:mainfrom
jmarrero:mount-empty-var
Draft

jmarrero wants to merge 3 commits into
bootc-dev:mainfrom
jmarrero:mount-empty-var

Conversation

@jmarrero

@jmarrero jmarrero commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

A common setup places /var, or parts of it such as /var/log, on separate
filesystems (for example LVM logical volumes). With bootc install to-filesystem these filesystems
currently end up empty: the deployment backend seeds the image's /var into its
own state directory (ostree/deploy/<stateroot>/var, or the composefs shared
var), and at boot the separately mounted filesystems hide that content. Since
#1727 such mountpoints are accepted, but anything the image ships below them is
lost. This was reported in osbuild/bootc-image-builder#1222, where the
maintainers traced it to bootc install to-filesystem; Anaconda calls it the
same way, so this should apply there too (untested).

This series:

  1. tmt: Use the boot partition UUID in the separate /var test: the
    existing test passed the ESP's UUID as --boot-mount-spec. Independent fix.
  2. install: Initialize mounted /var filesystems from the image: on a fresh
    to-filesystem install, discover filesystems mounted at the target's /var
    or below, and initialize each empty top-level mount tree (including nested
    mounts) from the seeded /var with cp --archive, then SELinux label and
    sync them.
    • A tree that already contains data is preserved as a whole; nothing is merged.
    • Alongside, host-root and existing-deployment installs, and install to-disk,
      are unchanged.
    • Callers remain responsible for mounting the filesystems at boot.
    • The separate-/var TMT test now ships content in the image, adds a nested
      LV, checks contents, ownership,on the actual
      volumes, and no longer passes `
  3. container: Advertise install features in container inspect: adds
    `"install-features": ["initialize prepare the
    target (e.g. disk image builders)s for a bootc
    that initializes them. Older versrsions before
    1.12 reject them.

Behavior change

Callers that mount an empty /varelves after
installation now find the image's coo opt-out; I'm
happy to add a flag if preferred.

Design notes and open questions

  • Discovery vs. explicit flags: it options
    (--var-mount-spec). This uses thr the target
    instead, which works unchanged for existing callers and handles nested mounts.
    An explicit flag could be layered
  • Copy, not move: the seed in the state directory is kept, because with OSTree
    an emptied stateroot var is reseThe cost is that
    the initial /var content is duplicated on the root filesystem.
  • Hardlinks cannot span filesystnts are copied
    with --no-preserve=links.
  • Symlinks: within a tree being be directories
    in the image. A symlinked path is llowed.
  • SELinux: mount roots are labelelinuxfs (e.g.
    in an osbuild buildroot), an unlabkernel's
    unlabeled context, which the existing relabel walk treats as labeled.
  • install-features describes the image.
    container inspect was chosen because builders already run it against the
    image; `bootc install print-configive.

Testing

  • Unit tests in install::var_mountsh real nested mounts (#[ignore], run under un
  • test-install-to-filesystem-var-moVM: fails with bootc 1.16.10 (seed content missins series. It also passes with --composefs-backend` (install only, not booted).
  • End to end with a companion image-: qcow2 and
    VMDK images with LVM layouts (a separate /var with nested LVs, and nested
    LVs without a separate /var), bonership and
    restorecon -n were verified at f
  • The VM and image tests were run beain; the rebased branch passes unit tests, e-generated --check.

Related: #1615, #997, #336, osbuild/bootc-image-builder#1222
See also #1728; this automates the mere.

Generated-by: AI

DRAFT, no need for reviews yet. This is my first pass.

Once this is polished it pairs with: osbuild/image-builder#2733

The test passed the EFI system partition's UUID as the boot mount spec,
while /boot is a separate ext4 partition in its layout. Use the UUID of
the boot partition, which is what the installed system needs to mount.
This went unnoticed because the test does not boot the result.

Generated-by: AI
A common setup places /var, or parts of it such as /var/log, on
separate filesystems (for example LVM logical volumes) so that runaway
writes cannot fill the root filesystem. With `install to-filesystem`
these filesystems end up empty: the deployment backend seeds the
image's /var into its own state directory (`ostree/deploy/<stateroot>/var`,
or the composefs shared var), and at boot the separately mounted
filesystems hide that content.

On a fresh to-filesystem installation, discover filesystems mounted at
the target's /var or below. Each empty top-level mount tree, including
its nested mounts, is initialized from the seeded /var with
`cp --archive`, then SELinux labeled and synced. A tree that already
contains data is preserved as a whole, without merging. Alongside,
host-root and existing-deployment installs are not affected, nor is
`install to-disk`. Callers remain responsible for mounting these
filesystems at boot.

Note this changes behavior for callers that mount an empty /var
filesystem and fill it themselves after installation: they now find the
image's content there first.

The seeded copy in the state directory is kept; on OSTree, emptying it
would make the next deployment reseed it. Hardlinks cannot span
filesystems, so trees with nested mounts are copied without preserving
them. The roots of these filesystems are labeled unconditionally:
without selinuxfs (e.g. in an osbuild buildroot), an inode with no label
still reports the kernel's unlabeled context, which the regular relabel
walk takes as already labeled.

The separate /var TMT test now ships content in the image, adds a
nested logical volume, and checks contents, ownership, symlinks and
SELinux labels on the actual volumes. It no longer disables SELinux.

Related: bootc-dev#1615
Related: bootc-dev#997
Generated-by: AI
Tools that prepare a target for `install to-filesystem`, such as disk
image builders, need to know whether the bootc in an image initializes
mounted /var filesystems before they mount them: older versions leave
such filesystems empty, so they hide the image's /var content at boot,
and versions before 1.12 reject mountpoints in the target entirely.

Add an `install-features` list to `bootc container inspect` output,
currently containing `initialize-var-mounts`. It describes the bootc
binary rather than the image, but this is the command builders already
run against the image. The human-readable output is unchanged.

Generated-by: AI
@github-actions github-actions Bot added area/install Issues related to `bootc install` area/documentation Updates to the documentation labels Oct 1, 2026
@bootc-bot
bootc-bot Bot requested a review from jeckersb October 1, 2026 03:44
@cgwalters cgwalters added this to the 1.18 milestone Oct 1, 2026
Comment thread crates/lib/src/spec.rs
pub(crate) kernel: Option<crate::kernel::Kernel>,
/// Optional `bootc install` behaviors implemented by this bootc binary,
/// for tools that prepare a target for `install to-filesystem`.
pub(crate) install_features: Vec<&'static str>,

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.

Mmmm I'd rather just have bootc --version output global features this came up in another PR should be straightforward

prepared and mounted by an external tool or script. The root filesystem
is currently expected to be empty by default.

Mount filesystems for `/var` or its subdirectories beneath *ROOT_PATH*

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.

That's a bit ugly if we create /var in the physical root here though it's not the end of the world.

This is a really complex topic...humm...I think it'd be cleaner to have a --var mount option probably?

Another thing that we should definitely do is honor DPS - if we find a partition on the target system that matches "Variable Data Partition" we use it by default?

Same idea behind the ESP - we should really encourage installer tools to setup the ESP which we then mount ourselves during to-filesystem instead of having them mount it.

Of course though there could be someone out there that was relying on doing something with repart.d or something at firstboot time and us finding the partition at install time now could break things...

I'd vote: Honor DPS by default, encourage people to use it, have a --var mount option where installers can set it up, and also have --var= empty string mean "don't auto-discover DPS /var" but use the default?

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