Host test failure in core/direct_io.zig on Linux kernel 6.17: O_DIRECT open succeeds on procfs, so the test's 'plain' fd is not plain

Closed Beginner friendly
#536 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@GustavBlack is already working on this.

Since Oct 9, 2026.

  • #540 by @GustavBlack — open

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
72/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
linux

Research direction

The failing test is 'direct reads return the same bytes as buffered reads' in zig/src/core/direct_io.zig, around lines 86-100, where the comparison fd is opened with File.open and its direct flag is then flipped. Run zig build test on Linux to reproduce the -1 from the pread of 1 byte at offset 0. Done when the comparison fd is opened without O_DIRECT, the test passes on kernel 6.17, and the test no longer depends on procfs rejecting O_DIRECT at open.

Written by the indexing model from the issue text.

Description

What fails

At v1.0.2 (f8fe17d), one host test fails on a DGX Spark head (aarch64, Ubuntu 24.04, kernel
6.17.0-1032-nvidia):

zig build test
...
error: 'direct_io.test.direct reads return the same bytes as buffered reads' failed:
       expected 1, found -1
    zig/src/core/direct_io.zig:100:9 in test.direct reads return the same bytes as buffered reads
        try std.testing.expectEqual(@as(isize, @intCast(c[1])), n);

75/76 pass; this is the only failure.

Cause

The test's comparison fd is not actually a plain fd. File.open tries O_DIRECT first and falls
back only when the open fails. On this kernel, open("/proc/self/exe", O_DIRECT) succeeds
(procfs tolerates the flag at open time), so both fds in the test are O_DIRECT. The test then sets
only the struct flag (plain.direct = false), which does not change the fd, and the first
comparison read — an unaligned pread(fd, want.ptr, 1, 0) — returns -1 with EINVAL.

Minimal C repro on the same host:

open O_DIRECT: 3 errno=none
pread aligned 4096@0: 4096 errno=none
pread 1@0: -1 errno=Invalid argument

The engine is unaffected: checkpoints are real NVMe files, and the fallback covers filesystems that
refuse O_DIRECT at open. The latent assumption is only that an O_DIRECT open of a procfs file
fails, which held on older kernels and not on 6.17.

Proposed fix (test-only)

Open the comparison fd explicitly without O_DIRECT, so the test no longer depends on the kernel's
procfs behavior:

--- a/zig/src/core/direct_io.zig
+++ b/zig/src/core/direct_io.zig
@@ -86,9 +86,10 @@
     if (builtin.os.tag != .linux) return error.SkipZigTest;
     const gpa = std.testing.allocator;
     var f = try File.open("/proc/self/exe");
     defer f.close();
-    var plain = try File.open("/proc/self/exe");
-    defer plain.close();
-    plain.direct = false;
+    const plain_fd = std.c.open("/proc/self/exe", .{ .ACCMODE = .RDONLY, .CLOEXEC = true });
+    if (plain_fd < 0) return error.FileNotFound;
+    var plain = File{ .fd = plain_fd, .direct = false };
+    defer plain.close();

I'll send this as a one-commit pull request if that's the preferred path.

— Gustav (GustavBlack)

Dominant language
Python
Stars
995
Forks
169
Avg merge
1d 7h
Merged PRs (30d)
446

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ashhart/TensorFold

All issues in ashhart/TensorFold

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.