update
This commit is contained in:
Executable
+319
@@ -0,0 +1,319 @@
|
||||
#!/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_FREEBSD_SRC:?PRE15_FREEBSD_SRC is required}"
|
||||
: "${PRE15_LIB_DIR:?PRE15_LIB_DIR is required}"
|
||||
. "$PRE15_LIB_DIR/runner.sh"
|
||||
|
||||
probe=$PRE15_DUT/tests/pre15/probes/ondisk_layout.c
|
||||
freebsd_header=$PRE15_DUT/src/erofs_fs.h
|
||||
internal_header=$PRE15_DUT/src/internal.h
|
||||
linux_header=$PRE15_ROOT/src-linux/erofs_fs.h
|
||||
sys=$PRE15_FREEBSD_SRC/sys
|
||||
target=x86_64-unknown-freebsd15.0
|
||||
artifacts=$PRE15_RUN_DIR/artifacts
|
||||
include_root=$PRE15_CASE_TMP/include
|
||||
|
||||
for tool in clang python3 sha256sum; do
|
||||
command -v "$tool" >/dev/null 2>&1 || \
|
||||
pre15_infra_blocked "missing B02 host tool: $tool"
|
||||
done
|
||||
test -d "$sys/amd64/include" || \
|
||||
pre15_infra_blocked "FreeBSD amd64 headers are absent: $sys"
|
||||
|
||||
pre15_record_fixture b02-layout-probe "$probe"
|
||||
pre15_record_fixture b02-freebsd-ondisk-header "$freebsd_header"
|
||||
pre15_record_fixture b02-freebsd-internal-header "$internal_header"
|
||||
pre15_record_fixture b02-linux-ondisk-header "$linux_header"
|
||||
|
||||
mkdir -p "$artifacts" "$include_root"
|
||||
ln -s "$sys/amd64/include" "$include_root/machine"
|
||||
ln -s "$sys/x86/include" "$include_root/x86"
|
||||
resource_include=$(clang -print-resource-dir)/include
|
||||
pre15_target_reached
|
||||
|
||||
if clang --target="$target" -fsyntax-only -std=gnu17 -Wall -Wextra -Werror \
|
||||
-nostdinc -isystem "$resource_include" \
|
||||
-isystem "$PRE15_FREEBSD_SRC/include" -isystem "$include_root" \
|
||||
-isystem "$sys" -Xclang -fdump-record-layouts "$probe" \
|
||||
> "$artifacts/freebsd-record-layouts.txt" \
|
||||
2> "$artifacts/freebsd-layout.stderr"; then
|
||||
:
|
||||
else
|
||||
pre15_dut_fail 'FreeBSD ondisk layout/type/macro oracle failed'
|
||||
fi
|
||||
if clang -DB02_LINUX_REFERENCE -fsyntax-only -std=gnu17 \
|
||||
-Wall -Wextra -Werror -Xclang -fdump-record-layouts "$probe" \
|
||||
> "$artifacts/linux-record-layouts.txt" \
|
||||
2> "$artifacts/linux-layout.stderr"; then
|
||||
:
|
||||
else
|
||||
pre15_dut_fail 'Linux reference layout/type/macro oracle failed'
|
||||
fi
|
||||
|
||||
clang --target="$target" -E -dM -std=gnu17 -nostdinc \
|
||||
-isystem "$resource_include" -isystem "$PRE15_FREEBSD_SRC/include" \
|
||||
-isystem "$include_root" -isystem "$sys" "$probe" | \
|
||||
awk '$2 ~ /^(EROFS_|Z_EROFS_)/ { print }' | LC_ALL=C sort \
|
||||
> "$artifacts/freebsd-macros.txt"
|
||||
clang -DB02_LINUX_REFERENCE -E -dM -std=gnu17 "$probe" | \
|
||||
awk '$2 ~ /^(EROFS_|Z_EROFS_)/ { print }' | LC_ALL=C sort \
|
||||
> "$artifacts/linux-macros.txt"
|
||||
|
||||
if python3 - "$PRE15_ROOT" "$artifacts/static-check.json" <<'PY'
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
root = Path(sys.argv[1])
|
||||
output = Path(sys.argv[2])
|
||||
dut = root / "repo-pre-15"
|
||||
src = dut / "src"
|
||||
ondisk = (src / "erofs_fs.h").read_text(encoding="utf-8")
|
||||
internal = (src / "internal.h").read_text(encoding="utf-8")
|
||||
linux = (root / "src-linux/erofs_fs.h").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def require_once(source: str, token: str) -> None:
|
||||
count = source.count(token)
|
||||
if count != 1:
|
||||
raise SystemExit(f"expected one occurrence of {token!r}, found {count}")
|
||||
|
||||
|
||||
def require_order(source: str, tokens: tuple[str, ...], label: str) -> None:
|
||||
positions = []
|
||||
for token in tokens:
|
||||
require_once(source, token)
|
||||
positions.append(source.index(token))
|
||||
if positions != sorted(positions):
|
||||
raise SystemExit(f"{label} section order mismatch: {tokens!r}")
|
||||
|
||||
|
||||
ondisk_markers = (
|
||||
"struct erofs_deviceslot {",
|
||||
"struct erofs_super_block {",
|
||||
"EROFS_INODE_CHUNK_BASED",
|
||||
"#define EROFS_CHUNK_FORMAT_BLKBITS_MASK",
|
||||
"#define EROFS_INODE_LAYOUT_COMPACT",
|
||||
"struct erofs_inode_chunk_info {",
|
||||
"struct erofs_inode_compact {",
|
||||
"struct erofs_inode_extended {",
|
||||
"struct erofs_xattr_ibody_header {",
|
||||
"struct erofs_xattr_entry {",
|
||||
"struct erofs_xattr_long_prefix {",
|
||||
"#define EROFS_NULL_ADDR",
|
||||
"struct erofs_inode_chunk_index {",
|
||||
"#define EROFS_DIRENT_NID_METABOX_BIT",
|
||||
"struct erofs_dirent {",
|
||||
"#define EROFS_NAME_LEN",
|
||||
"struct z_erofs_lz4_cfgs {",
|
||||
"struct z_erofs_map_header {",
|
||||
"Z_EROFS_LCLUSTER_TYPE_PLAIN",
|
||||
"struct z_erofs_lcluster_index {",
|
||||
"struct z_erofs_extent {",
|
||||
)
|
||||
require_order(ondisk, ondisk_markers, "FreeBSD ondisk")
|
||||
require_order(linux, ondisk_markers, "Linux ondisk")
|
||||
|
||||
aliases = {
|
||||
"EROFS_INODE_LAYOUT_COMPACT": "0",
|
||||
"EROFS_INODE_LAYOUT_EXTENDED": "1",
|
||||
"EROFS_INODE_LAYOUT_PLAIN": "EROFS_INODE_FLAT_PLAIN",
|
||||
}
|
||||
for name, value in aliases.items():
|
||||
pattern = rf"^#define[ \t]+{name}[ \t]+{value}$"
|
||||
if len(re.findall(pattern, ondisk, re.MULTILINE)) != 1:
|
||||
raise SystemExit(f"layout alias mismatch: {name}")
|
||||
|
||||
if not re.search(
|
||||
r"^#define[ \t]+EROFS_DEVT_SLOT_SIZE[ \t]+"
|
||||
r"sizeof\(struct erofs_deviceslot\)$",
|
||||
ondisk,
|
||||
re.MULTILINE,
|
||||
):
|
||||
raise SystemExit("EROFS_DEVT_SLOT_SIZE is not derived from its record")
|
||||
if re.search(r"^#if.*EROFS_DEVT_SLOT_SIZE", ondisk, re.MULTILINE):
|
||||
raise SystemExit("sizeof-based EROFS_DEVT_SLOT_SIZE is used in #if")
|
||||
|
||||
internal_markers = (
|
||||
"struct erofs_mount_opts {",
|
||||
"struct erofs_sb_lz4_info {",
|
||||
"struct erofs_device_info {",
|
||||
"struct erofs_xattr_prefix_item {",
|
||||
"struct erofs_zextent_cache {",
|
||||
"struct erofs_mount {",
|
||||
"#define EROFS_FEATURE_FUNCS",
|
||||
"EROFS_FEATURE_FUNCS(lz4_0padding",
|
||||
"struct erofs_node {",
|
||||
"struct erofs_fid {",
|
||||
"erofs_inode_version(unsigned int ifmt)",
|
||||
"#define EROFS_MAP_MAPPED",
|
||||
"struct erofs_map_blocks {",
|
||||
"struct erofs_map_dev {",
|
||||
"/* Buffer and device I/O. */",
|
||||
"/* Logical mapping and file data. */",
|
||||
"/* Inode and vnode lifecycle. */",
|
||||
"/* Directory operations. */",
|
||||
"/* Compressed mapping and data. */",
|
||||
"/* Compression configuration. */",
|
||||
"/* VOP vectors. */",
|
||||
)
|
||||
require_order(internal, internal_markers, "FreeBSD internal")
|
||||
if re.search(r"return[ \t]+-E[A-Z0-9_]+", internal):
|
||||
raise SystemExit("Linux negative-errno convention entered FreeBSD internal.h")
|
||||
|
||||
vnops = (src / "erofs_vnops.c").read_text(encoding="utf-8")
|
||||
super_source = (src / "super.c").read_text(encoding="utf-8")
|
||||
inode = (src / "inode.c").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def initializer(source: str, declaration: str, prefix: str) -> list[tuple[str, str]]:
|
||||
match = re.search(re.escape(declaration) + r"\s*=\s*\{(.*?)\n\};", source, re.DOTALL)
|
||||
if not match:
|
||||
raise SystemExit(f"initializer absent: {declaration}")
|
||||
return re.findall(
|
||||
rf"^\s*\.({prefix}_[A-Za-z0-9_]+)\s*=\s*([^,]+),",
|
||||
match.group(1),
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
|
||||
vnode = initializer(vnops, "struct vop_vector erofs_vnodeops", "vop")
|
||||
fifo = initializer(vnops, "struct vop_vector erofs_fifoops", "vop")
|
||||
vfs = initializer(super_source, "static struct vfsops erofs_vfsops", "vfs")
|
||||
expected_vnode = [
|
||||
("vop_default", "&default_vnodeops"),
|
||||
("vop_inactive", "erofs_inactive"),
|
||||
("vop_reclaim", "erofs_reclaim"),
|
||||
("vop_lookup", "vfs_cache_lookup"),
|
||||
("vop_cachedlookup", "erofs_lookup"),
|
||||
("vop_readdir", "erofs_readdir"),
|
||||
("vop_readlink", "erofs_readlink"),
|
||||
("vop_open", "erofs_open"),
|
||||
("vop_read", "erofs_read"),
|
||||
("vop_bmap", "erofs_bmap"),
|
||||
("vop_getpages", "vnode_pager_local_getpages"),
|
||||
("vop_getpages_async", "vnode_pager_local_getpages_async"),
|
||||
("vop_getattr", "erofs_getattr"),
|
||||
("vop_setattr", "erofs_setattr"),
|
||||
("vop_access", "erofs_access"),
|
||||
("vop_pathconf", "erofs_pathconf"),
|
||||
("vop_getextattr", "erofs_getextattr"),
|
||||
("vop_listextattr", "erofs_listextattr"),
|
||||
("vop_deleteextattr", "erofs_deleteextattr"),
|
||||
("vop_setextattr", "erofs_setextattr"),
|
||||
("vop_getacl", "erofs_vop_getacl"),
|
||||
("vop_aclcheck", "erofs_aclcheck"),
|
||||
("vop_setacl", "erofs_setacl"),
|
||||
("vop_vptofh", "erofs_vptofh"),
|
||||
]
|
||||
expected_fifo = [
|
||||
("vop_default", "&fifo_specops"),
|
||||
("vop_access", "erofs_access"),
|
||||
("vop_aclcheck", "erofs_aclcheck"),
|
||||
("vop_deleteextattr", "erofs_deleteextattr"),
|
||||
("vop_getacl", "erofs_vop_getacl"),
|
||||
("vop_getextattr", "erofs_getextattr"),
|
||||
("vop_getattr", "erofs_getattr"),
|
||||
("vop_listextattr", "erofs_listextattr"),
|
||||
("vop_pathconf", "erofs_pathconf"),
|
||||
("vop_reclaim", "erofs_reclaim"),
|
||||
("vop_setacl", "erofs_setacl"),
|
||||
("vop_setattr", "erofs_setattr"),
|
||||
("vop_setextattr", "erofs_setextattr"),
|
||||
("vop_vptofh", "erofs_vptofh"),
|
||||
]
|
||||
expected_vfs = [
|
||||
("vfs_fhtovp", "erofs_fhtovp"),
|
||||
("vfs_mount", "erofs_mount"),
|
||||
("vfs_root", "erofs_root"),
|
||||
("vfs_statfs", "erofs_statfs"),
|
||||
("vfs_unmount", "erofs_unmount"),
|
||||
("vfs_vget", "erofs_vgetf"),
|
||||
]
|
||||
if vnode != expected_vnode or fifo != expected_fifo or vfs != expected_vfs:
|
||||
raise SystemExit("VOP/VFS callback targets changed")
|
||||
|
||||
hash_calls = re.findall(
|
||||
r"vfs_hash_(?:get|insert)\s*\([^;]*?erofs_vfs_hash_cmp", inode, re.DOTALL
|
||||
)
|
||||
if len(hash_calls) != 2:
|
||||
raise SystemExit(f"hash comparator callsites changed: {len(hash_calls)}")
|
||||
|
||||
decompressors = []
|
||||
for path in sorted(src.glob("decompressor*.c")):
|
||||
for line in path.read_text(encoding="utf-8").splitlines():
|
||||
match = re.match(r"\s*\.(config|decompress)\s*=\s*([^,]+),", line)
|
||||
if match:
|
||||
decompressors.append((path.name, match.group(1), match.group(2)))
|
||||
expected_decompressors = [
|
||||
("decompressor.c", "decompress", "z_erofs_transform_plain"),
|
||||
("decompressor.c", "decompress", "z_erofs_transform_plain"),
|
||||
("decompressor.c", "config", "z_erofs_load_lz4_config"),
|
||||
("decompressor.c", "decompress", "z_erofs_lz4_decompress"),
|
||||
("decompressor_deflate.c", "config", "z_erofs_load_deflate_config"),
|
||||
("decompressor_deflate.c", "decompress", "z_erofs_deflate_decompress"),
|
||||
("decompressor_lzma.c", "config", "z_erofs_load_lzma_config"),
|
||||
("decompressor_lzma.c", "decompress", "z_erofs_lzma_decompress"),
|
||||
("decompressor_zstd.c", "config", "z_erofs_load_zstd_config"),
|
||||
("decompressor_zstd.c", "decompress", "z_erofs_zstd_decompress"),
|
||||
]
|
||||
if decompressors != expected_decompressors:
|
||||
raise SystemExit("decompressor callback targets changed")
|
||||
|
||||
result = {
|
||||
"status": "PASS",
|
||||
"source_symbol_denominator": {
|
||||
"baseline_physical": 464,
|
||||
"baseline_unique": 389,
|
||||
"b02_macro_delta": 3,
|
||||
"expected_physical": 467,
|
||||
"expected_unique": 392,
|
||||
"added_names": sorted(aliases),
|
||||
"kld_symbol_delta": 0,
|
||||
},
|
||||
"callbacks": {
|
||||
"vnode_slots": len(vnode),
|
||||
"fifo_slots": len(fifo),
|
||||
"vfs_slots": len(vfs),
|
||||
"hash_comparator_callsites": len(hash_calls),
|
||||
"decompressor_fields": len(decompressors),
|
||||
},
|
||||
"freebsd_adaptations": [
|
||||
"packed ondisk records",
|
||||
"little-endian typedefs",
|
||||
"explicit supported incompat mask",
|
||||
"FreeBSD VOP/VFS types",
|
||||
"positive errno convention",
|
||||
],
|
||||
}
|
||||
with output.open("x", encoding="ascii") as stream:
|
||||
json.dump(result, stream, ensure_ascii=True, indent=2, sort_keys=True)
|
||||
stream.write("\n")
|
||||
print(
|
||||
"static PASS source-symbols=464+3 callbacks=24+14/6 hash=2 decompress=10"
|
||||
)
|
||||
PY
|
||||
then
|
||||
:
|
||||
else
|
||||
pre15_dut_fail 'header order, symbol denominator, or callback oracle failed'
|
||||
fi
|
||||
|
||||
sha256sum \
|
||||
"$artifacts/freebsd-record-layouts.txt" \
|
||||
"$artifacts/linux-record-layouts.txt" \
|
||||
"$artifacts/freebsd-macros.txt" \
|
||||
"$artifacts/linux-macros.txt" \
|
||||
"$artifacts/static-check.json" \
|
||||
> "$artifacts/SHA256SUMS"
|
||||
|
||||
printf 'layout PASS FreeBSD and Linux size/offset/alignment/type/macro oracles\n'
|
||||
Reference in New Issue
Block a user