Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,14 @@ jobs:
- 'tests/qemu/Dockerfile.dlm-harness-h4'
- 'tests/qemu/init_dlm_h4.sh'
- 'tests/qemu/run_dlm_harness_h4.sh'
# H5 (rd vms-6ca, THE ASYNC-REPLY WIRE): after the join, node A holds
# RESONE then a second incompatible $ENQ QUEUES on node B; B WIREs a
# queued-reply (A's origin record PENDING) then, on A's $DEQ, WIREs
# the deferred GRANT -> A's origin record flips NL->EX. Proves the
# block-then-grant on the REQUESTER node across the live SCS wire.
- 'tests/qemu/Dockerfile.dlm-harness-h5'
- 'tests/qemu/init_dlm_h5.sh'
- 'tests/qemu/run_dlm_harness_h5.sh'
- 'tests/cluster/two-ovmx/mk_sysgen_scratch.py'
- 'tests/cluster/two-ovmx/verdict.sh'

Expand Down Expand Up @@ -2604,6 +2612,85 @@ jobs:
path: h4out/
if-no-files-found: ignore

# -----------------------------------------------------------------------
# DLM Harness H5 (rd vms-6ca) -- THE ASYNC-REPLY SCS WIRE: block-then-grant on
# the REQUESTER node. tests/qemu/Dockerfile.dlm-harness-h5 builds the SAME
# real-executive ingredients as H4 (vms.ko -- now with the requester-side GRANT
# RECEIVE + the deferred-grant report -- SCSD.EXE static musl with the H5 wire
# sequence + sca_l2probe + the two OVMXA/OVMXB SYSGEN stores) and boots the SAME
# TWO QEMU nodes, each with a real /dev/vms, on one shared L2 via a QEMU `socket`
# (mcast) netdev. It runs the SAME join sequencer, then arms node A's
# block-then-grant sequence (OVMX_DLM_ENQ=RESONE OVMX_DLM_H5=1): node A holds
# RESONE, a second incompatible $ENQ QUEUES on node B (B WIREs a queued-reply ->
# A's origin record PENDING), A releases the holder, and node B WIREs the
# deferred GRANT off that real $DEQ -> A's origin record FLIPS NL->EX. H5 PASS
# iff node A prints SCSD-I-DLMH5FLIP (granted_mode=EX -- the flip read back from
# A's OWN executive via GETLKI) and node B prints SCSD-I-DLMDEFER. INV-6: the
# verdict READS A's flip + B's deferred-grant from the nodes' own logs; a
# fabricated wire reply or grant cannot pass. The BLKAST wire is deferred.
# -----------------------------------------------------------------------
dlm-harness-h5:
name: DLM Harness H5 (block-then-grant proven on the REQUESTER over the SCS wire, QEMU)
needs: changes
if: ${{ github.event_name != 'pull_request' || needs.changes.outputs.dlm_harness == 'true' }}
runs-on: ubuntu-latest
# vms.ko + SCSD.EXE build + TWO QEMU boots, each running the join sequencer +
# the multi-step H5 sequence for ~90s. The inner H5_WALL_TIMEOUT (600s) is the
# real budget; this is the OUTER bound so a genuine hang surfaces.
timeout-minutes: 50
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build DLM harness H5 image (gha layer cache)
uses: docker/build-push-action@v6
with:
context: .
file: tests/qemu/Dockerfile.dlm-harness-h5
push: false
load: true
tags: ovmx-dlm-h5:latest
cache-from: type=gha,scope=dlm-harness-h5
cache-to: type=gha,mode=max,scope=dlm-harness-h5

- name: Boot TWO QEMU nodes, drive node A's block-then-grant over the SCS wire
run: |
set +e
# GitHub Linux runners expose /dev/kvm; pass it through so the two
# guests boot under KVM (much faster than TCG). Fall back cleanly if
# a runner lacks it -- the harness auto-detects and uses TCG.
KVM=""
[ -e /dev/kvm ] && KVM="--device /dev/kvm"
mkdir -p "$PWD/h5out"
RAW=$(docker run --rm $KVM -v "$PWD/h5out:/out" ovmx-dlm-h5:latest 2>&1)
RC=$?
set -e
# QEMU serial emits CRLF; strip \r so the line-anchored match holds.
OUTPUT=$(printf '%s\n' "$RAW" | tr -d '\r')
echo "$OUTPUT"
if [ "$RC" -ne 0 ]; then
echo "FAIL: DLM harness H5 exited nonzero"
exit 1
fi
if printf '%s\n' "$OUTPUT" | grep -qE '^ DLM HARNESS H5 PASSED'; then
echo "PASS: node A's QUEUED cross-node request GRANTED on the REQUESTER over the live SCS wire (SCSD-I-DLMH5FLIP granted_mode=EX)."
else
echo "FAIL: H5 verdict 'DLM HARNESS H5 PASSED' not found."
printf '%s\n' "$OUTPUT" | grep -E 'verdict inputs|A_FLIP|granted_mode|A_PEND|B_DEFER|highest join rung|VAXCLMEMBER|DLMENQ|DLMPEND|DLMDEFER|DLMH5FLIP|H5-NODE|MISS:|FAIL:' || true
exit 1
fi

- name: Upload H5 pcap + node logs
if: always()
uses: actions/upload-artifact@v4
with:
name: dlm-harness-h5-artifacts
path: h5out/
if-no-files-found: ignore

# -----------------------------------------------------------------------
# Job 3b: Kernel Executive (vms-e4d, epic vms-6b8 PHASE 0 HARD BARRIER)
#
Expand Down
32 changes: 31 additions & 1 deletion docs/compat/facilities/cluster-dlm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ summary: >
waiting queue (VMS_DLM_STS_QUEUED, not a grant, not a NOQUEUE decline), the
master FIRES a blocking-AST decision naming the remote holder, and a real
cross-node $DEQ releases and grants the blocked request (block-then-grant).
See kernel-executive.yaml for the single-node lock manager this builds on.
Rung H5 (vms-6ca) carries the async replies over the real SCS wire: the master
WIREs the queued-reply and — on a real $DEQ — the deferred GRANT, and the
REQUESTER-SIDE GRANT RECEIVE (was SS$_UNSUPPORTED) completes an
executive-resident origin record on the requesting node, so the block-then-grant
status flip (NL->EX) is observed on the REQUESTER across the wire, not just in
the master's local state. The BLKAST wire is deferred honestly (the holder
releases on its own). See kernel-executive.yaml for the single-node lock manager
this builds on.
last_reviewed: 2026-08-28
items:
- id: cluster-dlm$cross-node-lock
Expand All @@ -38,6 +45,29 @@ items:
real /dev/vms (tests/qemu/test_syssvc_dlm_xnode.c, x86_64 + Alpha LP64). No
fake grants OR blocks — a queued request is a real lock on the master's
queue that releases only on a real $DEQ (INV-6).
- id: cluster-dlm$async-reply-wire
kind: feature
status: partial
authenticity: real
vms: "Async DLM replies (queued-reply + deferred GRANT) delivered over SCS; requester-side completion"
evidence: src/vmsscs/scsd.c
notes: >
vms-6ca rung H5. The master's async replies ride the live SCS wire: node B
WIREs the queued-reply (granted mode NL — the requester stays genuinely
pending) and, on a real cross-node $DEQ that flips a queued waiter to
granted, WIREs an unprompted deferred GRANT (SS$_NORMAL, the granted mode)
to that requester (vms_lock_dlm_xnode_deq reports the flipped waiter). The
REQUESTER-SIDE GRANT RECEIVE (VMS_DLM_OP_GRANT, was SS$_UNSUPPORTED)
completes an executive-resident ORIGIN record on the requesting node, whose
granted mode is set ONLY from what the master sent over SCS; GETLKI reads
the NL->EX flip back on the REQUESTER. Proven on a two-node live A<->B QEMU
harness with real /dev/vms on both (tests/qemu/run_dlm_harness_h5.sh:
SCSD-I-DLMPEND, SCSD-I-DLMDEFER, SCSD-I-DLMH5FLIP granted_mode=EX). The
BLKAST wire (master -> holder) is deferred honestly on this rung — BLKAST as
a receive op still returns SS$_UNSUPPORTED; the block-then-grant is proven
without it (the holder releases on its own). Multi-peer routing of a deferred
grant by CSID (releaser and queued waiter on different nodes) is a later
rung; H5 proves the same-peer case. No fabricated wire reply or grant (INV-6).
- id: cluster-dlm$remaster-lvb-deadlock
kind: feature
status: absent
Expand Down
16 changes: 9 additions & 7 deletions docs/compatibility-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

## Inventory

**406 surfaces catalogued** across 9 domains, each with a per-surface status.
**407 surfaces catalogued** across 9 domains, each with a per-surface status.

> This register is an **inventory, not a percentage.** The total VMS compatibility surface has **no known denominator** — it is not version-scoped and cannot be counted — so no "% compatible" is claimed or computable. The catalogue is **incomplete by construction** and grows as surfaces are identified. Below are absolute counts; V1 progress is tracked separately against the commitment set we define, and is never conflated with the whole surface.

| Status | Count | | Authenticity | Count |
|---|---|---|---|---|
| ✅ verified | 24 | | real | 229 |
| ✅ verified | 24 | | real | 230 |
| 🟢 implemented | 206 | | n/a | 99 |
| 🟡 partial | 44 | | advisory | 34 |
| 🟡 partial | 45 | | advisory | 34 |
| 🟠 stub | 19 | | facade-risk | 44 |
| 🔵 designed | 2 | | | |
| ⬜ absent | 111 | | | |
Expand All @@ -24,7 +24,7 @@ Legend: ✅ verified · 🟢 implemented · 🟡 partial · 🟠 stub · 🔵 de

Of the surfaces **committed to V1** (`scope_1_0: in` — a set we define, not a measure of the whole surface):

- **364 committed** — **230 met** (implemented/verified), 43 in progress (partial), 91 not started (absent/stub/designed).
- **365 committed** — **230 met** (implemented/verified), 44 in progress (partial), 91 not started (absent/stub/designed).
- ⚠ **42 of the committed surfaces carry facade-risk** — they must reach honest behaviour, not just "done".
- Not in the V1 commitment set: 8 out · 25 stretch · 9 undecided (incl. the language scope calls, `vms-082`).

Expand Down Expand Up @@ -854,20 +854,22 @@ Full UAF account record storage and SHA-256 password authentication are real. Ac

_SCS, NISCA/NISCS, connection manager/quorum, cluster-wide DLM, MSCP serving, cluster-wide logicals, shadowing._

`✅✅🟢🟢🟢🟢🟢🟢🟢🟢🟡🟡🟡🟠🟠🟠⬜⬜⬜⬜⬜⬜⬜⬜` — 15 surfaces catalogued (6 met · 2 in progress · 7 not started) · V1: 14 committed, 6 met · ⚠ 1 facade-risk
`✅✅🟢🟢🟢🟢🟢🟢🟢🟢🟡🟡🟡🟡🟠🟠🟠⬜⬜⬜⬜⬜⬜⬜⬜` — 16 surfaces catalogued (6 met · 3 in progress · 7 not started) · V1: 15 committed, 6 met · ⚠ 1 facade-risk

### cluster-dlm — Cluster-wide Distributed Lock Manager
<sub>scope: in · plan: vms-694 · ref: OpenVMS Cluster Systems manual; $ENQ/$DEQ/$GETLKI system services · reviewed 2026-08-28</sub>

A cross-node $ENQ now GRANTS, BLOCKS, and GRANTS-on-release on the mastering node — the DLM's core contention behaviour — while resource remastering, LVB replication, and distributed deadlock detection remain absent, that absence authentic (SS$_UNSUPPORTED, never a fabricated answer). Rung 1 (vms-94c) built the DLM message TRANSPORT (a DLM SYSAP SCS connection + the ENQ/GRANT/DEQ/BLKAST message class). Rung 2 (vms-e8f1) made the RECEIVE handler grant a compatible cross-node $ENQ, held for the remote requester's CSID. Rung 3 (vms-904c) lifts the ENQ scope-fence: an incompatible request now QUEUES on the master's real waiting queue (VMS_DLM_STS_QUEUED, not a grant, not a NOQUEUE decline), the master FIRES a blocking-AST decision naming the remote holder, and a real cross-node $DEQ releases and grants the blocked request (block-then-grant). See kernel-executive.yaml for the single-node lock manager this builds on.
A cross-node $ENQ now GRANTS, BLOCKS, and GRANTS-on-release on the mastering node — the DLM's core contention behaviour — while resource remastering, LVB replication, and distributed deadlock detection remain absent, that absence authentic (SS$_UNSUPPORTED, never a fabricated answer). Rung 1 (vms-94c) built the DLM message TRANSPORT (a DLM SYSAP SCS connection + the ENQ/GRANT/DEQ/BLKAST message class). Rung 2 (vms-e8f1) made the RECEIVE handler grant a compatible cross-node $ENQ, held for the remote requester's CSID. Rung 3 (vms-904c) lifts the ENQ scope-fence: an incompatible request now QUEUES on the master's real waiting queue (VMS_DLM_STS_QUEUED, not a grant, not a NOQUEUE decline), the master FIRES a blocking-AST decision naming the remote holder, and a real cross-node $DEQ releases and grants the blocked request (block-then-grant). Rung H5 (vms-6ca) carries the async replies over the real SCS wire: the master WIREs the queued-reply and — on a real $DEQ — the deferred GRANT, and the REQUESTER-SIDE GRANT RECEIVE (was SS$_UNSUPPORTED) completes an executive-resident origin record on the requesting node, so the block-then-grant status flip (NL->EX) is observed on the REQUESTER across the wire, not just in the master's local state. The BLKAST wire is deferred honestly (the holder releases on its own). See kernel-executive.yaml for the single-node lock manager this builds on.


<sub>3 items · 0 met · 2 in progress · 1 not started</sub>
<sub>4 items · 0 met · 3 in progress · 1 not started</sub>

| | Surface | Kind | VMS | Status | Auth | Scope | Evidence / notes |
|---|---|---|---|---|---|---|---|
| 🟡 | `cluster-dlm$cross-node-lock` | feature | Cross-node $ENQ grant / block-then-grant / blocking-AST on the mastering node | partial | real | in | `src/kernel-core/vms_lock.c` — vms-94c/vms-e8f1/vms-904c. vms_lock_dlm_xnode_dispatch runs a decoded cross-node $ENQ through the real lock manager on the mastering node, held FOR the remote requester's CSID: a compatible request GRANTS (SS$_NORMAL, GET_RESMASTER shows held_for=<peer>); an incompatible one QUEUES on the real waiting queue (VMS_DLM_STS_QUEUED, GETLKI shows granted NL / requested EX) and the master emits the BLKAST directive (blocking_csid) for the remote holder; a cross-node $DEQ (vms_lock_dlm_xnode_deq, authorized by CSID) releases and grants the blocked request (GETLKI flips NL->EX). Proven on a real /dev/vms (tests/qemu/test_syssvc_dlm_xnode.c, x86_64 + Alpha LP64). No fake grants OR blocks — a queued request is a real lock on the master's queue that releases only on a real $DEQ (INV-6).
|
| 🟡 | `cluster-dlm$async-reply-wire` | feature | Async DLM replies (queued-reply + deferred GRANT) delivered over SCS; requester-side completion | partial | real | in | `src/vmsscs/scsd.c` — vms-6ca rung H5. The master's async replies ride the live SCS wire: node B WIREs the queued-reply (granted mode NL — the requester stays genuinely pending) and, on a real cross-node $DEQ that flips a queued waiter to granted, WIREs an unprompted deferred GRANT (SS$_NORMAL, the granted mode) to that requester (vms_lock_dlm_xnode_deq reports the flipped waiter). The REQUESTER-SIDE GRANT RECEIVE (VMS_DLM_OP_GRANT, was SS$_UNSUPPORTED) completes an executive-resident ORIGIN record on the requesting node, whose granted mode is set ONLY from what the master sent over SCS; GETLKI reads the NL->EX flip back on the REQUESTER. Proven on a two-node live A<->B QEMU harness with real /dev/vms on both (tests/qemu/run_dlm_harness_h5.sh: SCSD-I-DLMPEND, SCSD-I-DLMDEFER, SCSD-I-DLMH5FLIP granted_mode=EX). The BLKAST wire (master -> holder) is deferred honestly on this rung — BLKAST as a receive op still returns SS$_UNSUPPORTED; the block-then-grant is proven without it (the holder releases on its own). Multi-peer routing of a deferred grant by CSID (releaser and queued waiter on different nodes) is a later rung; H5 proves the same-peer case. No fabricated wire reply or grant (INV-6).
|
| ⬜ | `cluster-dlm$remaster-lvb-deadlock` | feature | Resource-directory consistency, dynamic remastering, LVB replication, distributed deadlock detection | absent | real | in | `src/kernel-core/vms_lock.c` — Still honestly out of scope, above the contention rung: resource-directory consistency (vms-1bba), remastering on membership change (vms-6ee), LVB replication (vms-d81), and distributed deadlock detection (vms-ec75). The cross-node ENQ carries no VALBLK and the queue path skips the single-node (proc-keyed) deadlock detector, both by design — SS$_UNSUPPORTED / omission, never a fabricated answer. A non-local directory/master on the SEND side still fails SS$_UNSUPPORTED (dlm_resolve_master). Gap is authentic (real).
|
| 🟡 | `cluster-dlm$scs-transport` | feature | DLM SYSAP SCS connection + lock-request message class (ENQ/GRANT/DEQ/BLKAST) between cluster nodes | partial | real | in | `src/vmsscs/scs_dlm.c` — vms-94c rung 1. A DLM message rides as a p.4-13 SCS application message (MTYPE 10) with its body at SCA content offset 58 (the scs_mscp.c nesting). The message TRANSPORT is real; the message HANDLER does not yet grant (rung 2).
Expand Down
Loading
Loading