Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,30 @@ All notable changes to virtkit will be documented in this file.

## [Unreleased]

### Added

- **DAX maps only the files worth mapping.** A share's window now serves regular files of
1M and more by default (`dax=inode`); smaller files read through the guest page cache as
without DAX, so a source tree no longer spends the window's overhead on files too small to
benefit. `vk run --dax`, `x-virtkit.dax` and `[executor.vm] dax` take `<size>:always` for
the previous behaviour and `<size>:inode=<min>` for another floor.

### Changed

- **Reading a large tree from a read-only share is faster.** A guest that reads many small
files — from an `:overlay` volume or the executor's host checkout — no longer pays a
per-file host cost that could dominate file-heavy jobs.

### Fixed

- **A stalled network transfer inside a guest now fails fast instead of hanging for the rest
of the job.** When the host was briefly overloaded a guest download could wedge and never
recover — a `cargo` fetch stuck at 0 bytes was the usual symptom. It now errors out
promptly and the application reconnects.
- **`host_checkout` jobs no longer stall on the first git command inside the guest.** The
job's first `git status` or `git checkout` now runs at full speed instead of stalling once
per job.

## [0.68.0] - 2026-09-11

### Changed
Expand Down
2 changes: 0 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ members = [
#
# third_party/imago is a single vendored leaf crate (see third_party/imago/VENDOR.md), a
# dependency of third_party/libkrun's block device — excluded for the same reason.
exclude = ["third_party/libkrun", "third_party/imago"]
exclude = ["third_party/libkrun", "third_party/imago", "third_party/ipstack"]

[workspace.package]
version = "0.68.0"
Expand Down Expand Up @@ -161,3 +161,9 @@ indicatif = "0.18"
unicode-width = "0.2"
# Use indicatif's transitive ANSI classifier in dashboard layout tests.
console = { version = "0.16", default-features = false, features = ["ansi-parsing"] }

# Vendored ipstack (third_party/ipstack/VENDOR.md): 1.0.1 plus one local patch — a TCP
# connection whose retransmissions are exhausted is reset instead of left Established with
# a hole in its stream.
[patch.crates-io]
ipstack = { path = "third_party/ipstack" }
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,13 @@ in per-fault latency.

The window reserves address space, not memory, and costs nothing until mapped. It defaults
to 8G per share; `vk run --dax`, a service's `x-virtkit.dax` and the executor's `[executor.vm] dax`
resize it or turn it `off`. Each guest supports 64G of windows — eight at the default size,
with further shares served without DAX. Guests with more than 63.25G of RAM have no room
for windows and receive none. DAX requires the built-in VMM. Under
resize it or turn it `off`. Each mapping costs the host an mmap and the guest an EPT
invalidation per 2 MiB range whatever the file's size, so by default only regular files of
1M and more go through the window (`dax=inode`; the host marks them) and smaller files read
through the guest's page cache as without DAX; `<size>:always` maps every file, and
`<size>:inode=<min>` moves the floor. Each guest supports 64G of windows — eight at the
default size, with further shares served without DAX. Guests with more than 63.25G of RAM
have no room for windows and receive none. DAX requires the built-in VMM. Under
`VIRTKIT_VMM=cloud-hypervisor`, and for single-file binds and `vk build` stage guests,
shares are served the ordinary way.

Expand Down
16 changes: 11 additions & 5 deletions docs/gitlab-ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -629,14 +629,20 @@ copy: ten concurrent job VMs reading a tools tree held eleven copies on the host

```toml
[executor.vm]
dax = "8G" # per share; the default
dax = "8G" # per share; the default: files of 1M and more through the window
# dax = "8G:always" # every file through the window
# dax = "8G:inode=64K" # another size floor
```

The window reserves guest address space, not memory, and costs nothing until mapped.
`"off"` disables it. Each guest supports 64G of windows — eight at the default size, with
further shares served without DAX. Guests with more than 63.25G of RAM have no room for
windows and receive none. Mappings are 4 KiB-granular, so the benefit is avoiding a tools
tree's memory cost per VM, not per-fault latency. Compose services inherit the job VM's
`"off"` disables it. Each mapping costs the host an mmap and the guest an EPT invalidation
per 2 MiB range whatever the file's size, which a source tree's small files never repay:
by default only regular files of 1M and more are mapped (`dax=inode`; the host marks them),
the rest read through the guest page cache as without DAX. Each guest supports 64G of
windows — eight at the default size, with further shares served without DAX. Guests with
more than 63.25G of RAM have no room for windows and receive none.
Mappings are 4 KiB-granular, so the benefit is avoiding a tools tree's memory cost per
VM, not per-fault latency. Compose services inherit the job VM's
setting unless they declare `x-virtkit.dax`. DAX requires the built-in VMM;
cloud-hypervisor has no DAX path and serves shares the ordinary way whatever this says.

Expand Down
Loading