fix(mft): real overlapped re-open for snapshot devices + snapshot-correct $MFT fallback#578
Merged
Merged
Conversation
…rect $MFT fallback
Reported from a live VSS content-ingest run: the in-process MFT read
logged 'IOCP inline read failed … 0x80070057', then 'Fallback 1 ($MFT
file) … Access is denied', succeeding only on Fallback 2 (unbuffered
volume I/O). The chain worked, but the first two rungs were broken by
construction on snapshot devices:
- open_overlapped_handle answered !is_live_letter with a
DuplicateHandle of the original (synchronous) handle. Overlapped-ness
is a property of the file object fixed at CreateFileW time, so the
duplicate was never overlapped and IOCP reads on it always failed
with ERROR_INVALID_PARAMETER — the exact trap opened_path's own doc
comment describes for the unbuffered path. Snapshot (and live) opens
now RE-OPEN the exact stored original path with FILE_FLAG_OVERLAPPED;
only broker-adopted handles still duplicate (the broker's handle is
opened overlapped, and a non-elevated process cannot re-open).
IOCP now works first-try on VSS snapshot devices.
- open_mft_read_handle built '{letter}:\$MFT' unconditionally — on a
snapshot-device handle that path opens the LIVE volume's $MFT. It
happened to fail access-denied in the observed run, but a successful
open would have silently indexed the wrong volume (the same
wrong-device class fixed earlier for get_mft_extents and the
unbuffered re-open). Fallback 1 now appends $MFT to the stored
snapshot device path ('\\?\GLOBALROOT\…\$MFT'), which is both
correct and actually functional on shadow copies.
unbuffered_reopen_path is renamed reopen_path (now shared by the
unbuffered and overlapped re-opens); the new mft_reopen_path helper is
unit-tested for the snapshot-append, live-letter, and broker cases.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Reported from a live VSS content-ingest run: the in-process MFT read logged
IOCP inline read failed … 0x80070057, thenFallback 1 ($MFT file) … Access is denied (os error 5), succeeding only on Fallback 2 (unbuffered volume I/O, 179.9 MB/s). The resilient chain worked and the index was correct — but the first two rungs were broken by construction on VSS snapshot devices.Bug 1: IOCP could never work first-try on a snapshot device
open_overlapped_handleanswered the snapshot-device case (!is_live_letter) with aDuplicateHandleof the original handle. Overlapped-ness is a property of the file object fixed atCreateFileWtime — a duplicate of a synchronous handle is never overlapped, so binding it to an IOCP fails withERROR_INVALID_PARAMETER(0x80070057) every time. Theopened_pathfield's own doc comment already describes this exact trap for the unbuffered path; the overlapped path just never received the same fix.Fix: non-broker handles now get a real re-open of the exact stored original path (
reopen_path, the renamed shared helper) withFILE_FLAG_OVERLAPPED. Broker-adopted handles still duplicate — the broker's handle is opened overlapped, and a non-elevated process cannot re-open the volume. Result: the IOCP fast path works first-try on snapshot devices instead of falling down the chain.Bug 2 (latent, wrong-device): Fallback 1 targeted the live volume
open_mft_read_handlebuilt{letter}:\$MFTfrom the drive letter unconditionally — on a snapshot-device handle that opens the live volume's$MFT. In the observed run it failed access-denied (harmless), but a successful open would have silently indexed the live volume while the caller believed it was reading the point-in-time snapshot — the same wrong-device class previously fixed forget_mft_extentsand the unbuffered re-open.Fix: the new
mft_reopen_pathhelper appends$MFTto the stored snapshot device path (\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopyN\$MFT), which is both correct and actually functional on shadow copies. Live-letter and broker-adopted handles keep the classic{letter}:\$MFTform unchanged.Fallback 2 was already path-correct via
opened_path— which is why the observed run produced a valid snapshot index.Tests
Unit tests pin the path-selection decisions without touching the filesystem:
reopen_path(stored snapshot path wins; letter fallback only when no stored path) andmft_reopen_path(snapshot append, live letter, broker cases). Windows-native execution happens in the merge queue as usual.Gates: full workspace suite (2500), lint-prod, lint-tests, xwin Windows clippy, rustdoc, doc-tests — green; full pre-push bundle passed on push.