This commit is contained in:
2026-08-18 09:20:44 +02:00
commit b826cd721a
522 changed files with 93730 additions and 0 deletions
+641
View File
@@ -0,0 +1,641 @@
#!/bin/sh
set -eu
: "${PRE15_DUT:?PRE15_DUT is required}"
: "${PRE15_ROOT:?PRE15_ROOT is required}"
: "${PRE15_CASE_TMP:?PRE15_CASE_TMP is required}"
: "${PRE15_RUN_DIR:?PRE15_RUN_DIR is required}"
: "${PRE15_LIB_DIR:?PRE15_LIB_DIR is required}"
. "$PRE15_LIB_DIR/runner.sh"
baseline=93d0c64e321f50cf68026c3f1c0c95293bf17302
case_script=$PRE15_DUT/tests/pre15/cases/B33-cache-policy.sh
fixture_dir=$PRE15_DUT/tests/pre15/fixtures
gate_dir=$PRE15_DUT/tests/pre15/gates
oracle=$fixture_dir/B33-cache-oracle.c
qemu_spec=$fixture_dir/B33-cache-state.json
qemu_generator=$fixture_dir/B33-cache-generate.py
qemu_runner=$fixture_dir/B33-qemu-run.sh
b32_probe=$fixture_dir/B32-cache-probe.c
kld_builder=$fixture_dir/B28-build-kld.sh
gate_input=$gate_dir/P15-038-input.json
gate_result=$PRE15_ROOT/planning/pre15/evidence/20260816T021736Z-G05-P15-038/result.json
gate_benefit=$PRE15_ROOT/planning/pre15/evidence/20260816T021736Z-G05-P15-038/benefit.json
gate_state=$PRE15_ROOT/planning/pre15/evidence/20260816T021736Z-G05-P15-038/state-model.json
gate_hashes=$PRE15_ROOT/planning/pre15/evidence/20260816T021736Z-G05-P15-038/SHA256SUMS
artifacts=$PRE15_RUN_DIR/artifacts
for tool in cc git python3 sha256sum timeout; do
command -v "$tool" >/dev/null 2>&1 || \
pre15_infra_blocked "missing B33 host tool: $tool"
done
for fixture in "$case_script" "$oracle" "$qemu_spec" "$qemu_generator" "$qemu_runner" \
"$b32_probe" "$kld_builder" "$gate_input" "$gate_result" \
"$gate_benefit" "$gate_state" "$gate_hashes"; do
pre15_record_fixture "b33-$(basename "$fixture")" "$fixture"
done
for source in internal.h zdata.c; do
pre15_record_fixture "b33-$source" "$PRE15_DUT/src/$source"
done
mkdir -p "$artifacts"
if test "${PRE15_QEMU_TARGET_ONLY:-0}" = 1; then
pre15_target_reached
else
if ! python3 -B - "$PRE15_ROOT" "$PRE15_DUT" "$baseline" "$gate_input" \
"$gate_result" "$gate_benefit" "$gate_state" \
"$artifacts/B33-source-audit.json" <<'PY'
from __future__ import annotations
import json
from pathlib import Path
import re
import subprocess
import sys
root = Path(sys.argv[1])
dut = Path(sys.argv[2])
baseline = sys.argv[3]
implementation = "bc56f830918b76029871b60cca2e53992de70a2e"
current_owners = {
"internal.h": "aa20623132b6821c6ad4651b263fc0ac0f7a14c8",
"zdata.c": implementation,
}
gate_input = json.loads(Path(sys.argv[4]).read_text(encoding="ascii"))
gate_result = json.loads(Path(sys.argv[5]).read_text(encoding="ascii"))
gate_benefit = json.loads(Path(sys.argv[6]).read_text(encoding="ascii"))
gate_state = json.loads(Path(sys.argv[7]).read_text(encoding="ascii"))
report_path = Path(sys.argv[8])
def fail(message: str) -> None:
raise SystemExit(message)
def committed(commit: str, relative: str) -> str:
completed = subprocess.run(
["git", "-C", str(root), "show", f"{commit}:{relative}"],
check=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
timeout=30,
)
if completed.returncode != 0:
fail(f"cannot read B33 source {commit}:{relative}: {completed.stderr.strip()}")
return completed.stdout
def function(source: str, name: str) -> str:
match = re.search(rf"\n(?:static\s+)?[^\n]+\n{name}\([^{{]+\n\{{", source)
if match is None:
fail(f"cannot locate function {name}")
start = match.start() + 1
brace = source.find("{", match.start())
depth = 0
for index in range(brace, len(source)):
if source[index] == "{":
depth += 1
elif source[index] == "}":
depth -= 1
if depth == 0:
return source[start : index + 1]
fail(f"unterminated function {name}")
expected_changed = {
"repo-pre-15/src/internal.h",
"repo-pre-15/src/zdata.c",
"repo-pre-15/tests/pre15/cases/B33-cache-policy.sh",
"repo-pre-15/tests/pre15/fixtures/B33-cache-generate.py",
"repo-pre-15/tests/pre15/fixtures/B33-cache-oracle.c",
"repo-pre-15/tests/pre15/fixtures/B33-cache-state.json",
"repo-pre-15/tests/pre15/fixtures/B33-qemu-run.sh",
}
changed = subprocess.run(
[
"git",
"-C",
str(root),
"diff-tree",
"--no-commit-id",
"--name-only",
"-r",
implementation,
],
check=True,
stdout=subprocess.PIPE,
text=True,
timeout=30,
).stdout.splitlines()
if set(changed) != expected_changed or len(changed) != len(expected_changed):
fail(f"B33 implementation write set mismatch: {changed!r}")
for name, commit in (("baseline", baseline), ("implementation", implementation)):
if subprocess.check_output(
["git", "-C", str(root), "rev-parse", commit], text=True
).strip() != commit:
fail(f"B33 {name} identity changed")
internal = (dut / "src/internal.h").read_text(encoding="utf-8")
zdata = (dut / "src/zdata.c").read_text(encoding="utf-8")
implemented_internal = committed(implementation, "repo-pre-15/src/internal.h")
implemented_zdata = committed(implementation, "repo-pre-15/src/zdata.c")
for name, source in (("internal.h", internal), ("zdata.c", zdata)):
owner = current_owners[name]
if source != committed(owner, f"repo-pre-15/src/{name}"):
fail(f"current B33 source differs from accepted owner {owner}: {name}")
baseline_zdata = committed(baseline, "repo-pre-15/src/zdata.c")
for preserved in ("z_erofs_decode_length", "z_erofs_decode_extent"):
if function(implemented_zdata, preserved) != function(baseline_zdata, preserved):
fail(f"B25/B27/B28 read/decode path changed in B33: {preserved}")
do_read = function(implemented_zdata, "z_erofs_do_read")
baseline_do_read = function(baseline_zdata, "z_erofs_do_read")
bypass_delta = (
"\t\t\t} else\n"
"\t\t\t\tz_erofs_extent_cache_record_bypass(sbi, &map);"
)
if do_read.count(bypass_delta) != 1 or do_read.replace(bypass_delta, "\t\t\t}") != baseline_do_read:
fail("B33 z_erofs_do_read differs beyond policy-rejection accounting")
required_b32 = (
"cache->nid == vi->nid",
"cache->decoded_size == decoded_size",
"cache->map.m_pa == map->m_pa",
"cache->map.m_la == map->m_la",
"cache->map.m_plen == map->m_plen",
"cache->map.m_llen == map->m_llen",
"cache->map.m_deviceid == map->m_deviceid",
"cache->map.m_algorithmformat == map->m_algorithmformat",
"cache->map.m_flags == map->m_flags",
"cache->state == EROFS_ZCACHE_INFLIGHT || cache->waiters != 0",
"cv_wait(&cache->cv, &sbi->z_extent_cache_lock)",
"cache->error = error",
"cache->closing = true",
"Z_EROFS_CACHE_BYPASS",
"free(decoded, M_EROFS);",
)
missing = [token for token in required_b32 if token not in zdata]
if missing:
fail(f"B32 key/inflight/failure/fallback token missing: {missing!r}")
policy = function(zdata, "z_erofs_extent_cache_eligible")
for named_codec in (
"Z_EROFS_COMPRESSION_LZ4",
"Z_EROFS_COMPRESSION_LZMA",
"Z_EROFS_COMPRESSION_DEFLATE",
"Z_EROFS_COMPRESSION_ZSTD",
):
if named_codec in policy:
fail(f"B33 admission still names a codec: {named_codec}")
for token in (
"map->m_algorithmformat < Z_EROFS_COMPRESSION_MAX",
"len <= cache->budget_bytes",
"decode_work >= cache->minimum_decode_work",
"z_erofs_cache_enabled != 0",
):
if token not in policy:
fail(f"codec-neutral work/size policy token is absent: {token}")
if "map->m_algorithmformat == Z_EROFS_COMPRESSION_LZMA" in zdata:
fail("LZMA-only admission branch remains")
record_bypass = function(zdata, "z_erofs_extent_cache_record_bypass")
if "++cache->metrics[map->m_algorithmformat].bypasses" not in record_bypass or (
"z_erofs_extent_cache_record_bypass(sbi, &map)" not in do_read
):
fail("B33 policy rejection is absent from four-codec accounting")
budget = gate_input["budget"]
expected_macros = {
"EROFS_ZCACHE_MOUNT_HARD_BUDGET": budget["per_mount_bytes"] // 1024,
"EROFS_ZCACHE_GLOBAL_HARD_BUDGET": budget["global_bytes"] // 1024,
"EROFS_ZCACHE_MIN_DECODE_WORK": budget["minimum_decode_work_bytes"] // 1024,
}
for name, kib in expected_macros.items():
if f"#define {name} ({kib}UL * 1024)" not in zdata:
fail(f"B33 hard policy differs from G05: {name}")
for token in (
'TUNABLE_INT("vfs.erofs.decoded_cache.enabled"',
'TUNABLE_ULONG("vfs.erofs.decoded_cache.mount_budget"',
'TUNABLE_ULONG("vfs.erofs.decoded_cache.global_budget"',
'TUNABLE_ULONG("vfs.erofs.decoded_cache.minimum_decode_work"',
"MIN(z_erofs_cache_mount_budget,",
"MIN(z_erofs_cache_global_budget,",
"EVENTHANDLER_REGISTER(vm_lowmem",
"EVENTHANDLER_DEREGISTER(vm_lowmem",
"LIST_FOREACH(sbi, &z_erofs_cache_mounts, z_extent_cache_link)",
"mtx_trylock(&sbi->z_extent_cache_lock)",
):
if token not in zdata:
fail(f"B33 budget/config/reclaim token is absent: {token}")
claim = function(zdata, "z_erofs_extent_cache_claim")
if claim.find("z_erofs_extent_cache_reserve(decoded_size)") > claim.find(
"cache->state = EROFS_ZCACHE_INFLIGHT"
):
fail("B33 does not reserve before inflight decode")
drop_position = claim.find("z_erofs_extent_cache_drop_locked(cache, true, false)")
empty_position = claim.find("cache->state = EROFS_ZCACHE_EMPTY", drop_position)
reserve_position = claim.find("z_erofs_extent_cache_reserve(decoded_size)")
if drop_position < 0 or not (drop_position < empty_position < reserve_position):
fail("B33 replacement reservation failure can leave READY without data")
complete = function(zdata, "z_erofs_extent_cache_complete")
if complete.find("z_erofs_extent_cache_release(cache->charged_bytes)") > complete.find(
"cache->state = EROFS_ZCACHE_FAILED"
):
fail("B33 failed decode publishes before releasing reservation")
for field in (
"hits",
"misses",
"bypasses",
"evictions",
"reclaims",
"resident_bytes",
"charged_bytes",
"budget_bytes",
"minimum_decode_work",
"metrics[Z_EROFS_COMPRESSION_MAX]",
):
if field not in internal:
fail(f"B33 four-codec accounting field is absent: {field}")
for forbidden in ("shrinker", "workqueue", "work_struct", "wait_on_bit", "folio"):
if forbidden in internal + zdata:
fail(f"Linux-only cache primitive introduced: {forbidden}")
if gate_result.get("status") != "GO" or gate_result.get("b33") != "AUTHORIZED":
fail("P15-038 G05 result is not GO")
if gate_state.get("status") != "PASS" or gate_state["budget"]["global_remaining"] != 0:
fail("P15-038 state model is not closed")
if gate_benefit.get("codecs_meeting_threshold", 0) < 2 or any(
len(summary["current_ns"]) != 5 or len(summary["candidate_ns"]) != 5
for summary in gate_benefit.get("summaries", [])
):
fail("P15-038 fixed five-sample benefit is incomplete")
report = {
"baseline": baseline,
"batch": "B33",
"b32_contract_preserved": True,
"codec_neutral": True,
"current_owners": current_owners,
"gate_codecs_meeting_threshold": gate_benefit["codecs_meeting_threshold"],
"global_hard_budget": budget["global_bytes"],
"implementation": implementation,
"lock_order": ["global-list", "mount-cache", "global-budget"],
"mount_hard_budget": budget["per_mount_bytes"],
"no_cache_fallback": True,
"reclaim": "FreeBSD-vm_lowmem",
"write_set": sorted(changed),
}
report_path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="ascii")
print(json.dumps(report, indent=2, sort_keys=True))
PY
then
pre15_runner_fail 'B33 source, gate, write-set, or preservation audit failed'
fi
if ! (cd "$PRE15_ROOT/planning/pre15/evidence/20260816T021736Z-G05-P15-038" && \
timeout -k 5 30 sha256sum -c SHA256SUMS) \
>"$artifacts/gate-manifest.stdout" 2>"$artifacts/gate-manifest.stderr"; then
pre15_runner_fail 'P15-038 gate evidence manifest failed'
fi
if ! cc -std=c11 -O2 -Wall -Wextra -Werror "$oracle" \
-o "$PRE15_CASE_TMP/B33-cache-oracle" \
>"$artifacts/oracle-build.stdout" 2>"$artifacts/oracle-build.stderr"; then
pre15_runner_fail 'B33 cache budget oracle did not compile'
fi
if ! timeout -k 5 60 "$PRE15_CASE_TMP/B33-cache-oracle" \
>"$artifacts/oracle.json" 2>"$artifacts/oracle.stderr"; then
pre15_dut_fail 'B33 cache budget/accounting oracle failed'
fi
if ! python3 -B - "$artifacts/oracle.json" <<'PY'
import json
from pathlib import Path
import sys
result = json.loads(Path(sys.argv[1]).read_text(encoding="ascii"))
if result.get("status") != "PASS":
raise SystemExit("B33 oracle status is not PASS")
if result.get("global_peak") != result.get("global_limit") or result.get("global_remaining") != 0:
raise SystemExit("B33 oracle global budget did not close")
metrics = result.get("metrics", [])
if len(metrics) != 4 or [item.get("codec") for item in metrics] != list(range(4)):
raise SystemExit("B33 four-codec metric set is incomplete")
for item in metrics:
if item.get("hits", 0) < 1 or item.get("misses", 0) < 1 or item.get("evictions", 0) < 1:
raise SystemExit(f"B33 codec metric is incomplete: {item!r}")
if item.get("resident_bytes") != 0:
raise SystemExit(f"B33 codec resident bytes leaked: {item!r}")
PY
then
pre15_dut_fail 'B33 four-codec accounting result is incomplete'
fi
sha256sum "$artifacts/B33-source-audit.json" "$artifacts/oracle.json" \
"$artifacts/gate-manifest.stdout" >"$artifacts/SHA256SUMS"
fi
pre15_target_reached
if test "${PRE15_MODE:-host}" != qemu; then
printf '%s\n' \
'B33-cache-budget host PASS' \
'Four-codec admission/accounting, mount/global hard budgets, exhaustion fallback, reclaim, failure retry, disable, and eviction hash PASS' \
'P15-038 host codec-cost gate replay manifest PASS; no guest vnode performance claimed' \
'TC084/TC105/TC129 NOT_RUN (not necessary)' \
'QEMU TC168, TC130, and full feature suite NOT_RUN in host mode'
exit 0
fi
test "${PRE15_B32_SCENARIO:-}" = TC168-cache-inflight || \
pre15_runner_fail 'B33 QEMU mode requires TC168-cache-inflight'
for tool in clang cmp diff file mkfs.erofs nm scp tar timeout; do
command -v "$tool" >/dev/null 2>&1 || \
pre15_infra_blocked "missing B33 QEMU tool: $tool"
done
: "${PRE15_QEMU_CONTROL_PATH:?QEMU control path is required}"
: "${PRE15_QEMU_SSH_KEY:?QEMU SSH key is required}"
: "${PRE15_QEMU_SSH_PORT:?QEMU SSH port is required}"
: "${PRE15_QEMU_SSH_USER:?QEMU SSH user is required}"
first=$PRE15_CASE_TMP/fixtures-first
second=$PRE15_CASE_TMP/fixtures-second
if ! (umask 022 && timeout -k 5 180 python3 -B "$qemu_generator" \
--spec "$qemu_spec" --output "$first") \
>"$artifacts/generate-first.json" 2>"$artifacts/generate-first.stderr" || \
! (umask 022 && timeout -k 5 180 python3 -B "$qemu_generator" \
--spec "$qemu_spec" --output "$second") \
>"$artifacts/generate-second.json" 2>"$artifacts/generate-second.stderr"; then
pre15_runner_fail 'B33 fixture generation failed'
fi
if ! diff -qr "$first" "$second" >"$artifacts/fixture-repeat.diff"; then
pre15_runner_fail 'B33 fixtures are not byte reproducible'
fi
cp "$first/fixture-index.json" "$artifacts/B33-fixture-index.json"
module=$PRE15_CASE_TMP/B33-erofs-zstdio0.ko
if ! timeout -k 10 600 /bin/sh "$kld_builder" "$PRE15_DUT" \
"$PRE15_FREEBSD_SRC" "$module" "$PRE15_CASE_TMP/kld-work" 0 \
>"$artifacts/kld-build.stdout" 2>"$artifacts/kld-build.stderr"; then
pre15_dut_fail 'B33 cross-target zstdio0 KLD build failed'
fi
pre15_record_module "$module"
file "$module" >"$artifacts/kld-file.txt"
sha256sum "$module" >"$artifacts/kld-sha256.txt"
nm -u "$module" | LC_ALL=C sort >"$artifacts/kld-nm-u.txt"
fixture_archive=$PRE15_CASE_TMP/B33-fixtures.tar.gz
tar -C "$first" -czf "$fixture_archive" .
pre15_scp()
{
timeout -k 5 "${PRE15_GUEST_COMMAND_TIMEOUT:-60}" scp -O -q \
-o BatchMode=yes -o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 \
-o "ControlPath=$PRE15_QEMU_CONTROL_PATH" \
-i "$PRE15_QEMU_SSH_KEY" -P "$PRE15_QEMU_SSH_PORT" \
"$1" "$PRE15_QEMU_SSH_USER@127.0.0.1:$2"
}
pre15_guest_ssh_bounded()
{
timeout -k 5 "${PRE15_GUEST_COMMAND_TIMEOUT:-60}" ssh -n -q \
-o BatchMode=yes -o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 \
-o "ControlPath=$PRE15_QEMU_CONTROL_PATH" \
-p "$PRE15_QEMU_SSH_PORT" \
"$PRE15_QEMU_SSH_USER@127.0.0.1" "$@"
}
if ! pre15_scp "$fixture_archive" /root/B33-fixtures.tar.gz || \
! pre15_scp "$b32_probe" /root/B33-cache-probe.c || \
! pre15_scp "$module" /root/B33-erofs-zstdio0.ko; then
pre15_infra_blocked 'could not transfer B33 module, probe, or fixtures'
fi
if ! pre15_guest_ssh_bounded \
'rm -rf /root/B33-fixtures && mkdir /root/B33-fixtures && tar -xzf /root/B33-fixtures.tar.gz -C /root/B33-fixtures && cc -O2 -Wall -Wextra -Werror -pthread -o /root/B33-cache-probe /root/B33-cache-probe.c'; then
pre15_infra_blocked 'could not prepare B33 guest fixtures/probe'
fi
if pre15_guest_ssh_bounded kldstat -q -m erofs >/dev/null 2>&1; then
pre15_infra_blocked 'guest kernel already owns the erofs.1 interface'
fi
module_sha256=$(sha256sum "$module" | awk '{print $1}')
guest_module_sha256=$(pre15_guest_ssh_bounded sha256 -q /root/B33-erofs-zstdio0.ko) || \
pre15_infra_blocked 'could not hash transferred B33 KLD'
printf 'host=%s guest=%s\n' "$module_sha256" "$guest_module_sha256" \
>"$artifacts/guest-module-sha256.txt"
test "$guest_module_sha256" = "$module_sha256" || \
pre15_runner_fail 'transferred B33 KLD hash differs from host module'
pre15_guest_ssh_bounded kldstat >"$artifacts/guest-kldstat-before-load.txt"
pre15_guest_ssh_bounded dmesg >"$artifacts/guest-dmesg-before-load.txt"
cache_tunable=vfs.erofs.decoded_cache.minimum_decode_work
cache_tunable_before=$(pre15_guest_ssh_bounded kenv -q "$cache_tunable" || true)
printf 'name=%s before=%s test-value=0\n' "$cache_tunable" \
"${cache_tunable_before:-unset}" >"$artifacts/cache-tunable.txt"
if ! pre15_guest_ssh_bounded kenv "$cache_tunable=0" \
>"$artifacts/cache-tunable-set.stdout" \
2>"$artifacts/cache-tunable-set.stderr"; then
pre15_infra_blocked 'could not force B33 decoded-cache admission'
fi
if ! pre15_guest_ssh_bounded kldload /root/B33-erofs-zstdio0.ko \
>"$artifacts/kldload.stdout" 2>"$artifacts/kldload.stderr"; then
if test -n "$cache_tunable_before"; then
pre15_guest_ssh_bounded kenv "$cache_tunable=$cache_tunable_before" || true
else
pre15_guest_ssh_bounded kenv -u "$cache_tunable" || true
fi
if grep -q 'module already loaded or in kernel' \
"$artifacts/kldload.stderr"; then
pre15_infra_blocked 'guest kernel already owns the erofs.1 interface'
fi
pre15_dut_fail 'B33 exact-source zstdio0 KLD failed to load'
fi
if test -n "$cache_tunable_before"; then
pre15_guest_ssh_bounded kenv "$cache_tunable=$cache_tunable_before" \
>"$artifacts/cache-tunable-restore.stdout" \
2>"$artifacts/cache-tunable-restore.stderr" || \
pre15_infra_blocked 'could not restore B33 cache tunable'
else
pre15_guest_ssh_bounded kenv -u "$cache_tunable" \
>"$artifacts/cache-tunable-restore.stdout" \
2>"$artifacts/cache-tunable-restore.stderr" || \
pre15_infra_blocked 'could not remove B33 cache tunable override'
fi
cache_tunable_after=$(pre15_guest_ssh_bounded kenv -q "$cache_tunable" || true)
printf 'after=%s\n' "${cache_tunable_after:-unset}" \
>>"$artifacts/cache-tunable.txt"
if test "$cache_tunable_after" != "$cache_tunable_before"; then
pre15_runner_fail 'B33 cache tunable was not restored exactly'
fi
if ! pre15_guest_ssh_bounded kldstat -q -m erofs; then
pre15_dut_fail 'B33 kldload returned success without erofs.1 ownership'
fi
if ! pre15_guest_ssh_bounded kldstat -q -n B33-erofs-zstdio0.ko; then
pre15_dut_fail 'B33 kldload returned success without exact KLD file ownership'
fi
pre15_guest_ssh_bounded kldstat >"$artifacts/guest-kldstat-after-load.txt"
pre15_guest_ssh_bounded dmesg >"$artifacts/guest-dmesg-before.txt"
diff -u "$artifacts/guest-dmesg-before-load.txt" \
"$artifacts/guest-dmesg-before.txt" >"$artifacts/guest-dmesg-load.diff" || true
sed -n '/^+++ /d; /^+/s/^+//p' "$artifacts/guest-dmesg-load.diff" \
>"$artifacts/guest-dmesg-load-added.txt"
if grep -Eqi 'panic:|lock order reversal|witness.*warning|use-after-free|fatal trap|pager fault|linker.*(error|undefined)|undefined symbol' \
"$artifacts/guest-dmesg-load-added.txt"; then
pre15_dut_fail 'B33 exact-source KLD load produced kernel or linker errors'
fi
pre15_own_guest_kld B33-erofs-zstdio0.ko 'B33 exact-source KLD'
pre15_guest_ssh_bounded kldstat >"$artifacts/guest-kldstat-before-trace.txt"
if ! pre15_guest_ssh_bounded command -v dtrace \
>"$artifacts/guest-dtrace-command.txt" 2>"$artifacts/guest-dtrace-command.stderr"; then
pre15_infra_blocked 'guest dtrace tool is unavailable for B33 call proof'
fi
set +e
pre15_guest_ssh_bounded kldload dtraceall \
>"$artifacts/guest-dtrace-kldload.stdout" \
2>"$artifacts/guest-dtrace-kldload.stderr"
dtrace_load_rc=$?
set -e
pre15_guest_ssh_bounded kldstat >"$artifacts/guest-kldstat-after-trace.txt"
awk 'NR == FNR { if (FNR > 1) seen[$5] = 1; next }
FNR > 1 && !seen[$5] { print $1 "\t" $5 }' \
"$artifacts/guest-kldstat-before-trace.txt" \
"$artifacts/guest-kldstat-after-trace.txt" \
>"$artifacts/guest-trace-klds-all.tsv"
awk '$2 == "dtraceall.ko"' "$artifacts/guest-trace-klds-all.tsv" \
>"$artifacts/guest-trace-klds.tsv"
while IFS="$(printf '\t')" read -r trace_kld_id trace_kld_name; do
test -n "$trace_kld_id" || continue
pre15_own_guest_kld "$trace_kld_name" 'B33 FBT call-proof dependency'
done <"$artifacts/guest-trace-klds.tsv"
test "$dtrace_load_rc" -eq 0 || \
pre15_infra_blocked 'guest dtraceall KLD failed to load for B33 call proof'
if ! pre15_guest_ssh_bounded \
"dtrace -l -n 'fbt::z_erofs_extent_cache_init:entry' -n 'fbt::z_erofs_do_read:entry'" \
>"$artifacts/guest-dtrace-probe-list.txt" \
2>"$artifacts/guest-dtrace-probe-list.stderr"; then
pre15_infra_blocked 'B33 cache init/read FBT probes are unavailable'
fi
grep -q 'z_erofs_extent_cache_init.*entry' \
"$artifacts/guest-dtrace-probe-list.txt" || \
pre15_runner_fail 'B33 cache init FBT probe was not listed exactly'
grep -q 'z_erofs_do_read.*entry' \
"$artifacts/guest-dtrace-probe-list.txt" || \
pre15_runner_fail 'B33 compressed-read FBT probe was not listed exactly'
b33_unown()
{
kind=$1
value=$2
tmp=$PRE15_CASE_TMP/ownership.$$
awk -F ' ' -v kind="$kind" -v value="$value" \
'!($1 == kind && $2 == value)' "$PRE15_OWNERSHIP_FILE" >"$tmp"
mv "$tmp" "$PRE15_OWNERSHIP_FILE"
}
b33_attach()
{
image=$1
label=$2
B33_MD=$(pre15_guest_ssh_bounded mdconfig -a -t vnode \
-f "/root/B33-fixtures/images/$image") || \
pre15_dut_fail "$label md attach failed"
case "$B33_MD" in
md[0-9]*) ;;
*) pre15_runner_fail "unexpected B33 md unit: $B33_MD" ;;
esac
pre15_own_guest_md "$B33_MD" "$label md"
B33_MOUNT=/mnt/pre15-b33-$label
pre15_guest_ssh_bounded mkdir -p "$B33_MOUNT"
if test "${B33_TRACE_MOUNT:-0}" = 1; then
mount_trace=/tmp/pre15-b33-cache-init.trace
pre15_guest_ssh_bounded \
"dtrace -q -o '$mount_trace' -n 'fbt::z_erofs_extent_cache_init:entry { @calls = count(); } END { printa(@calls); }' -c 'mount -t erofs -o ro /dev/$B33_MD $B33_MOUNT'" \
>"$artifacts/valid-mount.stdout" \
2>"$artifacts/valid-mount.stderr" || \
pre15_dut_fail "$label traced mount failed"
pre15_guest_ssh_bounded cat "$mount_trace" \
>"$artifacts/guest-cache-init-fbt.txt"
if ! awk '$1 ~ /^[0-9]+$/ && $1 > 0 { found = 1 }
END { exit !found }' "$artifacts/guest-cache-init-fbt.txt"; then
pre15_dut_fail 'B33 guest mount did not call decoded-cache init'
fi
else
pre15_guest_ssh_bounded mount -t erofs -o ro "/dev/$B33_MD" "$B33_MOUNT" || \
pre15_dut_fail "$label mount failed"
fi
pre15_own_guest_mount "$B33_MOUNT" "$label mount"
}
b33_detach()
{
if pre15_guest_ssh_bounded mount | grep -F " on $B33_MOUNT " >/dev/null; then
pre15_guest_ssh_bounded umount "$B33_MOUNT" || \
pre15_dut_fail "$B33_MOUNT unmount failed"
fi
b33_unown guest-mount "$B33_MOUNT"
pre15_guest_ssh_bounded mdconfig -d -u "$B33_MD" || \
pre15_dut_fail "$B33_MD detach failed"
b33_unown guest-md "$B33_MD"
}
reference=/root/B33-fixtures/source/payload.bin
B33_TRACE_MOUNT=1
b33_attach lz4-valid.erofs valid
unset B33_TRACE_MOUNT
trace_file=/tmp/pre15-b33-do-read.trace
if ! pre15_guest_ssh_bounded \
"dtrace -q -o '$trace_file' -n 'fbt::z_erofs_do_read:entry { @calls = count(); } END { printa(@calls); }' -c '/root/B33-cache-probe concurrent $B33_MOUNT/payload.bin $reference 0 64 4 0 65536'" \
>"$artifacts/valid-concurrent.stdout" \
2>"$artifacts/valid-concurrent.stderr"; then
pre15_dut_fail 'TC168 valid full-extent concurrent reads diverged'
fi
if ! grep -qx 'concurrent PASS workers=64 loops=4 assertions=256 errno=0 offset=0 length=65536' \
"$artifacts/valid-concurrent.stdout"; then
pre15_runner_fail 'TC168 valid assertion count was not exactly 256'
fi
pre15_guest_ssh_bounded cat "$trace_file" \
>"$artifacts/guest-do-read-fbt.txt"
if ! awk '$1 ~ /^[0-9]+$/ && $1 > 0 { found = 1 }
END { exit !found }' "$artifacts/guest-do-read-fbt.txt"; then
pre15_dut_fail 'B33 guest reads did not call the target read implementation'
fi
b33_detach
b33_attach lz4-truncated.erofs truncated
if ! pre15_guest_ssh_bounded /root/B33-cache-probe concurrent \
"$B33_MOUNT/payload.bin" "$reference" 97 1 1 0 65536 \
>"$artifacts/failure-single.stdout" \
2>"$artifacts/failure-single.stderr"; then
pre15_dut_fail 'TC168 single corrupt read did not return EINTEGRITY'
fi
if ! grep -qx 'concurrent PASS workers=1 loops=1 assertions=1 errno=97 offset=0 length=65536' \
"$artifacts/failure-single.stdout"; then
pre15_runner_fail 'TC168 single corrupt assertion count was not 1'
fi
if ! pre15_guest_ssh_bounded /root/B33-cache-probe concurrent \
"$B33_MOUNT/payload.bin" "$reference" 97 64 2 0 65536 \
>"$artifacts/failure-concurrent.stdout" \
2>"$artifacts/failure-concurrent.stderr"; then
pre15_dut_fail 'TC168 failure waiters did not receive EINTEGRITY'
fi
if ! grep -qx 'concurrent PASS workers=64 loops=2 assertions=128 errno=97 offset=0 length=65536' \
"$artifacts/failure-concurrent.stdout"; then
pre15_runner_fail 'TC168 failure assertion count was not exactly 128'
fi
b33_detach
pre15_guest_ssh_bounded dmesg >"$artifacts/guest-dmesg-after.txt"
diff -u "$artifacts/guest-dmesg-before.txt" \
"$artifacts/guest-dmesg-after.txt" >"$artifacts/guest-dmesg.diff" || true
sed -n '/^+++ /d; /^+/s/^+//p' "$artifacts/guest-dmesg.diff" \
>"$artifacts/guest-dmesg-added.txt"
if grep -Eqi 'panic:|lock order reversal|witness.*warning|use-after-free|fatal trap|pager fault|linker.*(error|undefined)|undefined symbol' \
"$artifacts/guest-dmesg-added.txt"; then
pre15_dut_fail 'TC168 produced panic, WITNESS, or UAF evidence'
fi
printf '%s\n' \
'TC168-cache-inflight B33 QEMU PASS' \
'Exact KLD ownership, FBT-proven cache init/read calls, full-extent success/failure waiters, unmount drain, and cleanup exercised' \
'TC130 and full feature suite NOT_RUN'