summaryrefslogtreecommitdiff
path: root/src/serve.zig
Commit message (Collapse)AuthorAge
* fs, serve: set an engine up in place, so a large fid table costs only the ↵Gabriel Schneider6 days
| | | | | | | | | | | | | | | fids used A kernel mount (9ns) holds a fid for every inode the kernel caches, so a server that wants `ls -l` of a directory of thousands of files to work needs a fid table of tens of thousands. Server.initIn sets an engine up in place and, with fid_index, never writes a fid slot at or past high_water; the walks over the table (references, reset, orphan) stop there. Runner.init sets each connection's small fields one by one and leaves the engine to start(), so connection slots nobody uses are never written. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
* 9ns --mntgen: registry subdirectories are mount points tooGabriel Schneider10 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | A registry entry that is a directory is now served the way the root is: a synthetic directory listing the real one, dialing the sockets inside it on walk and recursing into further directories, to max_synth_depth (8) levels across max_synth_dirs (64) synthetic nodes. That is the plan9port mntgen shape and the layout zmx now posts under, so a live session reads at /mnt/9p/zmx/<name>. Before this a directory in the registry was dialed like a socket and answered EIO for good. post gains the two entry points the traversal needs: postedDir (the registry scan, against any directory) and dialPath (a dial by composed path, no name validation). Hardening, each from an attack that broke the code: - BATCH_FORGET carries entries for many owners and puts 0 in the header nodeid, so routing it by the header dropped all of them: 32 of 64 synthetic slots leaked in one close burst and the subdirectories that held them answered EIO forever. distributeForgets unpacks the body and hands each entry to its owner. - probe() and connectBlocking() copied a caller's path into the kernel address with no bound: a path past sun_path overran the 110-byte stack sockaddr (a panic in Debug, silent corruption in ReleaseFast). Both refuse it now, probe as `.live` so a claim never deletes what it could not inspect. - That bound then caught 9proc's own listener, which handed probe() the whole 108-byte sun_path array instead of the path inside it. The probe reads `.live` for anything it cannot ask about, so every stale socket became AlreadyListening and no server could ever take a dead predecessor's name back. It passes the path now. Suites: 87/87 root (+7 post/serve attack regressions), 48/48 9ns, 51+88 9ns integration (+4 traversal and slot-recycling checks), 213/0 9ns adversarial, 60/60 9proc plus its adversarial suites with a new stale-socket takeover check, freestanding green.
* post registry + 9ns --mntgen: the /srv translationGabriel Schneider11 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | cloud9.post: servers post their socket under a name in $XDG_RUNTIME_DIR/9p (post/unpost, posted, dial, Watch) and serve.Runner.listenPosted posts a server by name, unposting on stop. Names are budget-checked against the 108-byte socket path; a claim binds+listens at a private temp path and takes the name with atomic renames under flock (RENAME_NOREPLACE for free names, RENAME_EXCHANGE grab-verify-commit for stale ones): the registry path is never unlinked by a claim, live names refuse with AlreadyPosted, foreign files with NotSocket, and unpost removes only the caller's inode-matched entry. Watch surfaces inotify overflow and a replaced registry dir. 9ns --mntgen [--mount DIR] -- PROGRAM: one FUSE mount at /mnt/9p whose synthetic root lists the posted registry (no connection made); a walk into an unmounted name dials it and runs the existing bridge dispatch in a per-server worker thread, routed by mount index in the node id's top bits (ordinals never reused, cap 4096); a dead server answers EIO on its subtree and is re-dialed on the next walk. The dial watches stop_fd through Tversion (connectWatched). All existing 9ns forms are unchanged. 9proc's unix listener no longer blind-unlinks its path: a foreign non-socket is refused (Occupied), a live server is refused (AlreadyListening), only a refused socket is cleared, and stop() unlinks only the listener's own inode-matched socket. Hardened by adversarial review (GLM 5.3 x2 + DeepSeek V4.1 Flash, all high-thinking): double-bind races on one name (0 in 180k rounds), foreign-file TOCTOU deletions (0 in 4M flips), a 255-byte-name listing panic, inotify queue overflow silently dropped, listenPosted silently overwriting, dial-time Tversion hangs wedging the dispatcher, --debug silently ignored in mntgen, and xattr/statx probes answering EPERM on the synthetic root (broke `ls -l /mnt/9p`). Tests: root 80/80, 9ns 47/47, 9proc 60/60, integration 88/88 + mntgen 37/37, adversarial 213/0, freestanding riscv32 gate green.
* Add cloud9.serve: an std.Io runner around the file-server engineGabriel Schneider12 days
Runner(Backend, Options, Limits) listens on Unix or TCP, runs a reader and a serve task per connection in one Io.Group, pushes frames into an fs.Server, and lets the backend answer now or later from any task or thread (reply, flush, wake); Tflush, greet timeout, connection limit, close and stop with cancellation are covered by tests over real sockets. The engine and the backend contract stay Io-free, so the push/step mode for freestanding targets is unchanged. Documented as the two ways to drive the engine. Co-Authored-By: Claude Fable 5.1 <[email protected]>