Skip to content

perf(tfork): inject small clone files before publication - #12

Open
yiying-zhang wants to merge 69 commits into
mainfrom
perf/tfork-inject-clone-files
Open

perf(tfork): inject small clone files before publication#12
yiying-zhang wants to merge 69 commits into
mainfrom
perf/tfork-inject-clone-files

Conversation

@yiying-zhang

Copy link
Copy Markdown
Collaborator

What this changes

This PR adds a repeatable live-clone option:

--tfork-inject-file=COPY_INDEX:HOST_PATH:CONTAINER_PATH

It copies a small host file into one selected tfork child after CRIU restores the
child and before that child is registered in libpod. This lets a single live
fork produce children with different contexts, credentials, capability
descriptions, or other small per-child configuration files without a later
podman cp or podman exec.

COPY_INDEX is zero-based. The option may be repeated to inject multiple files
into one child or different files into different children.

Example

podman container clone --live --copies 2 \
  --tfork-inject-file 0:/host/child-0.json:/run/gensee/context.json \
  --tfork-inject-file 1:/host/child-1.json:/run/gensee/context.json \
  SOURCE

Both children receive the file at /run/gensee/context.json, but child 0 gets
child-0.json and child 1 gets child-1.json.

Lifecycle and failure semantics

For a live clone, Podman now:

  1. parses and validates all injection specifications before freezing the source;
  2. performs the normal CRIU tfork restore;
  3. obtains and validates each restored child's PID;
  4. opens that child's root through /proc/<pid>/root;
  5. applies the files assigned to that child;
  6. registers the fully configured child in libpod.

Injection is part of the existing clone transaction. If any source open,
destination lookup, file creation, or copy fails, the operation returns an error
and transactional rollback cleans up the incomplete clone batch. Earlier
children are not published as a partial success.

“Before publication” specifically means before libpod registration. The child
process has already been restored and is running when injection occurs. This PR
therefore prevents Podman clients from observing an unconfigured child, but it
does not prevent an internal child process from racing with the injection and
reading the destination first. Workloads that require the file to exist before
any child instruction executes would additionally need the child held frozen
until injection finishes.

Path, ownership, and file safety

Each injection must satisfy the following contract:

  • the copy index must be within the requested clone count;
  • host and container paths must be absolute, non-root paths;
  • the host source is opened with O_NOFOLLOW;
  • the source must be a regular file no larger than 1 MiB;
  • the destination parent is resolved securely beneath the child's root with
    pathrs.OpenInRoot;
  • the destination leaf is opened with openat(O_NOFOLLOW);
  • a newly created destination inherits the Podman process's filesystem UID/GID,
    which normally means root:root for rootful Podman;
  • an existing destination retains its current ownership;
  • every destination is forced to mode 0600.

This interface does not provide ownership or mode overrides. Consequently, a
non-root child process normally cannot read a newly created injected file. To
serve a non-root process with the current interface, the image or source
filesystem must pre-create the destination with the desired ownership; injection
preserves that owner while truncating the file and forcing mode 0600.

The destination parent directory must already exist. Only file contents are
copied; source ownership, timestamps, permissions, and extended attributes are
not preserved.

Performance impact

This does not shorten CRIU Phase A or Phase B. Its benefit is eliminating a
separate post-clone setup operation and keeping per-child initialization inside
the transactional fork workflow.

Injection is on the publication critical path and currently runs sequentially
per child. Added latency is therefore approximately the secure path lookup and
copy time for the total injected data. The 1 MiB per-file limit bounds the most
common use case, but many files or many children will increase fork completion
latency roughly linearly.

Patch scope

The file-injection behavior is implemented by
f9e0a8b5d8be28ebf2d8946145297f307f8c6d66; follow-up commit
7989e55af makes its ownership and mode contract explicit in CLI help and code.
This branch is stacked on earlier tfork transaction, synchronization, readiness,
and metadata work, so the full diff against gensee-tclone also contains those
prerequisite commits.

Validation

  • parser coverage for valid specifications, malformed fields, out-of-range copy
    indices, and relative paths;
  • go test ./cmd/podman/containers ./pkg/domain/infra/abi;
  • real Webtop live forks validating distinct per-child context contents and the
    expected child process trees.

yiying-zhang and others added 30 commits July 10, 2026 23:44
Stabilize live tfork source freezing
yiying-zhang and others added 30 commits July 20, 2026 00:03
…-main

Stabilize single-copy tfork clone path
Rewrite tclone setup for Gensee Crate
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants