Skip to content

Add VixDiskLib_QueryAllocatedBlocks; investigate NFC_DELTA_DISK - #5

Open
doccaz wants to merge 4 commits into
cloudbase:masterfrom
doccaz:pr3-queryallocatedblocks-deltadisk
Open

doccaz wants to merge 4 commits into
cloudbase:masterfrom
doccaz:pr3-queryallocatedblocks-deltadisk

Conversation

@doccaz

@doccaz doccaz commented Sep 19, 2026

Copy link
Copy Markdown

Summary

  • VixDiskLib_QueryAllocatedBlocks (AIO type 13): returns which blocks within a disk are allocated (non-sparse). Reverse-engineered via an SSL/write-hook capture, hitting and resolving two non-obvious wire-format bugs:
    • Field-order swap: a first capture used startSector=0, which made two request fields (a reserved field and start_offset_bytes) both read as zero — indistinguishable. Implementing from that single capture put start_offset_bytes at the wrong byte offset and silently returned wrong (all-empty) results for every non-zero start. A second capture against a known-allocated region with a non-zero startSector broke the tie.
    • Bitmap padding: the reply's allocation bitmap is padded to a 4-byte boundary, not the raw ceil(chunk_count/8) an earlier draft assumed — invisible for a chunk_count that's already a multiple of 4, but it under-read and desynced the connection for smaller chunk counts.
  • NFC_DELTA_DISK investigated: expected a distinct wire message for reading snapshot delta files. strings on libvixDiskLib.so found it's actually an alternate OPEN_FILE file-type value used by an internal VDDK optimization for very sparse VMFS redo logs — not a correctness requirement. Verified end-to-end that reading, writing, and query_allocated_blocks against an actual post-snapshot delta file all already work with the existing NFC_DISK-only implementation.
  • Found and documented a real gotcha along the way: querying allocated blocks on the same still-open handle a write just went through can see stale (pre-write) data. Reproduced identically on native VDDK (two-process capture — loading native VDDK in the same process as pyVmomi segfaults on this host's OpenSSL), confirming it's real server/VMFS behavior, not a client bug.

Full protocol details and both bugs: docs/nfc_read.md. The NFC_DELTA_DISK investigation: docs/reverse_engineering_procedure.md.

Test plan

  • New unit tests: bitmap decode/merge logic, input validation — no lab needed, pytest tests/unit
  • Validated against a live standalone ESXi 8.0.3 host: full-disk query, a known-allocated sub-range, an aligned empty range, and a real snapshot delta file all match native VDDK's own output exactly
  • New integration tests (test_query_allocated_blocks, test_write_and_query_allocated_blocks_on_delta_disk) — the former initially had the same "write and query on one still-open handle" staleness bug documented above (caught while validating this split), fixed to use separate handles

Note on PR sequencing

Third of 4 focused PRs splitting up the original combined PR #2 (now closed). Independent of #3 (direct-ESXi fix) and #4 (GetInfo+DDB_GET) — can merge in any order. (Validated live by temporarily stacking on the direct-ESXi fix locally, since our test lab is a bare ESXi host that needs that fix to connect at all.)

🤖 Generated with Claude Code

VixDiskLib_QueryAllocatedBlocks (AIO type 13) returns which blocks
within a disk are allocated (non-sparse), useful for skipping empty
regions when reading a snapshot delta file. Reverse-engineered via an
SSL/write-hook capture extended to a ctypes call to
VixDiskLib_QueryAllocatedBlocks after Open, hitting and resolving two
non-obvious wire-format bugs along the way:

- Field-order swap: a first capture used startSector=0, which made two
  request fields (a reserved field and start_offset_bytes) both read
  as zero -- indistinguishable. Implementing from that single capture
  put start_offset_bytes at the wrong byte offset (8 instead of 24)
  and silently returned wrong (all-empty) results for every non-zero
  start. A second capture against a known-allocated region with a
  non-zero startSector broke the tie.
- Bitmap padding: the reply's allocation bitmap is padded to a 4-byte
  boundary, not the raw ceil(chunk_count/8) an earlier draft assumed --
  invisible for a chunk_count that's already a multiple of 4, but it
  under-read and desynced the connection for smaller chunk counts.

Also investigated the "NFC_DELTA_DISK" backlog item (reading directly
from a snapshot delta chain), expecting a distinct wire message.
`strings` on libvixDiskLib.so found it's actually an alternate
OPEN_FILE file-type value used by an internal VDDK client-side
optimization for very sparse VMFS redo logs -- not a correctness
requirement. Verified end-to-end that reading, writing, and
query_allocated_blocks against an actual post-snapshot delta file all
already work with the existing NFC_DISK-only implementation. Found
and documented a real gotcha along the way: querying allocated blocks
on the same still-open handle a write just went through can see stale
(pre-write) data -- reproduced identically on native VDDK (two-process
capture, since loading native VDDK in the same process as pyVmomi
segfaults on this host's OpenSSL), so this is real server/VMFS
behavior, not a client bug.

Validated against a live standalone ESXi 8.0.3 host: full-disk query,
a known-allocated sub-range, an aligned empty range, and a real
snapshot delta file all match native VDDK's own output exactly. Adds
unit tests for the bitmap decode/merge logic and input validation
(no lab needed) plus integration tests for the live scenarios above.
Full protocol details and both bugs are in docs/nfc_read.md; the
NFC_DELTA_DISK investigation is in docs/reverse_engineering_procedure.md.
For better readability, we'll add an inline comment that describes
how allocation bitmaps are parsed.
We'll use the same typing.Protocol approach as
cloudbase#4, minimizing
merge conflicts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants