Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Device-level fault injection (disk.fault.*)

Copperline can inject deterministic, seeded faults into any image-backed block device: dropped, torn, and reordered writes; ignored flushes; stale and corrupted reads; media errors; delays; and simulated power-cuts. This models the storage medium and bus misbehaving, not the guest -- a test exercises a filesystem’s or driver’s actual recovery code against the same byte-for-byte reproducible fault sequence on every run, from a copperline-ctl script or an MCP-driving agent.

This is a separate namespace from fault.inject (the CPU-bus fault family): disk.fault.* is medium/device behavior, never a guest-visible bus error.

Targets

A target names one device/unit:

{"kind": "copperhf", "unit": 0}
{"kind": "pcmcia"}
{"kind": "ide", "unit": 0}
{"kind": "scsi", "unit": 0}
{"kind": "floppy", "drive": 0}
{"kind": "cd"}

unit/drive default to 0. copperhf/pcmcia/ide/scsi resolve to whichever controller the machine profile actually has configured (Gayle, A4000 IDE, a Zorro IDE board such as LIDE, A2091/A3000-internal/A4091 SCSI); cd resolves to the machine’s CD drive, whichever it is (SCSI, ATAPI, CD32’s Akiko, or CDTV).

floppy only works on a plain (non-extended) ADF: extended ADF and raw MFM images have no logical sector grid for a lba to name, and disk.fault.set rejects them with a specific error rather than silently installing a policy the read/write hooks never consult.

cd is read-only medium, so only corrupt/error/delay/cut ever actually fire on it; a rule with "op": "write" is schema-valid there but never matches.

Policies and rules

A policy is a named, ordered list of rules:

{
  "on_clear": "release",
  "rules": [
    {
      "op": "write",
      "lba": {"from": 100, "to": 200},
      "probability": 0.01,
      "after": {"writes": 50},
      "times": 10,
      "continue": false,
      "action": "drop"
    }
  ]
}

Several policies may be active on one target at once; they are evaluated in installation order, and within a policy, rules are evaluated in list order. For a given request, the first matching rule whose probability test passes applies its action and stops evaluation, unless it sets "continue": true (rule fields below), in which case later rules may also match and apply on top of it. A write’s fate, once decided, wins over anything a later continuing rule tries to do to the data: "drop" is final -- a later "corrupt"/"tear" cannot make a dropped write land anyway, and a later "drop" discards whatever an earlier "reorder" already queued -- and "reorder" defers the decision -- a later "corrupt" mutates the queued copy in place rather than also landing an independent write, and a later "error" removes the queued copy before failing, since a write the guest sees fail never left anything in a real drive’s cache for a later flush to resurrect.

Rule fields (all but action optional):

Actions

on_clear (policy-level, default "release"): what happens to a held reorder queue when this policy is cleared, or replaced by a set under the same id -- "release" replays the held writes onto the image in order (same effect as a flush), "drop" discards them.

Control-protocol methods

See the control protocol reference for the exact parameter/reply shapes and error cases.

Determinism

Every random choice (probability tests, reorder release order, corrupt bit positions, auto-assigned ids) is drawn from a generator keyed on the policy’s own seed and the target’s request sequence number, never on wall-clock time or host state. Two runs with the same image, the same guest input schedule, and the same seed fault identically, so a flaky guest-side recovery bug reproduces exactly, every time.