update
This commit is contained in:
Executable
+570
@@ -0,0 +1,570 @@
|
||||
#!/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=8a8761af91654a025fd991d14da906c0b612bd7d
|
||||
fixture=$PRE15_DUT/tests/pre15/fixtures/B22-zmap-arithmetic.json
|
||||
kld_builder=$PRE15_DUT/tests/pre15/fixtures/B22-build-kld.sh
|
||||
zmap=$PRE15_DUT/src/zmap.c
|
||||
linux_zmap=$PRE15_ROOT/src-linux/zmap.c
|
||||
artifacts=$PRE15_RUN_DIR/artifacts
|
||||
|
||||
for tool in cc git python3 sha256sum; do
|
||||
command -v "$tool" >/dev/null 2>&1 || \
|
||||
pre15_infra_blocked "missing B22 host tool: $tool"
|
||||
done
|
||||
|
||||
pre15_record_fixture b22-arithmetic "$fixture"
|
||||
pre15_record_fixture b22-kld-builder "$kld_builder"
|
||||
pre15_record_fixture b22-case "$PRE15_DUT/tests/pre15/cases/B22-zmap-arithmetic.sh"
|
||||
pre15_record_fixture b22-zmap "$zmap"
|
||||
pre15_record_fixture b22-linux-zmap "$linux_zmap"
|
||||
mkdir -p "$artifacts"
|
||||
pre15_target_reached
|
||||
|
||||
if python3 -B - "$PRE15_ROOT" "$PRE15_DUT" "$baseline" "$fixture" \
|
||||
"$artifacts" <<'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]
|
||||
fixture_path = Path(sys.argv[4])
|
||||
artifacts = Path(sys.argv[5])
|
||||
src = dut / "src"
|
||||
u32_max = (1 << 32) - 1
|
||||
u64_max = (1 << 64) - 1
|
||||
eintegrity = 97
|
||||
|
||||
|
||||
def committed(path: str) -> str:
|
||||
completed = subprocess.run(
|
||||
["git", "-C", str(root), "show", f"{baseline}:repo-pre-15/{path}"],
|
||||
check=False,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
if completed.returncode != 0:
|
||||
raise SystemExit(f"cannot read B22 baseline {path}: {completed.stderr}")
|
||||
return completed.stdout
|
||||
|
||||
|
||||
def function(source: str, name: str) -> str:
|
||||
match = re.search(r"^" + re.escape(name) + r"\s*\(", source, re.MULTILINE)
|
||||
if match is None:
|
||||
raise SystemExit(f"missing function: {name}")
|
||||
name_line = source.rfind("\n", 0, match.start()) + 1
|
||||
start = source.rfind("\n", 0, name_line - 1) + 1
|
||||
brace = source.find("{", match.end())
|
||||
if brace < 0:
|
||||
raise SystemExit(f"missing function body: {name}")
|
||||
depth = 0
|
||||
state = "code"
|
||||
index = brace
|
||||
while index < len(source):
|
||||
char = source[index]
|
||||
following = source[index + 1] if index + 1 < len(source) else ""
|
||||
if state == "code":
|
||||
if char == "/" and following == "*":
|
||||
state = "block"
|
||||
index += 2
|
||||
continue
|
||||
if char == "/" and following == "/":
|
||||
state = "line"
|
||||
index += 2
|
||||
continue
|
||||
if char == '"':
|
||||
state = "string"
|
||||
elif char == "'":
|
||||
state = "character"
|
||||
elif char == "{":
|
||||
depth += 1
|
||||
elif char == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return source[start : index + 1]
|
||||
elif state == "block" and char == "*" and following == "/":
|
||||
state = "code"
|
||||
index += 2
|
||||
continue
|
||||
elif state == "line" and char == "\n":
|
||||
state = "code"
|
||||
elif state in {"string", "character"}:
|
||||
if char == "\\":
|
||||
index += 2
|
||||
continue
|
||||
if (state == "string" and char == '"') or (
|
||||
state == "character" and char == "'"
|
||||
):
|
||||
state = "code"
|
||||
index += 1
|
||||
raise SystemExit(f"unterminated function: {name}")
|
||||
|
||||
|
||||
def add(left: int, right: int) -> tuple[str, int | None]:
|
||||
value = left + right
|
||||
if value > u64_max:
|
||||
return ("EINTEGRITY", None)
|
||||
return ("PASS", value)
|
||||
|
||||
|
||||
def multiply(left: int, right: int) -> tuple[str, int | None]:
|
||||
value = left * right
|
||||
if value > u64_max:
|
||||
return ("EINTEGRITY", None)
|
||||
return ("PASS", value)
|
||||
|
||||
|
||||
def model(case: dict[str, object]) -> tuple[str, int | None]:
|
||||
operation = case["operation"]
|
||||
if operation == "compact_pblk":
|
||||
return add(int(case["base"]), int(case["nblk"]))
|
||||
if operation == "index_base":
|
||||
status, end = add(int(case["inode_off"]), int(case["inode_isize"]))
|
||||
if status != "PASS":
|
||||
return (status, None)
|
||||
status, end = add(int(end), int(case.get("xattr_isize", 0)))
|
||||
if status != "PASS":
|
||||
return (status, None)
|
||||
status, end = add(int(end), 7)
|
||||
if status != "PASS":
|
||||
return (status, None)
|
||||
end = int(end) & ~7
|
||||
return add(end, 8)
|
||||
if operation == "index_advance":
|
||||
status, delta = multiply(int(case["count"]), int(case["unit"]))
|
||||
if status != "PASS":
|
||||
return (status, None)
|
||||
return add(int(case["position"]), int(delta))
|
||||
if operation == "lcluster_count":
|
||||
bits = int(case["lclusterbits"])
|
||||
if bits >= 64:
|
||||
return ("EINTEGRITY", None)
|
||||
size = int(case["size"])
|
||||
count = size >> bits
|
||||
if size & ((1 << bits) - 1):
|
||||
return add(count, 1)
|
||||
return ("PASS", count)
|
||||
if operation == "lcluster_pos":
|
||||
bits = int(case["lclusterbits"])
|
||||
if bits >= 64:
|
||||
return ("EINTEGRITY", None)
|
||||
status, base = multiply(int(case["lcn"]), 1 << bits)
|
||||
if status != "PASS":
|
||||
return (status, None)
|
||||
return add(int(base), int(case["clusterofs"]))
|
||||
if operation == "lcn_advance":
|
||||
return add(int(case["lcn"]), int(case["delta"]))
|
||||
if operation == "physical_end":
|
||||
status, pend = add(int(case["pa"]), int(case["plen"]))
|
||||
if status != "PASS":
|
||||
return (status, None)
|
||||
limit = (1 << 48) * int(case["block_size"])
|
||||
if limit <= u64_max and int(pend) > limit:
|
||||
return ("EINTEGRITY", None)
|
||||
return ("PASS", None)
|
||||
if operation == "post_eof":
|
||||
la = int(case["la"])
|
||||
size = int(case["size"])
|
||||
if la < size:
|
||||
return ("EINTEGRITY", None)
|
||||
length = la - size + 1
|
||||
return ("PASS", min(length, u64_max))
|
||||
if operation == "fragment_offset":
|
||||
low = int(case["low"])
|
||||
high = int(case["high"])
|
||||
if low > u32_max or high > u32_max:
|
||||
return ("EINTEGRITY", None)
|
||||
return ("PASS", low | (high << 32))
|
||||
raise SystemExit(f"unknown B22 operation: {operation}")
|
||||
|
||||
|
||||
fixture = json.loads(fixture_path.read_text(encoding="ascii"))
|
||||
if fixture.get("schema") != 1 or fixture.get("batch") != "B22":
|
||||
raise SystemExit("invalid B22 fixture identity")
|
||||
if fixture.get("test") != "TC170-zmap-arithmetic":
|
||||
raise SystemExit("invalid B22 test identity")
|
||||
if fixture.get("candidates") != [
|
||||
"P15-047",
|
||||
"P15-059",
|
||||
"P15-071",
|
||||
"P15-079",
|
||||
"P15-084",
|
||||
]:
|
||||
raise SystemExit("B22 candidate set changed")
|
||||
if fixture.get("errno") != {
|
||||
"corruption": eintegrity,
|
||||
"provider_io": "unchanged",
|
||||
"sign": "positive",
|
||||
}:
|
||||
raise SystemExit("B22 errno contract changed")
|
||||
|
||||
cases = fixture.get("cases")
|
||||
if not isinstance(cases, list) or not cases:
|
||||
raise SystemExit("B22 fixture has no cases")
|
||||
names: set[str] = set()
|
||||
markers: set[str] = set()
|
||||
operations: set[str] = set()
|
||||
decoded: list[dict[str, object]] = []
|
||||
for case in cases:
|
||||
if not isinstance(case, dict):
|
||||
raise SystemExit("B22 fixture case is not an object")
|
||||
name = str(case.get("name", ""))
|
||||
marker = str(case.get("target_marker", ""))
|
||||
if not name or name in names or not marker.startswith("TC170:"):
|
||||
raise SystemExit(f"invalid B22 case identity: {name!r}")
|
||||
names.add(name)
|
||||
markers.add(marker)
|
||||
operations.add(str(case.get("operation", "")))
|
||||
status, value = model(case)
|
||||
if status != case.get("status"):
|
||||
raise SystemExit(f"B22 independent status mismatch: {name}")
|
||||
if status == "PASS" and value is not None and value != case.get("expected"):
|
||||
raise SystemExit(f"B22 independent value mismatch: {name}")
|
||||
mutated = case.get("mutated_fields")
|
||||
if status == "EINTEGRITY" and (
|
||||
not isinstance(mutated, list) or len(mutated) != 1
|
||||
):
|
||||
raise SystemExit(f"B22 negative is not single-field: {name}")
|
||||
if status == "PASS" and mutated != []:
|
||||
raise SystemExit(f"B22 positive declares a mutation: {name}")
|
||||
decoded.append({"name": name, "status": status, "value": value})
|
||||
|
||||
required_markers = {
|
||||
"TC170:compact-pblk-32bit-crossing",
|
||||
"TC170:index-position",
|
||||
"TC170:delta-lcn",
|
||||
"TC170:physical-end-48bit",
|
||||
"TC170:post-eof",
|
||||
"TC170:fragment-high-bits",
|
||||
}
|
||||
if markers != required_markers:
|
||||
raise SystemExit("B22 target-marker set is incomplete")
|
||||
if operations != {
|
||||
"compact_pblk",
|
||||
"fragment_offset",
|
||||
"index_advance",
|
||||
"index_base",
|
||||
"lcluster_count",
|
||||
"lcluster_pos",
|
||||
"lcn_advance",
|
||||
"physical_end",
|
||||
"post_eof",
|
||||
}:
|
||||
raise SystemExit("B22 operation set is incomplete")
|
||||
|
||||
current = (src / "zmap.c").read_text(encoding="utf-8")
|
||||
base = committed("src/zmap.c")
|
||||
linux = (root / "src-linux/zmap.c").read_text(encoding="utf-8")
|
||||
helpers = [
|
||||
"z_erofs_index_base",
|
||||
"z_erofs_index_advance",
|
||||
"z_erofs_lcluster_count",
|
||||
"z_erofs_lcluster_pos",
|
||||
"z_erofs_lcn_advance",
|
||||
"z_erofs_compact_pblk",
|
||||
"z_erofs_fragment_offset",
|
||||
"z_erofs_post_eof_len",
|
||||
"z_erofs_physical_end",
|
||||
]
|
||||
for helper in helpers:
|
||||
if helper in base or current.count(helper) < 2:
|
||||
raise SystemExit(f"B22 helper is missing, duplicated, or pre-existing: {helper}")
|
||||
|
||||
old_freebsd = (
|
||||
"m->pblk = le32dec(in + packsize - sizeof(uint32_t)) + nblk;",
|
||||
"map->m_llen = map->m_la + 1 - vi->size;",
|
||||
"vi->z_fragmentoff |= map->m_pa << 32;",
|
||||
"lcn += m->delta[1];",
|
||||
"pos += lcn << amortizedshift;",
|
||||
"(pend >> sbi->blkszbits) >= (1ULL << 48)",
|
||||
)
|
||||
if not all(anchor in base for anchor in old_freebsd):
|
||||
raise SystemExit("B22 baseline arithmetic anchors changed")
|
||||
if any(anchor in current for anchor in old_freebsd):
|
||||
raise SystemExit("B22 left an unchecked baseline arithmetic anchor")
|
||||
linux_anchors = (
|
||||
"m->pblk = le32_to_cpu(*(__le32 *)in) + nblk;",
|
||||
"map->m_llen = map->m_la + 1 - inode->i_size;",
|
||||
"vi->z_fragmentoff |= map->m_pa << 32;",
|
||||
"lcn += m->delta[1];",
|
||||
"(pend >> sbi->blkszbits) >= BIT_ULL(48)",
|
||||
)
|
||||
if not all(anchor in linux for anchor in linux_anchors):
|
||||
raise SystemExit("Linux zmap semantic anchor changed")
|
||||
if function(current, "z_erofs_read_index") != function(base, "z_erofs_read_index"):
|
||||
raise SystemExit("B22 changed the FreeBSD metadata/provider reader")
|
||||
if current.count("erofs_read_metadata") != base.count("erofs_read_metadata"):
|
||||
raise SystemExit("B22 changed metadata I/O call count")
|
||||
if current.count("erofs_put_metabuf") != base.count("erofs_put_metabuf"):
|
||||
raise SystemExit("B22 changed metadata release call count")
|
||||
for public in ("z_erofs_fill_inode", "z_erofs_map_blocks"):
|
||||
old_signature = function(base, public).split("{", 1)[0]
|
||||
new_signature = function(current, public).split("{", 1)[0]
|
||||
if old_signature != new_signature:
|
||||
raise SystemExit(f"B22 changed public zmap ABI: {public}")
|
||||
if re.search(r"return\s*\(\s*-E[A-Z0-9_]+", current):
|
||||
raise SystemExit("B22 introduced Linux negative errno")
|
||||
|
||||
legacy_mismatches: set[str] = set()
|
||||
for case in cases:
|
||||
operation = case["operation"]
|
||||
status = case["status"]
|
||||
expected = case.get("expected")
|
||||
if operation == "compact_pblk" and status == "PASS":
|
||||
old = (int(case["base"]) + int(case["nblk"])) & u32_max
|
||||
if old != expected:
|
||||
legacy_mismatches.add("compact-pblk")
|
||||
elif operation == "index_advance" and status == "EINTEGRITY":
|
||||
old = (int(case["position"]) + int(case["count"]) * int(case["unit"])) & u64_max
|
||||
if old <= u64_max:
|
||||
legacy_mismatches.add("index-position")
|
||||
elif operation == "lcluster_pos" and status == "EINTEGRITY":
|
||||
old = ((int(case["lcn"]) << int(case["lclusterbits"])) + int(case["clusterofs"])) & u64_max
|
||||
if old <= u64_max:
|
||||
legacy_mismatches.add("delta-lcn")
|
||||
elif operation == "physical_end" and case["name"] == "physical-last-48bit-block":
|
||||
pend = int(case["pa"]) + int(case["plen"])
|
||||
if (pend >> 12) >= (1 << 48):
|
||||
legacy_mismatches.add("physical-end")
|
||||
elif operation == "post_eof" and case["name"] == "post-eof-saturates-empty-inode":
|
||||
old = ((int(case["la"]) + 1) & u64_max) - int(case["size"])
|
||||
if old != expected:
|
||||
legacy_mismatches.add("post-eof")
|
||||
elif operation == "fragment_offset" and status == "EINTEGRITY":
|
||||
old = int(case["low"]) | ((int(case["high"]) << 32) & u64_max)
|
||||
if old <= u64_max:
|
||||
legacy_mismatches.add("fragment-high")
|
||||
if legacy_mismatches != {
|
||||
"compact-pblk",
|
||||
"delta-lcn",
|
||||
"fragment-high",
|
||||
"index-position",
|
||||
"physical-end",
|
||||
"post-eof",
|
||||
}:
|
||||
raise SystemExit("B22 fixtures do not distinguish every legacy bug")
|
||||
|
||||
helper_source = "\n\n".join(function(current, name) for name in helpers)
|
||||
c_lines = [
|
||||
"#include <stdint.h>",
|
||||
"#include <stdio.h>",
|
||||
"#define EINTEGRITY 97",
|
||||
"#define rounddown2(x, y) ((x) & ~((y) - 1))",
|
||||
"typedef uint64_t erofs_off_t;",
|
||||
"typedef uint64_t erofs_blk_t;",
|
||||
"struct z_erofs_map_header { uint8_t bytes[8]; };",
|
||||
"struct erofs_inode { erofs_off_t inode_off; unsigned int inode_isize; unsigned int xattr_isize; };",
|
||||
helper_source,
|
||||
"int main(void)",
|
||||
"{",
|
||||
"\tuint64_t value;",
|
||||
"\tint error, failures = 0;",
|
||||
]
|
||||
|
||||
|
||||
def u64(value: object) -> str:
|
||||
return f"UINT64_C({int(value)})"
|
||||
|
||||
|
||||
for case in cases:
|
||||
name = str(case["name"])
|
||||
operation = case["operation"]
|
||||
expected_error = 0 if case["status"] == "PASS" else eintegrity
|
||||
c_lines.append(f"\t/* {name} */")
|
||||
if operation == "compact_pblk":
|
||||
call = f"z_erofs_compact_pblk(UINT32_C({int(case['base'])}), {int(case['nblk'])}U, &value)"
|
||||
elif operation == "index_base":
|
||||
c_lines.extend([
|
||||
"\t{",
|
||||
"\t\tstruct erofs_inode vi = {",
|
||||
f"\t\t\t.inode_off = {u64(case['inode_off'])},",
|
||||
f"\t\t\t.inode_isize = {int(case['inode_isize'])}U,",
|
||||
f"\t\t\t.xattr_isize = {int(case.get('xattr_isize', 0))}U,",
|
||||
"\t\t};",
|
||||
])
|
||||
call = "z_erofs_index_base(&vi, &value)"
|
||||
elif operation == "index_advance":
|
||||
c_lines.append(f"\tvalue = {u64(case['position'])};")
|
||||
call = f"z_erofs_index_advance(&value, {u64(case['count'])}, {u64(case['unit'])})"
|
||||
elif operation == "lcluster_count":
|
||||
call = f"z_erofs_lcluster_count({u64(case['size'])}, {int(case['lclusterbits'])}U, &value)"
|
||||
elif operation == "lcluster_pos":
|
||||
call = f"z_erofs_lcluster_pos({u64(case['lcn'])}, {int(case['lclusterbits'])}U, {u64(case['clusterofs'])}, &value)"
|
||||
elif operation == "lcn_advance":
|
||||
c_lines.append(f"\tvalue = {u64(case['lcn'])};")
|
||||
call = f"z_erofs_lcn_advance(&value, {u64(case['delta'])})"
|
||||
elif operation == "physical_end":
|
||||
call = f"z_erofs_physical_end({u64(case['pa'])}, {u64(case['plen'])}, {u64(case['block_size'])})"
|
||||
elif operation == "post_eof":
|
||||
call = f"z_erofs_post_eof_len({u64(case['la'])}, {u64(case['size'])}, &value)"
|
||||
elif operation == "fragment_offset":
|
||||
call = f"z_erofs_fragment_offset({u64(case['low'])}, {u64(case['high'])}, &value)"
|
||||
else:
|
||||
raise SystemExit(f"cannot generate C for operation: {operation}")
|
||||
c_lines.append(f"\terror = {call};")
|
||||
c_lines.append(f"\tif (error != {expected_error}) {{")
|
||||
c_lines.append(f"\t\tfprintf(stderr, \"{name}: error=%d\\n\", error);")
|
||||
c_lines.append("\t\tfailures++;\n\t}")
|
||||
if case["status"] == "PASS" and "expected" in case:
|
||||
c_lines.append(f"\tif (value != {u64(case['expected'])}) {{")
|
||||
c_lines.append(f"\t\tfprintf(stderr, \"{name}: value mismatch\\n\");")
|
||||
c_lines.append("\t\tfailures++;\n\t}")
|
||||
if operation == "index_base":
|
||||
c_lines.append("\t}")
|
||||
c_lines.extend([
|
||||
"\tif (failures != 0)",
|
||||
"\t\treturn (1);",
|
||||
f"\tprintf(\"B22 extracted arithmetic PASS cases={len(cases)}\\n\");",
|
||||
"\treturn (0);",
|
||||
"}",
|
||||
])
|
||||
c_path = artifacts / "B22-zmap-arithmetic.c"
|
||||
binary = artifacts / "B22-zmap-arithmetic"
|
||||
c_path.write_text("\n".join(c_lines) + "\n", encoding="ascii")
|
||||
compiled = subprocess.run(
|
||||
["cc", "-std=gnu11", "-Wall", "-Wextra", "-Werror", str(c_path), "-o", str(binary)],
|
||||
check=False,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
(artifacts / "B22-compile.stdout").write_text(compiled.stdout, encoding="utf-8")
|
||||
(artifacts / "B22-compile.stderr").write_text(compiled.stderr, encoding="utf-8")
|
||||
if compiled.returncode != 0:
|
||||
raise SystemExit("B22 extracted arithmetic compilation failed")
|
||||
executed = subprocess.run(
|
||||
[str(binary)],
|
||||
check=False,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
(artifacts / "B22-extracted.stdout").write_text(executed.stdout, encoding="utf-8")
|
||||
(artifacts / "B22-extracted.stderr").write_text(executed.stderr, encoding="utf-8")
|
||||
if executed.returncode != 0:
|
||||
raise SystemExit("B22 extracted arithmetic execution failed")
|
||||
|
||||
result = {
|
||||
"status": "PASS",
|
||||
"batch": "B22",
|
||||
"test": "TC170-zmap-arithmetic",
|
||||
"baseline": baseline,
|
||||
"case_count": len(cases),
|
||||
"negative_count": sum(case["status"] == "EINTEGRITY" for case in cases),
|
||||
"target_markers": sorted(markers),
|
||||
"legacy_mismatches": sorted(legacy_mismatches),
|
||||
"freebsd_positive_errno": True,
|
||||
"linux_algorithm_locations_audited": True,
|
||||
"provider_io_calls_unchanged": True,
|
||||
"metadata_release_calls_unchanged": True,
|
||||
"decompressor_abi_unchanged": True,
|
||||
"ondisk_abi_unchanged": True,
|
||||
"qemu_scope": "exact-source KLD load plus extracted helper replay when PRE15_MODE=qemu",
|
||||
"full_feature_suite": "NOT_RUN",
|
||||
}
|
||||
(artifacts / "B22-decoded-cases.json").write_text(
|
||||
json.dumps(decoded, ensure_ascii=True, indent=2, sort_keys=True) + "\n",
|
||||
encoding="ascii",
|
||||
)
|
||||
(artifacts / "B22-result.json").write_text(
|
||||
json.dumps(result, ensure_ascii=True, indent=2, sort_keys=True) + "\n",
|
||||
encoding="ascii",
|
||||
)
|
||||
print(
|
||||
f"B22 host PASS cases={len(cases)} negatives={result['negative_count']} "
|
||||
f"markers={len(markers)}"
|
||||
)
|
||||
PY
|
||||
then
|
||||
:
|
||||
else
|
||||
pre15_dut_fail 'B22 source, fixture, or extracted arithmetic check failed'
|
||||
fi
|
||||
|
||||
sha256sum "$artifacts/B22-zmap-arithmetic.c" \
|
||||
"$artifacts/B22-zmap-arithmetic" \
|
||||
"$artifacts/B22-decoded-cases.json" "$artifacts/B22-result.json" \
|
||||
> "$artifacts/SHA256SUMS"
|
||||
|
||||
if test "${PRE15_MODE:-host}" != qemu; then
|
||||
printf '%s\n' \
|
||||
'TC170 host extracted zmap arithmetic and fixture oracle PASS' \
|
||||
'QEMU exact-source KLD load and FreeBSD helper replay NOT_RUN in host mode'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for tool in awk clang file nm scp; do
|
||||
command -v "$tool" >/dev/null 2>&1 || \
|
||||
pre15_infra_blocked "missing B22 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}"
|
||||
|
||||
module=$PRE15_CASE_TMP/B22-erofs.ko
|
||||
if ! /bin/sh "$kld_builder" "$PRE15_DUT" "$PRE15_FREEBSD_SRC" "$module" \
|
||||
"$PRE15_CASE_TMP/kld-work" >"$artifacts/B22-kld-build.stdout" \
|
||||
2>"$artifacts/B22-kld-build.stderr"; then
|
||||
pre15_dut_fail 'B22 cross-target KLD build failed'
|
||||
fi
|
||||
pre15_record_module "$module"
|
||||
file "$module" > "$artifacts/B22-kld-file.txt"
|
||||
sha256sum "$module" > "$artifacts/B22-kld-sha256.txt"
|
||||
nm -u "$module" | LC_ALL=C sort > "$artifacts/B22-kld-nm-u.txt"
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
if ! pre15_scp "$module" /root/B22-erofs.ko || \
|
||||
! pre15_scp "$artifacts/B22-zmap-arithmetic.c" \
|
||||
/root/B22-zmap-arithmetic.c; then
|
||||
pre15_infra_blocked 'could not transfer B22 module or arithmetic source'
|
||||
fi
|
||||
if pre15_guest_ssh_bounded kldstat -n erofs >/dev/null 2>&1; then
|
||||
pre15_infra_blocked 'FreeBSD guest already has an EROFS module loaded'
|
||||
fi
|
||||
if ! pre15_guest_ssh_bounded kldload /root/B22-erofs.ko \
|
||||
>"$artifacts/B22-kldload.stdout" 2>"$artifacts/B22-kldload.stderr"; then
|
||||
if grep -q 'module already loaded or in kernel' \
|
||||
"$artifacts/B22-kldload.stderr"; then
|
||||
pre15_infra_blocked 'guest kernel already owns the erofs.1 interface'
|
||||
fi
|
||||
pre15_dut_fail 'B22 exact-source KLD failed to load'
|
||||
fi
|
||||
pre15_own_guest_kld erofs 'B22 exact-source KLD'
|
||||
if ! pre15_guest_ssh_bounded cc -std=gnu11 -Wall -Wextra -Werror \
|
||||
/root/B22-zmap-arithmetic.c -o /root/B22-zmap-arithmetic; then
|
||||
pre15_infra_blocked 'could not compile B22 arithmetic helper in the guest'
|
||||
fi
|
||||
if ! pre15_guest_ssh_bounded /root/B22-zmap-arithmetic \
|
||||
>"$artifacts/B22-guest-arithmetic.stdout" \
|
||||
2>"$artifacts/B22-guest-arithmetic.stderr"; then
|
||||
pre15_dut_fail 'B22 FreeBSD arithmetic helper replay failed'
|
||||
fi
|
||||
pre15_guest_ssh_bounded kldstat -n erofs > "$artifacts/B22-kldstat.txt"
|
||||
printf '%s\n' \
|
||||
'TC170 QEMU PASS exact-source KLD load and FreeBSD arithmetic helper replay' \
|
||||
'No full feature suite or shared GEOM provider was used'
|
||||
Reference in New Issue
Block a user