From d562e9df2bc5e69bba7298a9439e2adca5c18faf Mon Sep 17 00:00:00 2001 From: salmonik Date: Sat, 1 Aug 2026 15:00:47 +0200 Subject: rsnix: runtime device detection — rescan for hotplugged/removed disks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1: make the boot discovery pipeline re-runnable and diff it against live hardware state. - ahci: store ABAR/NP/port bitmap; poll_dirty() (cheap PxSSTS.DET check per port) and rescan() which starts newly-present ports and tombstones the slots of removed ones. Slots never shift, so disk indices stay valid. select() now rejects tombstoned slots. - fat: Volume gets a mounted flag; rescan() unmounts volumes whose disk left and mounts every disk without a mounted volume (re-trying failed boot mounts). UID dedup ignores tombstones so a re-plugged disk keeps its /disk/ name. - fs: init's mount loop factored into rescan_disks(), which lazily creates /disk, ensures a mount node per mounted volume and tombstones nodes of unmounted ones. - shell: 'rescan' command + automatic deep rescan before each prompt when ahci::poll_dirty() sees a port-presence change. Rescan events flow through serial_println so they land in klog too. Removal (PxSSTS) is a real-hardware path: QEMU q35 rejects disk hotplug on the ich9-ahci IDE buses, and PCIe device_del is a guest-cooperative protocol this kernel does not implement. --- shell/src/lib.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'shell') diff --git a/shell/src/lib.rs b/shell/src/lib.rs index ddd8688..28eb737 100644 --- a/shell/src/lib.rs +++ b/shell/src/lib.rs @@ -45,6 +45,12 @@ pub fn run() -> ! { // Push any deferred scrolls so the prompt renders on a current // framebuffer (e.g. after a streaming command's batch of output). rsnix::vt::sync_scroll(); + // Cheap hotplug probe: if any AHCI port's device presence changed + // since the last scan, re-run discovery (mounts new volumes, + // unmounts gone ones) before showing the prompt. + if rsnix::ahci::poll_dirty() { + report_rescan(rescan_all()); + } // Print prompt term_print("> "); @@ -681,6 +687,7 @@ write `{} TIL `", "stress" => cmd_stress(&parsed), "date" => cmd_date(&parsed), "pci" => cmd_pci(&parsed), + "rescan" => cmd_rescan(&parsed), "ls" => cmd_ls(&parsed), "cat" => cmd_cat(&parsed), "klog" => cmd_klog(&parsed), @@ -710,6 +717,7 @@ fn cmd_help(_p: &Parsed) { stress — stress-test heap/page allocators date — show current date/time (RTC) pci — list PCI devices + rescan — re-scan for hotplugged/removed disks (also runs automatically) ls — list a directory cat — print files (cat USE a TO b copies a→b; cat TIL END is a heredoc) klog — kernel boot log (cat /dev/klog; WRITING persists it) @@ -1527,6 +1535,33 @@ fn cmd_date(p: &Parsed) { pipe.end(); } +/// Deep device re-scan: AHCI ports → FAT volumes → VFS mount table. +/// Returns (disks added, disks removed, vols mounted, vols unmounted, +/// nodes added, nodes removed) so callers can report the result. +fn rescan_all() -> (usize, usize, usize, usize, usize, usize) { + let (da, dr) = rsnix::ahci::rescan(); + let (ma, mu) = rsnix::fat::rescan(); + let (na, nr) = rsnix::fs::rescan_disks(); + (da, dr, ma, mu, na, nr) +} + +/// Print the one-line change summary; returns true if anything changed. +fn report_rescan((da, dr, ma, mu, na, nr): (usize, usize, usize, usize, usize, usize)) -> bool { + term_println(&alloc::format!( + "rescan: {} disk(s) added, {} removed · {} volume(s) mounted, {} unmounted · {} node(s) added, {} removed", + da, dr, ma, mu, na, nr + )); + da + dr + ma + mu + na + nr > 0 +} + +fn cmd_rescan(_p: &Parsed) { + if report_rescan(rescan_all()) { + term_println("rescan done — /disk updated"); + } else { + term_println("rescan done — nothing changed"); + } +} + fn cmd_pci(p: &Parsed) { let devices = rsnix::pci::probe(); let mut pipe = Pipeline::new(&p.filters, &p.output); -- cgit v1.2.3