Repository navigation
A kernel directory, symlink and listing entry each have an identity: SYS_STAT by path, and readdir answers the node - #855
Conversation
…answers its node The kernel's directories and symlinks answered `(0, 0)` for stat's `(volume, node)`, so every one was one file to a program that asked, and clang's FileManager took every kernel include directory for the first: `ignoring duplicate directory` and `'stdio.h' file not found` with libc's realpath in. `readdir`'s `d_ino` was the entry's offset in the listing. `SYS_STAT` (16) answers a `Stat` for any name the kernel serves, a final symlink followed or not, with `FileType::Directory` and `Symlink` beside `File`. libc's `stat`, `lstat` and `access` and std's `stat` and `lstat` are one call each; the `readdir` and `readlink` probes they stood on, and the zeroed answers, are deleted. Numbering, on #851's volumes (a mount's index plus one): - a file's node stays its `FileId`; - a symlink's is drawn from the count `FileId`s are drawn from (`file_cache::draw_node`), so no node on a kernel volume is another's: on `/tmp` at the link's making, carried in its entry across a rename; on ROOT on first ask, in the adapter's map, which ROOT's immutability bounds; - a directory's is drawn the same way and kept by absolute path in the VFS (`kernel::dirnodes::Directories`), since neither mount keeps a record of one. A delete, rename or rmdir forgets every directory above it that ended, so what is held is bounded by the directories that exist; the truncating open deletes with `delete_file`, which forgets nothing, because it puts the file back at once; - `/` and an empty mount point are the VFS's own directories, on a volume of their own below a file server's bit 63. ROOT now mints a file's `FileId` on first ask rather than first open, with no reference held, so a listing can answer an unopened file's node. `SYS_READDIR`'s eight bytes per entry were the entry's size, which no reader used since #851; they are now its node, and `d_ino` is it. Tests: `kernel::dirnodes` is host-tested, and four mutations of it red. The 210 C case and `stat_identity` carry the guest and metal claims; on origin/main both red, and each of the VFS's four forget sites, mutated, reds `stat_identity` at its own assertion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
… issue closes Its exit is the 210 C case's new lines: two kernel directories and two ROOT symlinks answer two nonzero pairs, and `d_ino` is its entry's `st_ino` for a directory, a file, a link, a mount and two `/tmp` names. They pass in a QEMU guest at 7cdd1ec and red on origin/main; the T14 row is staged. Its two citations in `toyos-builds-itself.md` go with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
|
ci-host, part 1 of 9, |
|
ci-host, part 2 of 9, |
|
ci-host, part 3 of 9, |
|
ci-host, part 4 of 9, |
|
ci-host, part 5 of 9, |
|
ci-host, part 6 of 9, |
|
ci-host, part 7 of 9, |
|
ci-host, part 8 of 9, |
|
ci-host, part 9 of 9, |
|
guest-suite, part 1 of 1, |
|
probe-harness, part 1 of 1, the throwaway QEMU probe (never committed): a machine test that boots tests/testcases with the named shared members and runs each, a C case judged against its .expect |
|
probe-at-head, part 1 of 1, the probe at tree 41d1592e (head ad23112's), exit 1: the four reds are the probe's environment, and origin/main's too (next comment) |
|
probe-at-origin-main, part 1 of 1, the probe at tree 85beb2ae (origin/main bb3344d's), exit 1 |
|
negative-control, part 1 of 1, the test changes alone applied onto origin/main bb3344d, through the probe, exit 1: both arms red |
|
dirnodes-host-mutations, part 1 of 1, kernel::dirnodes host tests (exit 0) and four mutations, each a checked patch applied, run and reverted, at tree 1110569d (head 056ee670a's, whose dirnodes.rs is the head's) |
|
vfs-mutations, part 1 of 1, the VFS's four forget sites mutated, stat_identity through the probe: green, delete, rename and rmdir before stat_identity's truncate lines; green2 and truncate at tree 1110569d (head 056ee670a's) |
|
metal-staged, part 1 of 1, |
|
throwaway-merge, part 1 of 1, the evidence tree 0a9180449 = #830's local head 46a27b9 + origin/main bb3344d + #854 de5faac + this branch 7cdd1ec; its one hand resolution, libc's posix_io.rs, against e0d185b5b (the tree before this branch merged): #854's realpath kept, its is_dir asked through SYS_STAT |
|
throwaway-build, part 1 of 1, |
|
hosted-clang-hello, part 1 of 7, |
|
hosted-clang-hello, part 2 of 7, |
|
hosted-clang-hello, part 3 of 7, |
|
hosted-clang-hello, part 4 of 7, |
|
hosted-clang-hello, part 5 of 7, |
|
hosted-clang-hello, part 6 of 7, |
|
hosted-clang-hello, part 7 of 7, |
|
T14 reading at |
|
Review of #855 at ad23112 against Net lines ( Judged with no finding:
BLOCKER
NOTE
SEND BACK |
|
host-mutations, part 1 of 1, the dirnodes host tests at head's kernel/pure/dirnodes.rs, green and eight mutations as checked patches, each red, exit 101 |
|
bound-measurement, part 1 of 1, a throwaway host crate (never committed) that includes head's kernel/pure/dirnodes.rs verbatim and measures the bound at its worst, release build, exit 0 |
|
vfs-mutations, part 1 of 1, the throwaway QEMU probe at tree 79abe77b9 (2c645ce; ed538e7 differs from it only in #838's acpiserver and harness files): green, and six kernel mutations, each reds stat_identity at its own assertion |
|
negative-control, part 1 of 2, everything outside tests/ reverted to origin/main 41ad7ec merged with #854 6aa7722 (tree 0fa6a201f), head's tests kept (stat_identity.rs blob 072c7e666, head's), through the probe: exit 1, both red |
|
negative-control, part 2 of 2, everything outside tests/ reverted to origin/main 41ad7ec merged with #854 6aa7722 (tree 0fa6a201f), head's tests kept (stat_identity.rs blob 072c7e666, head's), through the probe: exit 1, both red |
|
merge-854-resolution, part 1 of 1, git show --remerge-diff 2c645ce: the hand resolution of #854's three conflicts |
|
metal-staged, part 1 of 1, cargo test --test toyos-build -- --metal --metal-readback stat_identity 207_libc_names readdir_bound fs_share app_view at ed538e7, exit 2 (staged, machine untouched) |
|
ci-host, part 1 of 9, cargo run -- --ci host at ed538e7, exit 0, 79 steps green |
|
ci-host, part 2 of 9, cargo run -- --ci host at ed538e7, exit 0, 79 steps green |
|
ci-host, part 3 of 9, cargo run -- --ci host at ed538e7, exit 0, 79 steps green |
|
ci-host, part 4 of 9, cargo run -- --ci host at ed538e7, exit 0, 79 steps green |
|
ci-host, part 5 of 9, cargo run -- --ci host at ed538e7, exit 0, 79 steps green |
|
ci-host, part 6 of 9, cargo run -- --ci host at ed538e7, exit 0, 79 steps green |
|
ci-host, part 7 of 9, cargo run -- --ci host at ed538e7, exit 0, 79 steps green |
|
ci-host, part 8 of 9, cargo run -- --ci host at ed538e7, exit 0, 79 steps green |
|
ci-host, part 9 of 9, cargo run -- --ci host at ed538e7, exit 0, 79 steps green |
|
guest-suite, part 1 of 2, cargo test --test toyos-build at ed538e7, exit 0, 61 of 61 |
|
guest-suite, part 2 of 2, cargo test --test toyos-build at ed538e7, exit 0, 61 of 61 |
|
T14 reading at |
|
Review of #855 at ed538e7 against Earlier BLOCKERs
Earlier NOTEs: the negative control was rerun with head's Net lines ( Judged with no finding:
BLOCKER NOTE
LAND AFTER NAMED CHANGES |
MAX_DIRECTORIES is a bound with no owner, like max_windows and places_for, and unlike them its refusal reaches other processes' reads: once /tmp names fill it, a stat, access, opendir or listing of a directory not yet numbered is refused ResourceExhausted. The issue now names it as a cap that per-process accounting deletes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
Main now carries the loader's relocation (#836), stat identity (#851), libc's realpath (#854), the kernel's directory identity (#855) and the second bench (#852). ALL_CONFIGS keeps consentcase and hostedclangcase; the host-tools issue takes main's os-release row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
Every kernel directory and symlink answered
(0, 0)for stat's(volume, node), andreaddir'sd_inowas the entry's offset in the listing. With #854'srealpathin, clang found its install directory and then took every kernel include directory for the first (ignoring duplicate directory,'stdio.h' file not found): itsFileManagerkeys directories on the pair. Now a kernel directory, symlink and listing entry each have a true identity.Design
SYS_STAT(16),toyos_abi::syscall::stat(path, follow): aStatfor any name the kernel serves, a final symlink followed or not, withFileType::Directory(11) andSymlink(12) besideFile. A directory or symlink cannot be opened, so asking by path is the only way to its identity. libc'sstat,lstatandaccessand std'sstatandlstatare one call each; thereaddirprobe (is_dir,kernel_is_dir), thereadlinkprobe and the zeroed answers they built are deleted, and libc's realpath resolves a path by the kernel's rules and link bound, which toyos-abi declares, and the kernel's non-POSIX resolution is recorded #854'srealpathasks itsis_dirthroughSYS_STAT.Vfs::statanswers the kernel'sops::Statitself, so no intermediate type stands between it and the copy-out.FileIds come from (file_cache::draw_node), so none on a kernel volume is another's:FileId, as A file's identity: stat answers a volume and a node, through the kernel, the file server, libc and std #851 has it;/tmp, is drawn at its making and carried in its tmpfs entry, so a rename keeps it; on ROOT it is drawn on first ask and kept in the adapter's per-name map asNode::Symlink, besideNode::File(FileId), which an immutable volume bounds; a name the map holds as a symlink that the volume then answers extents for is refusedIorather than opened as aFileId;kernel::dirnodes::Directories, host-tested), because neither kernel mount records a directory: one is a prefix its names share, or a namemkdirleft increated_dirs. A delete, a rename and an rmdir forget every directory above them that the removal ended; the truncating open deletes withdelete_file, which forgets nothing, because it puts its file back at once and the directory never ended;created_dirsis: at mostMAX_DIRECTORIES(16384) keys of at mosttoyos_abi::syscall::MAX_PATH(4096) bytes. A path pastMAX_PATHis refusedInvalidArgument, ascdandmkdirrefuse it; a new directory past the countResourceExhausted, until one ends; astator a listing that would number one answers the refusal. A removal's ancestor walk begins at the longest ancestor withinMAX_PATH, since nothing longer is held, so an unlink beneath a 64 KiB name walks at most the 2047 ancestors a key can be;/and an empty mount point are the VFS's own directories, on a volume of their own (NAMESPACE_VOLUME,2^63 - 1: below a file server's bit 63, above every mount):/is 1 and the root entry at slotiisi + 2.SYS_READDIR's eight bytes per entry were the entry's size, which nothing read since A file's identity: stat answers a volume and a node, through the kernel, the file server, libc and std #851; they are now its node (Dirent::node), and libc'sd_inois it.FileSystem::listanswers names alone, and a newFileSystem::nodeanswers a file's or symlink's number.FileIdon first ask, with no reference held, rather than on first open, so a listing can answer an unopened file's node.Vfs::followedisresolve_for_open's link walk, made a loop bounded by libc's realpath resolves a path by the kernel's rules and link bound, which toyos-abi declares, and the kernel's non-POSIX resolution is recorded #854'sMAX_LINKSthat stops at a mount root rather than refusing it, sostatandopenfollow links one way.Roast
forget_ended_dirsleaks one entry per directory it ends, and a directory made there again keeps the old number (POSIX allows the reuse; the memory is the cost).revoke_selftestdeletes throughdelete_file, an actuator-only top-level/tmpfile under no directory.created_dirscan beside it; once it is full, one process's directories refuse every other's until one ends. Whose to refuse isissues/no-physical-memory-fairness.md's question, which this does not answer.forget_ended_dirskeeps a number when the mount cannot say whether its directory stands (unwrap_or(true)): forgetting one that stands would renumber it. Neither kernel mount can refuse there today (tmpfs answers from memory; ROOT is never written). It splits its borrow withmem::takeof the map around the closure.is_symlinkand afile_extentslookup per name on its first listing; the listing already walks the whole tree (issues/a-listing-still-scans-the-whole-mount.md)./'s listing answers a mounted entry'sd_inoas the mounted root's node (Linux answers the covered directory's), sod_inoandst_inoagree, as the issue's exit asks.DIRENT_FILE,DT_UNKNOWN); both are as they were.Statis still declared twice (issues/fstats-answer-is-declared-twice.md);SYS_STATcopies out the kernel's existing copy and adds no third.(0, 0); the closed issue recorded that too, so it is filed on its own:issues/a-pipe-console-socket-or-shared-memory-has-no-identity.md.symlink(refused.rs), so the claims about a/tmplink are the Rust case's, through std.issues/+28 / −31 (git diff --shortstat origin/main...ed538e73c: 20 files, +717 / −267;kernel/pure/dirnodes.rsis 76 lines of production and 127 of tests). The growth is the syscall (ABI wrapper, dispatch arm,sys_stat),Vfs::stat, the numbering and its bound; libc and std each shrink.Unsure of: whether
/and the empty mount points want a volume of their own or none; whether a node count apart fromFileIds would read better than sharing theirs; whetherMAX_DIRECTORIESwants to be belowcreated_dirs's cap rather than equal to it.Checks (filesystems and the ABI)
kernel::dirnodes, seven tests, exit 0; eight mutations, each red, exit 101: forgets nothing, judges the parent only, draws on every ask, judges what it holds not, no length bound, no count bound, the count bound one past, and the walk starting one byte short ofMAX_PATH(host-mutations).dirnodes.rsincluded verbatim in a throwaway crate (bound-measurement): full, 16384 keys of 4096 bytes hold 68150016 bytes; a new key on the full map is refusedResourceExhaustedin 2.5 µs, a 64 KiB keyInvalidArgumentin 31 µs; a removal beneath a 65536-byte name, with all 2047 ancestors withinMAX_PATHheld in a full map, judges 2047 and walks in 1.39 ms, forgets all 2047 in 3.0 ms, and walks a map holding none of them in 0.45 ms. The kernel'sexistsper judged ancestor (is_mounted_dir: acreated_dirslookup and tmpfs's ordered range lookup) is not in these figures. A host measurement, not a timing verdict.tests/testcases/tinycc/210_stat_identity.cgains twelve lines of verdict (two/systemdirectories, one through two paths, a directory against its mount's root and against a file, two ROOT symlinks against each other and against what they name, andd_inoagainstst_inofor a directory, a file, a link, a mount and two/tmpnames).stat_identity(Rust) drops its guard that exempted kernel directories, adds a/tmpsymlink's own identity across a rename,an_ended_directory_is_forgotten(rmdir, an unlink and a rename each give an ended directory's number up, and a truncating open of its one file does not), anda_standing_directory_keeps_its_number(a directory a second file still makes one, and onemkdirmade whose only file goes, each keep theirs across an unlink beneath them, as/tmpdoes).stat_identity.stat_identityat its own assertion, exit 1: the review'sunwrap_or(true)→ alwaysfalse(an unlink beside a second file renumbered /tmp/stat-identity-stands); the forget judging by the mount alone, blind tocreated_dirs(an unlink of its only file renumbered the made /tmp/stat-identity-stands); the forget removed from delete, rename or rmdir; anddeletein the truncating open.stat_identity.rsblob 072c7e666, head's) on everything else reverted to origin/main 41ad7ec merged with libc's realpath resolves a path by the kernel's rules and link bound, which toyos-abi declares, and the kernel's non-POSIX resolution is recorded #854 6aa7722 (tree 0fa6a201f): 210 stops at/system/bin has no identityandstat_identityat/tmp/stat-identity-ended has no identity: (0, 0), exit 1 (1 2). The one file outsidetests/left differing is the closed issue, re-created untracked, which no build reads.<sys/stat.h>(st_inoandst_devuniquely identify a file) and<dirent.h>(d_inois the entry's file serial number) are the specification; clang'sFileManager(UniqueRealDirs, keyed on the pair) is a third-party reader; the T14 is the hardware, 6 passed at ed538e7.Gates
cargo run -- --ci hostcargo test --test toyos-build(guest suite)--metal --metal-readback <dir> stat_identity 207_libc_names readdir_bound fs_share app_viewtestcases(test_rs_stat_identity,207_libc_names,210_stat_identity, 3 of 3 members with both markers),proctreecase(fs_share,app_viewPASS) andtestcases-readdir(readdir_boundPASS)Head 6e022ac differs from ed538e7 only in
issues/no-physical-memory-fairness.md, which no build reads; every gate above stands for it.#854's three conflicts were resolved by hand at 2c645ce:
vfs.rstakesMAX_LINKSandMAX_PATHfromtoyos_abi,posix_io.rskeeps #854'srealpathwithis_dirthroughSYS_STATand dropsstat_impl, andtoyos-builds-itself.mdkeeps #854'srealpathline without the closed issue (merge-854-resolution).hosted_clang_helloMeasured at evidence tree 0a9180449 (#830's unpushed 46a27b9, #854 at de5faac and this branch at 7cdd1ec): exit 0,
hello.oandhellobyte-identical to the host's. #854 landed at 6aa7722, whose later commits rewriteresolve.rsandrealpath, the path clang takes, and #830's pushed head is 6b2edd9; so this is no evidence for #830, and it is to be measured again at #830's head once this branch lands.The issue
issues/the-kernel-numbers-no-directory-symlink-or-listing-entry.mdis deleted, its exit being 210's new lines, which pass in a QEMU guest and on the T14 and red on the base. Its two citations inissues/toyos-builds-itself.mdgo with it. Its line on pipes, consoles and other objects moves toissues/a-pipe-console-socket-or-shared-memory-has-no-identity.md.issues/no-physical-memory-fairness.mdnamesMAX_DIRECTORIESbesidemax_windowsandplaces_for: a cap with no owner whose refusal crosses processes, since once/tmpnames fill it every process'sstat,access,opendiror listing of a directory not yet numbered is refusedResourceExhausted; per-process accounting deletes it.🤖 Generated with Claude Code
https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C