pub struct DiskConfig {
pub capacity_mib: u32,
pub filesystem: Filesystem,
pub throttle: DiskThrottle,
pub read_only: bool,
pub name: Option<&'static str>,
pub no_auto_mount: bool,
}Expand description
Per-disk config. Default is raw 256 MiB device on /dev/vda;
formatting and auto-mount are deferred.
No backing-file path field: the framework owns the per-test
backing file (tempfile() for Raw, FICLONE-cloned template
for Btrfs). See module docs.
Fields§
§capacity_mib: u32Advertised capacity in mebibytes (MiB). capacity_bytes()
computes capacity_mib << 20. 256 MiB default capacity.
Sized to accommodate common guest filesystem formatters;
smaller values are accepted but may cause mkfs failures
inside the template VM (see
crate::vmm::disk_template::build_template_via_vm) for
Filesystem::Btrfs.
filesystem: FilesystemFilesystem to format the per-test backing with. Raw leaves
the device unformatted; Btrfs routes through the
template-cache lifecycle.
throttle: DiskThrottleIO throttle. Default unthrottled.
read_only: boolRead-only at the device level — the device advertises VIRTIO_BLK_F_RO so the guest mounts read-only. Useful for tests that need protection against accidental writes.
name: Option<&'static str>Optional human-readable label for this disk. None (the
default) is an anonymous disk addressable only by index. A
name lets WorkType variants reference the disk symbolically
(e.g. "data", "log") instead of by index, which keeps
tests stable across topology rearrangements.
Stored as Option<&'static str> so DiskConfig is
const-constructible — DiskConfig::DEFAULT.with_name("data")
works in a static or const initializer, which the
#[ktstr_test(disk = ...)] macro relies on. The field is
#[serde(skip)] because &'static str can’t be deserialized
from arbitrary input without leaking; the name is operator
metadata that the framework computes on-the-fly from the
declaration, not state that needs to round-trip through
sidecar JSON. Sidecar consumers that need to associate a
disk identity with serialized data should use the disk’s
index instead.
no_auto_mount: boolOpt out of guest-side auto-mount. Default false means a
non-Raw disk is auto-mounted at /mnt/disk0 by the guest
init (see
crate::vmm::rust_init::auto_mount_data_disks); setting
true suppresses the auto-mount cmdline tokens and leaves
/dev/vda raw to the test author. Has no effect for
Filesystem::Raw disks (there is nothing to mount). The
only honest reason to flip this is a test that wants to
drive the mount path itself (e.g. exercise mount-option
fuzzing or fail-injection on the kernel mount syscall).
Implementations§
Source§impl DiskConfig
impl DiskConfig
Sourcepub const DEFAULT: Self
pub const DEFAULT: Self
Const-evaluable default — same values as Default::default
but usable in static / const initializers. Required for
the #[ktstr_test(disk = ...)] macro surface: the macro
emits a static containing a DiskConfig, which must be
const-constructible.
Spread via ..DiskConfig::DEFAULT in struct-update syntax,
or chain const setters (DiskConfig::DEFAULT.with_name("data")).
Source§impl DiskConfig
impl DiskConfig
Sourcepub fn capacity_mib(self, mib: u32) -> Self
pub fn capacity_mib(self, mib: u32) -> Self
Set capacity in mebibytes (MiB). The argument is interpreted
as binary mebibytes per Self::capacity_bytes, not decimal
megabytes.
Sourcepub fn filesystem(self, fs: Filesystem) -> Self
pub fn filesystem(self, fs: Filesystem) -> Self
Select the on-disk filesystem.
Filesystem::Raw (the default) leaves the device unformatted.
Filesystem::Btrfs routes through
crate::vmm::disk_template::ensure_template: on cache miss
the framework boots a one-shot template VM that runs
mkfs.btrfs inside the guest, caches the formatted image,
and per-test boots reflink-clone it. The lifecycle requires
a reflink-capable cache directory (btrfs or xfs) and a host
mkfs.btrfs binary on PATH at template-build time. See
the module-level docs and crate::vmm::disk_template.
§Disk-template lifecycle
For Filesystem::Btrfs, the per-test backing file is produced
in three stages — none of which the test author needs to drive
explicitly:
- Cache lookup —
disk_template::ensure_templatekeys off(filesystem, capacity)and returns the cached image path on hit. See the module docs atcrate::vmm::disk_templatefor the cache-key encoding and on-disk layout. - Template build (cache miss) —
disk_template::build_template_via_vmboots a one-shot guest with the host’smkfs.btrfspacked into the initramfs; the guest formats/dev/vdaagainst a sparse staging image, and the framework atomically moves the formatted image into the cache viadisk_template::store_atomic. The host never execsmkfs.btrfsagainst a real backing file — the guest kernel is the on-disk-format authority. - Per-test fan-out —
disk_template::clone_to_per_testFICLONE-clones the cached image into a tempfile under the cache root. The clone is O(metadata) and copy-on-write at the extent level, so per-test writes never touch the cached template.
Stage 3 requires the cache directory to live on a reflink-
capable filesystem (btrfs or xfs); see
disk_template::verify_cache_dir_supports_reflink
for the gate and
crate::vmm::KtstrVmBuilder::disk for the full
builder-side wiring.
Sourcepub fn iops(self, iops: u64) -> Self
pub fn iops(self, iops: u64) -> Self
Set IOPS throttle. Passing 0 disables IOPS throttling
(equivalent to None). To throttle near-zero, use iops(1).
There is no “block all IO” mode — the minimum throttled rate
is 1 op/sec. Any positive value is wrapped in NonZeroU64.
Clearing the rate (iops(0)) also clears the matching
iops_burst_capacity — a burst capacity without a refill
rate is invalid (caught by DiskThrottle::validate) and
keeping a stale burst around after the user explicitly
disabled the rate is a footgun: the next validate() call
would fail with a less-helpful “burst without rate” error
rather than the user’s intent (a fully-unthrottled bucket).
Sourcepub fn bytes_per_sec(self, bytes_per_sec: u64) -> Self
pub fn bytes_per_sec(self, bytes_per_sec: u64) -> Self
Set bandwidth throttle (bytes per second). A zero value
disables bandwidth throttling (stored as None); any
positive value is wrapped in NonZeroU64.
Clearing the rate (bytes_per_sec(0)) also clears the
matching bytes_burst_capacity for the same reason as
iops — a burst without a rate is invalid and stale-burst
retention turns a deliberate “drop the throttle” into a
validate-time failure.
Sourcepub fn iops_burst_capacity(self, capacity: u64) -> Self
pub fn iops_burst_capacity(self, capacity: u64) -> Self
Set IOPS burst capacity (token-bucket peak). A zero value
clears the burst override (stored as None), reverting to
the default 1-second burst (capacity equals refill rate).
Any positive value is wrapped in NonZeroU64.
The capacity must be >= iops when both are set, and must
not be set without iops. Both rules are enforced by
DiskThrottle::validate at VM build time, not by the
builder — the builder is order-independent (a user may set
burst before rate). Tests should call validate() after
chaining, or construct an invalid config and observe the
error from VM build.
Sourcepub fn bytes_burst_capacity(self, capacity: u64) -> Self
pub fn bytes_burst_capacity(self, capacity: u64) -> Self
Set bandwidth burst capacity in bytes (token-bucket peak).
A zero value clears the burst override (stored as None),
reverting to the default 1-second burst. Any positive value
is wrapped in NonZeroU64.
The capacity must be >= bytes_per_sec when both are set,
and must not be set without bytes_per_sec. Both rules are
enforced by DiskThrottle::validate at VM build time, not
by the builder.
Sourcepub fn read_only(self) -> Self
pub fn read_only(self) -> Self
Mark the disk read-only (advertises VIRTIO_BLK_F_RO).
Default is read-write; this builder takes no argument (no
boolean footgun) and only flips the flag on. To return to
read-write, drop the call or reconstruct from
DiskConfig::default().
Sourcepub const fn with_name(self, name: &'static str) -> Self
pub const fn with_name(self, name: &'static str) -> Self
Attach a human-readable label to this disk. WorkType variants
that need to address a specific disk (e.g. one of several
attached) can resolve the name instead of relying on
attachment order. Default is anonymous (None); calling
.with_name(...) sets it.
The name also drives the guest auto-mount path: a disk
named "data" auto-mounts at /mnt/data instead of the
default /mnt/disk0. See Self::no_auto_mount to opt
out of auto-mount entirely.
Takes &'static str so the builder is const fn —
DiskConfig::DEFAULT.with_name("data") can spread into a
static initializer. String literals are &'static; tests
needing a dynamic name should build the disk programmatically
rather than going through this builder.
Sourcepub fn no_auto_mount(self) -> Self
pub fn no_auto_mount(self) -> Self
Suppress the guest-side auto-mount of this disk. Default
behavior auto-mounts a non-Raw disk at the path returned
by Self::auto_mount_path; calling this method flips
the flag on. Useful for tests that want raw access to
/dev/vda after a host-driven mkfs (e.g. mount-option
fuzzing, deliberate mount-failure injection, manual
subvolume traversal).
No-op for Filesystem::Raw disks (there is nothing to
mount). The flag is honored at cmdline-emission time in
crate::vmm::KtstrVm::build_guest_cmdline (via
disk_auto_mount_cmdline_tokens): when set, the
KTSTR_DISK0_FS / KTSTR_DISK0_MOUNT / KTSTR_DISK0_RO
tokens are not emitted, and the guest’s
crate::vmm::rust_init::auto_mount_data_disks short-
circuits at the missing-token check.
Trait Implementations§
Source§impl Clone for DiskConfig
impl Clone for DiskConfig
Source§fn clone(&self) -> DiskConfig
fn clone(&self) -> DiskConfig
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for DiskConfig
impl Debug for DiskConfig
Source§impl Default for DiskConfig
impl Default for DiskConfig
Source§fn default() -> Self
fn default() -> Self
256 MiB, Filesystem::Raw, no throttle. The Raw default
keeps the on-host cost minimal — no template-VM build, no
cache directory required — and the per-test backing is a
fresh sparse tempfile() per VM (see
crate::vmm::KtstrVm::init_virtio_blk).
§Memory footprint
The 256 MiB sparse file lives under the host’s TMPDIR
(tempfile()); actual host disk/RAM consumption equals the
bytes the guest writes, not the advertised capacity. On
tmpfs-backed TMPDIR (the default on most Linux distros), a
fully-written disk consumes 256 MiB of host RAM per test
— operators running large topologies should size host memory
accordingly or override TMPDIR to a disk-backed path.
Source§impl<'de> Deserialize<'de> for DiskConfig
impl<'de> Deserialize<'de> for DiskConfig
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl Hash for DiskConfig
impl Hash for DiskConfig
Source§impl PartialEq for DiskConfig
impl PartialEq for DiskConfig
Source§impl Serialize for DiskConfig
impl Serialize for DiskConfig
impl Eq for DiskConfig
impl StructuralPartialEq for DiskConfig
Auto Trait Implementations§
impl Freeze for DiskConfig
impl RefUnwindSafe for DiskConfig
impl Send for DiskConfig
impl Sync for DiskConfig
impl Unpin for DiskConfig
impl UnwindSafe for DiskConfig
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more