handoff: VSync/event-wedge fixes + iterate 2.A–2.BC research notes
Source changes (dormant parity infra, retained from iterate 2.AI/2.AO): - xenia-kernel/exports.rs: nt_create_event manual_reset polarity + related event wiring - xenia-gpu/mmio_region.rs: D1MODE_VBLANK_VLINE_STATUS hardcode parity Also lands the audit-runs/ analysis notes (.md/.txt/.json digests) for the iterate 2.x VSync/0x10e8/0x1004 wedge investigation. Raw trace dumps (.jsonl/.gz/.csv/.stdout) and agent worktrees (.claude/) are gitignored as regenerable local artifacts — see memory + HANDOFF for the running findings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
105
audit-runs/phase-c11-1-access-recent-fix/fix.diff
Normal file
105
audit-runs/phase-c11-1-access-recent-fix/fix.diff
Normal file
@@ -0,0 +1,105 @@
|
||||
Phase C+11.1 — `cache:/access` / `cache:/recent` dir-vs-file fix
|
||||
================================================================
|
||||
|
||||
File: crates/xenia-kernel/src/exports.rs
|
||||
Function: open_cache_file
|
||||
|
||||
Hunk 1: replace the post-existing-file-wins block with a
|
||||
disposition-gated mkdir + STATUS_OBJECT_NAME_NOT_FOUND on miss.
|
||||
|
||||
Pre-fix (Phase C+11 HEAD):
|
||||
|
||||
let host_exists_as_dir = host_path.is_dir();
|
||||
let host_exists_as_file = host_path.is_file();
|
||||
let is_dir_open = host_exists_as_dir
|
||||
|| (!host_exists_as_file && !want_non_dir && want_dir);
|
||||
if is_dir_open {
|
||||
// For non-existent paths the guest wants us to create as a
|
||||
// directory, mkdir-p; canary's HostPathDevice does the same
|
||||
// when FILE_DIRECTORY_FILE is set on a kCreate disposition.
|
||||
if want_dir && !host_path.exists() {
|
||||
if let Err(e) = std::fs::create_dir_all(host_path) {
|
||||
...STATUS_UNSUCCESSFUL...
|
||||
}
|
||||
}
|
||||
// ... falls through to SUCCESS / handle alloc
|
||||
|
||||
Post-fix (Phase C+11.1):
|
||||
|
||||
let host_exists_as_dir = host_path.is_dir();
|
||||
let host_exists_as_file = host_path.is_file();
|
||||
let is_dir_open = host_exists_as_dir
|
||||
|| (!host_exists_as_file && !want_non_dir && want_dir);
|
||||
if is_dir_open {
|
||||
// Phase C+11.1 — only create the host directory when the
|
||||
// disposition is *create-capable*. Mirrors canary's
|
||||
// `VirtualFileSystem::OpenFile` (virtual_file_system.cc:265-273):
|
||||
// for `FileDisposition::kOpen`/`kOverwrite` on a non-existent
|
||||
// path the function returns `X_STATUS_OBJECT_NAME_NOT_FOUND`
|
||||
// *before* any `CreatePath` call — i.e. mkdir is never invoked
|
||||
// on these dispositions. The pre-fix code (Phase C+11) called
|
||||
// `create_dir_all` whenever `want_dir && !host_path.exists()`,
|
||||
// so Sylpheed's cold-boot probes for `cache:/access`,
|
||||
// `cache:/ignore`, `cache:/recent` (disp=1, opts=0x7) succeeded
|
||||
// and produced spurious host directories. Canary instead
|
||||
// returns NOT_FOUND, after which Sylpheed re-creates these as
|
||||
// FILES via `disp=5` + `FILE_NON_DIRECTORY_FILE`.
|
||||
//
|
||||
// Create-capable dispositions (mkdir OK):
|
||||
// 0 FILE_SUPERSEDE
|
||||
// 2 FILE_CREATE
|
||||
// 3 FILE_OPEN_IF
|
||||
// 5 FILE_OVERWRITE_IF
|
||||
// Non-create dispositions (must miss when path is absent):
|
||||
// 1 FILE_OPEN
|
||||
// 4 FILE_OVERWRITE
|
||||
let disp_is_create_capable = matches!(
|
||||
create_disposition,
|
||||
FILE_SUPERSEDE | FILE_CREATE | FILE_OPEN_IF | FILE_OVERWRITE_IF
|
||||
);
|
||||
if !host_path.exists() {
|
||||
if !disp_is_create_capable {
|
||||
if handle_out != 0 {
|
||||
mem.write_u32(handle_out, 0);
|
||||
}
|
||||
write_io_status_block(
|
||||
mem,
|
||||
io_status_block,
|
||||
STATUS_OBJECT_NAME_NOT_FOUND as u32,
|
||||
0,
|
||||
);
|
||||
tracing::info!(
|
||||
"cache open (dir) MISS path={:?} disp={} opts={:#x} -> NOT_FOUND",
|
||||
guest_path,
|
||||
create_disposition,
|
||||
create_options
|
||||
);
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
// create-capable + want_dir → mkdir-p the directory.
|
||||
if want_dir {
|
||||
if let Err(e) = std::fs::create_dir_all(host_path) {
|
||||
...STATUS_UNSUCCESSFUL...
|
||||
}
|
||||
}
|
||||
}
|
||||
// ... falls through to SUCCESS / handle alloc as before
|
||||
|
||||
Hunk 2 (tests): two new unit tests added in
|
||||
crates/xenia-kernel/src/exports.rs after
|
||||
`cache_top_level_manifests_create_as_files`:
|
||||
|
||||
- cache_open_directory_on_missing_path_returns_not_found
|
||||
Loops over the three cold-probe paths Sylpheed actually emits
|
||||
(cache:\\access, cache:\\ignore, cache:\\recent) and asserts
|
||||
NtCreateFile + disp=1 + opts=0x7 returns NOT_FOUND, writes
|
||||
handle=0, and leaves no host entry on disk.
|
||||
|
||||
- cache_disp5_after_disp1_miss_creates_file
|
||||
Pins the canary two-call sequence: cold disp=1 returns NOT_FOUND;
|
||||
immediately following disp=5 + opts=0x60 (FILE_NON_DIRECTORY_FILE)
|
||||
succeeds and produces a host FILE.
|
||||
|
||||
LOC summary: ~30 added in open_cache_file (mkdir gate + NOT_FOUND
|
||||
return branch + comments), ~6 removed (the unconditional mkdir
|
||||
flow); ~88 lines of test code for the two new tests.
|
||||
Reference in New Issue
Block a user