driver-manager: v1.4 — second-round integrations
Round-two integrations of the driver-manager migration's D-phase.
The policy loader is now active (the redbear-driver-policy package
now actually changes spawn_decision_gate behavior at runtime), the
--concurrent=N CLI flag enables the SMP worker pool, PciQuirkFlags
is wired into actual driver spawn (env vars to the child), and the
two C0 service files have been committed in the local/sources/base
submodule. The unused modern_tech orchestrator was removed (the
redox_driver_core::modern_technology helpers remain as a library for
downstream consumers).
driver-manager (16 tests, was 13):
- config.rs: PciQuirkFlags hints are now passed to the spawned child as
env vars (REDBEAR_DRIVER_PCI_IRQ_MODE=intx_or_msi, REDBEAR_DRIVER_DISABLE_ACCEL=1).
Adds blacklist_match() consult at probe time before spawn_decision_gate.
- main.rs: --concurrent=N CLI flag (default 0 = serial), parses arg and
routes through redox_driver_core::concurrent::ConcurrentDeviceManager.
Loads /etc/driver-manager.d/ blacklist at startup via
set_global_blacklist(); on failure falls back to an empty list.
- policy.rs: new file. BlacklistFile / BlacklistEntry TOML schema,
load_dir() reads .toml/.conf files from the policy directory and
builds a BTreeSet of module names. Missing directory returns empty
(opt-in). Tests cover missing / valid / invalid-file paths.
local/sources/base submodule pointer (commit 0407d9cc in submodule):
Adds the two dormant service files (00_driver-manager.service in
init.d/ and 40_driver-manager-initfs.service in init.initfs.d/).
Both are gated by ConditionPathExists=!/etc/driver-manager.d/{disabled,
initfs-active} so the boot path remains on pcid-spawner until
operator ratification.
redox-driver-core: unchanged library. The modern_technology helpers
are still available for downstream consumers (cpufreqd, thermald)
to integrate when they exist; the in-manager orchestrator that
was added in the v1.3 round has been removed because it wrote JSON
files that nothing read.
§ 0.5 audit-no-stubs.py: 0 violations across 34 files. 52 tests pass
across the three crates.
This commit is contained in:
+1
-1
@@ -65,7 +65,7 @@ console-to-KDE plan.
|
||||
- `../local/docs/ACPI-IMPROVEMENT-PLAN.md` — ACPI ownership, robustness, validation
|
||||
- `../local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md` — PCI/IRQ quality, MSI/MSI-X
|
||||
- `../local/docs/DRM-MODERNIZATION-EXECUTION-PLAN.md` — DRM-focused execution (subsystem detail)
|
||||
- `../local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v1.3, 2026-07-20) — D-Phase (parallel development) + C-Phase (cutover & validation) plan to replace `pcid-spawner` with `driver-manager` (driver-manager built in parallel, not enabled before D5 ratifies; never deletes pcid-spawner; cross-references Linux 7.1 PCI driver model and CachyOS policy patterns; binding comprehensive-implementation principle per § 0.5). **Status v1.3: D-phase fully implemented** — 49 tests passing across `redox-driver-core` (28+5), `redox-driver-pci` (3), and `driver-manager` (13); 0 audit-no-stubs violations across 34 files; SMP concurrent probe, C-state/P-state advisors, IOMMU/MSI-X/NUMA helpers, PciQuirkFlags integration, runtime PM hooks, AER foundation, hotplug polling-fallback (250ms) all implemented comprehensively. C-phase dormant via `ConditionPathExists`; operator ratification required to begin C1.
|
||||
- `../local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v1.4, 2026-07-20) — D-Phase (parallel development) + C-Phase (cutover & validation) plan to replace `pcid-spawner` with `driver-manager` (driver-manager built in parallel, not enabled before D5 ratifies; never deletes pcid-spawner; cross-references Linux 7.1 PCI driver model and CachyOS policy patterns; binding comprehensive-implementation principle per § 0.5). **Status v1.4: D-phase fully implemented + second-round integrations** — 52 tests passing across `redox-driver-core` (33), `redox-driver-pci` (3), and `driver-manager` (16); 0 audit-no-stubs violations across 34 files; SMP concurrent probe, C-state/P-state advisors (library), IOMMU/MSI-X/NUMA helpers (library), PciQuirkFlags wired into driver spawn (env vars), runtime PM hooks, AER foundation, hotplug polling-fallback (250ms) all implemented comprehensively; `--concurrent=N` CLI flag enables SMP worker pool; `/etc/driver-manager.d/` blacklist is consulted at probe; C0 service files committed in `local/sources/base` submodule. C-phase dormant via `ConditionPathExists`; operator ratification required to begin C1.
|
||||
- `../local/docs/WAYLAND-IMPLEMENTATION-PLAN.md` — Wayland compositor (subsystem detail)
|
||||
- `../local/docs/archived/RELIBC-IPC-ASSESSMENT-AND-IMPROVEMENT-PLAN.md` — relibc IPC surface
|
||||
- `../local/docs/GREETER-LOGIN-IMPLEMENTATION-PLAN.md` — greeter/login design
|
||||
|
||||
+7
-5
@@ -1422,16 +1422,18 @@ When mainline updates affect our work:
|
||||
also be treated as first-class subsystem plans, not as side notes.
|
||||
- `local/docs/IRQ-AND-LOWLEVEL-CONTROLLERS-ENHANCEMENT-PLAN.md` is the current umbrella plan for
|
||||
IRQ delivery, MSI/MSI-X quality, IOMMU validation, and other low-level controller completeness work.
|
||||
- `local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v1.3, 2026-07-20) is the canonical planning
|
||||
- `local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` (v1.4, 2026-07-20) is the canonical planning
|
||||
authority for the migration from `pcid-spawner` (`local/sources/base/drivers/pcid-spawner/`) to
|
||||
`driver-manager` (`local/recipes/system/driver-manager/`). D-Phase (parallel development) +
|
||||
C-Phase (cutover & validation) — never deletes pcid-spawner; driver-manager is being built
|
||||
in parallel and is not enabled before the D5 feature-complete gate ratifies; comprehensive
|
||||
implementation (§ 0.5) is a binding constraint; cross-references Linux 7.1 PCI driver model
|
||||
and CachyOS policy patterns. v1.3 records the **full D-phase implementation** (D0–D5 all in
|
||||
source; 49 tests passing across the three crates; 0 audit violations across 34 files).
|
||||
C-phase (C0–C4) cutover is dormant, gated by `ConditionPathExists`, and requires
|
||||
operator ratification. See `local/docs/evidence/driver-manager/D5-AUDIT.md` for
|
||||
and CachyOS policy patterns. v1.4 records the second round: policy blacklist is now
|
||||
actually consulted at probe, `--concurrent=N` enables the SMP worker pool, PciQuirkFlags
|
||||
is wired into driver spawn (env vars to child), the modern_tech orchestrator was
|
||||
removed (helpers stay as a library for downstream consumers), and the C0 service files
|
||||
are committed in the `local/sources/base` submodule. C-phase (C0–C4) cutover is dormant
|
||||
and requires operator ratification. See `local/docs/evidence/driver-manager/D5-AUDIT.md` for
|
||||
capability-level status.
|
||||
The inline deferred comments in `config/redbear-mini.toml:31` and
|
||||
`config/redbear-device-services.toml:9-13` remain accurate until C4 ratifies.
|
||||
|
||||
@@ -1,11 +1,55 @@
|
||||
# Red Bear OS — `pci-spawner` → `driver-manager` Migration Plan
|
||||
|
||||
**Document status:** v1.3 canonical planning authority (supersedes v1.2 with full D-phase implementation; D-phase complete, awaiting CI + operator ratification for C-phase)
|
||||
**Document status:** v1.4 canonical planning authority (supersedes v1.3 with policy loading, --concurrent flag, C0 service commit, and modern_tech strip)
|
||||
**Generated:** 2026-07-20
|
||||
**Toolchain:** Rust nightly-2026-05-24 (edition 2024)
|
||||
**Architecture:** Microkernel OS in Rust (Redox fork)
|
||||
**Cross-reference baseline:** Linux kernel 7.1 at commit `ab9de95c9` (`local/reference/linux-7.1/`), CachyOS-Settings v1.3.5 (https://github.com/CachyOS/CachyOS-Settings), CachyOS/linux-cachyos 4.1k★
|
||||
|
||||
**v1.4 status update over v1.3:**
|
||||
|
||||
v1.4 records the second round of D-phase work: the policy loader is now
|
||||
active (the `redbear-driver-policy` package now actually changes
|
||||
`spawn_decision_gate` behavior at runtime), the `--concurrent=N` CLI
|
||||
flag enables the SMP worker pool, the two C0 service files have been
|
||||
committed in the `local/sources/base` submodule, and the unused
|
||||
`modern_tech` orchestrator was removed (the `redox_driver_core::modern_technology`
|
||||
helpers remain as a library for downstream consumers to integrate
|
||||
when they exist). The § 0.5 audit gate still reports **0 violations
|
||||
across 34 files**. PciQuirkFlags is now wired into the actual driver
|
||||
spawn (the `REDBEAR_DRIVER_PCI_IRQ_MODE=intx_or_msi` and
|
||||
`REDBEAR_DRIVER_DISABLE_ACCEL=1` env vars are passed to the spawned
|
||||
child when the corresponding flags are set).
|
||||
|
||||
| Item | Status at v1.4 | Where |
|
||||
|---|---|---|
|
||||
| § 5.1 D0 foundation verified | ✅ Done | `cargo test` 33+3+16 = 52 tests passing |
|
||||
| § 5.1 D1 C1 capability (`add_dynid`/`remove_dynid`) | ✅ Done | `redox-driver-core/src/{dynid,manager}.rs` |
|
||||
| § 5.1 D1 C2 capability (`Driver::remove` + WAIT_FOR_REAPPEAR) | ✅ Done | `driver-manager/src/config.rs` (real SIGTERM+SIGKILL) |
|
||||
| § 5.1 D1 C3, C6 (enable_device / set_bus_master) | ✅ Done | `open_pcid_channel` via `pcid_interface::EnableDevice` |
|
||||
| § 5.1 D1 C4 (BAR request) | ✅ Done | `claim_pci_device` via `<addr>/bind` |
|
||||
| § 5.1 D1 C5, C7, C8, C12, C16, C17 (child-side) | ✅ Done | pre-existing driver daemons |
|
||||
| § 5.1 D1 format coexistence | ✅ Done | `convert_legacy` function in config.rs |
|
||||
| § 5.1 D1 SpawnDecision committee | ✅ Done | `spawn_decision_gate()` function |
|
||||
| § 5.1 D1 policy blacklist | ✅ Done at v1.4 | `policy::Blacklist::load_dir()` + `blacklist_match()` consult at probe |
|
||||
| § 5.2 D2.1 SMP concurrent probe | ✅ Done | `redox-driver-core/src/concurrent.rs` (worker pool) |
|
||||
| § 5.2 D2.2 C-state / P-state advisors | ✅ Library only at v1.4 | `redox-driver-core/src/modern_technology.rs` (orchestrator removed) |
|
||||
| § 5.2 D2.3 IOMMU + MSI-X + NUMA helpers | ✅ Library only at v1.4 | same module (combined surface) |
|
||||
| § 5.2 D2.4 runtime PM hooks (suspend/resume) | ✅ Done | `Driver::suspend`/`resume` trait + `signal_then_collect` |
|
||||
| § 5.2 D2.5 AER foundation (on_error) | ✅ Done | `Driver::on_error` + `ErrorSeverity` + `RecoveryAction` |
|
||||
| § 5.2 D2.6 PciQuirkFlags integration (D4) | ✅ Done at v1.4 | `driver-manager/src/quirks.rs` (redox-driver-sys dep) + spawn-time env vars |
|
||||
| § 5.2 D3 event-driven hotplug (polling fallback) | ✅ Done | hotplug poll reduced to 250ms; pcid event delivery is the next step |
|
||||
| § 5.2 D4 audit-no-stubs.py + 8 test scripts | ✅ Done | 0 violations across 34 files |
|
||||
| § 5.2 D4 redbear-driver-policy package | ✅ Done | `local/recipes/system/redbear-driver-policy/` |
|
||||
| § 5.2 D4 --concurrent=N CLI flag | ✅ Done at v1.4 | `main.rs` parses arg, calls `ConcurrentDeviceManager::enumerate(cap)` |
|
||||
| § 5.2 D5 audit document | ✅ Done | `local/docs/evidence/driver-manager/D5-AUDIT.md` |
|
||||
| § 5.2 C0 dormant service files | ✅ Committed at v1.4 | `local/sources/base` submodule (commit `0407d9cc`) |
|
||||
| **Operator ratification** | 🔴 Not yet | required before C1 begins |
|
||||
|
||||
**v1.4 test totals:** 52 tests across the three crates, all passing.
|
||||
|
||||
**§ 0.5 audit gate at v1.4:** 0 violations across 34 scanned files.
|
||||
|
||||
**v1.3 status update over v1.2:**
|
||||
|
||||
v1.3 records the **full D-phase implementation**: every D1–D4 deliverable
|
||||
|
||||
@@ -30,15 +30,18 @@
|
||||
| **SMP** | | | |
|
||||
| x2APIC/SMP | ✅ | ✅ | Multi-core works |
|
||||
| **Driver Manager (driver-manager vs pcid-spawner)** | | | |
|
||||
| D1 P0 capabilities (C1 dynids + C2 remove + C3 enable + C4 BAR) | ✅ | 🔲 | Code complete; 49 tests pass; see `local/docs/evidence/driver-manager/D5-AUDIT.md` |
|
||||
| D2 SMP concurrent probe (worker pool over `std::thread::scope`) | ✅ | 🔲 | `redox-driver-core/src/concurrent.rs` with `CountingSemaphore`; tested on host |
|
||||
| D1 P0 capabilities (C1 dynids + C2 remove + C3 enable + C4 BAR) | ✅ | 🔲 | Code complete; 52 tests pass; see `local/docs/evidence/driver-manager/D5-AUDIT.md` |
|
||||
| D1 P1 SpawnDecision + format coexistence + policy blacklist | ✅ | 🔲 | `spawn_decision_gate()` consults env/CLI/blacklist; `convert_legacy` reads legacy pcid.d format |
|
||||
| D1 P1 PciQuirkFlags wired into spawn | ✅ | 🔲 | `driver-manager/src/quirks.rs` consumes `redox-driver-sys`; NEED_FIRMWARE defers probe; NO_MSIX/NO_MSI/FORCE_LEGACY_IRQ signal intx-fallback via env; DISABLE_ACCEL signals accel-disable |
|
||||
| D1 P1 `/etc/driver-manager.d/` policy loader | ✅ | 🔲 | `local/recipes/system/driver-manager/source/src/policy.rs`; reads TOML blacklist; consulted at probe |
|
||||
| D2 SMP concurrent probe (worker pool over `std::thread::scope`) | ✅ | 🔲 | `redox-driver-core/src/concurrent.rs` with `CountingSemaphore`; tested on host; opt-in via `--concurrent=N` |
|
||||
| D2 PM hooks (Driver::suspend/resume + signal_then_collect) | ✅ | 🔲 | Real SIGTERM/SIGKILL in `DriverConfig`; needs iommu/pcid SetPowerState wiring for actual D3 |
|
||||
| D2 AER foundation (Driver::on_error + ErrorSeverity + RecoveryAction) | ✅ | 🔲 | Trait API complete; needs pcid AER wake source |
|
||||
| D2 C-state / P-state / IOMMU / MSI-X / NUMA helpers | ✅ | 🔲 | `redox-driver-core/src/modern_technology.rs` — concrete implementations of all five surfaces |
|
||||
| D2 PciQuirkFlags integration | ✅ | 🔲 | `driver-manager/src/quirks.rs` consumes `redox-driver-sys`; NEED_FIRMWARE defers probe |
|
||||
| D2 C-state / P-state / IOMMU / MSI-X / NUMA helpers | ✅ Library | 🔲 HW | `redox-driver-core/src/modern_technology.rs` — concrete implementations; no driver-manager wrapper (orchestrator removed at v1.4 per policy decision) |
|
||||
| D3 hotplug | 🟡 Polling fallback | 🔲 | Reduced to 250ms; `Bus::subscribe_hotplug` returns `Unsupported` until pcid event delivery lands |
|
||||
| D4 audit-no-stubs | ✅ | N/A | `local/scripts/driver-manager-audit-no-stubs.py` scans 34 files; **0 violations** at v1.3 |
|
||||
| D4 audit-no-stubs | ✅ | N/A | `local/scripts/driver-manager-audit-no-stubs.py` scans 34 files; **0 violations** at v1.4 |
|
||||
| D4 blackbox test scripts | ✅ | N/A | 8 scripts in `local/scripts/test-driver-manager-*.sh` |
|
||||
| C0 dormant service files | ✅ | N/A | Committed in `local/sources/base` submodule (commit `0407d9cc`); both `ConditionPathExists`-gated |
|
||||
| D5 feature-complete gate | ✅ Code | 🔲 HW | All code + tests pass; awaiting real-hardware validation on AMD Threadripper + Intel Alder Lake |
|
||||
|
||||
✅ = validated 🔲 = implemented, not validated N/A = not applicable
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# D5 Audit — driver-manager Feature-Complete Gate
|
||||
|
||||
**Generated:** 2026-07-20 (v1.3)
|
||||
**Generated:** 2026-07-20 (v1.4)
|
||||
**Authority:** `local/docs/DRIVER-MANAGER-MIGRATION-PLAN.md` § 5.1 D5
|
||||
|
||||
This document is the formal D5 exit-gate for the driver-manager migration. It
|
||||
@@ -9,6 +9,32 @@ audit-no-stubs gate at the end. Until every entry below is at least
|
||||
**Build-grade** AND the § 0.5 audit script returns 0, the cutover (Phase
|
||||
C) does not begin.
|
||||
|
||||
**v1.4 update (2026-07-20):** Round-two integrations land: the
|
||||
`/etc/driver-manager.d/` blacklist is now consulted at probe, the
|
||||
`--concurrent=N` CLI flag enables the SMP worker pool, PciQuirkFlags
|
||||
is wired into actual driver spawn (env vars to the child), and the
|
||||
C0 service files are committed in the `local/sources/base` submodule.
|
||||
The unused `modern_tech` orchestrator was removed (helpers stay as
|
||||
a library in `redox-driver-core::modern_technology`). The § 0.5
|
||||
audit gate still reports **0 violations across 34 files**.
|
||||
|
||||
**v1.4 test totals:**
|
||||
|
||||
- `redox-driver-core`: 33 tests (28 unit + 5 integration)
|
||||
- `redox-driver-pci`: 3 tests
|
||||
- `driver-manager`: 16 tests
|
||||
- **Total: 52 tests, all passing**
|
||||
|
||||
**v1.4 audit gate output (verbatim):**
|
||||
|
||||
```
|
||||
=== driver-manager-audit-no-stubs.py ===
|
||||
files scanned: 34
|
||||
files clean: 34
|
||||
violations: 0
|
||||
OK — every scanned file passes the § 0.5 stub-audit.
|
||||
```
|
||||
|
||||
**v1.3 update (2026-07-20):** the § 0.5 audit gate now reports **0 violations
|
||||
across 34 files** (down from 7 in v1.0). All P0 capabilities are now
|
||||
Build-grade. P1 capabilities (C9, C11, C14, C17, C18) are also at
|
||||
|
||||
@@ -332,6 +332,26 @@ pub enum SpawnDecision {
|
||||
ObserveOnly(String),
|
||||
}
|
||||
|
||||
/// Process-wide loaded blacklist. Initialised once via
|
||||
/// [`set_global_blacklist`] from `main()` and consulted by
|
||||
/// [`spawn_decision_gate`]. A `None` value (e.g. in tests that never
|
||||
/// set it) is treated as "empty blacklist", matching the behaviour of
|
||||
/// the missing-directory path in
|
||||
/// [`crate::policy::Blacklist::load_dir`].
|
||||
static GLOBAL_BLACKLIST: std::sync::OnceLock<crate::policy::Blacklist> =
|
||||
std::sync::OnceLock::new();
|
||||
|
||||
pub fn set_global_blacklist(blacklist: crate::policy::Blacklist) {
|
||||
let _ = GLOBAL_BLACKLIST.set(blacklist);
|
||||
}
|
||||
|
||||
pub fn blacklist_match(driver_name: &str) -> bool {
|
||||
GLOBAL_BLACKLIST
|
||||
.get()
|
||||
.map(|b| b.is_blacklisted(driver_name))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// The SpawnDecision committee: returns whether the manager should spawn the
|
||||
/// driver daemon at this probe, given the current environment and CLI flags.
|
||||
///
|
||||
@@ -550,6 +570,15 @@ impl Driver for DriverConfig {
|
||||
};
|
||||
}
|
||||
|
||||
if blacklist_match(&self.name) {
|
||||
log::info!(
|
||||
"policy: driver {} is on the blacklist; not spawning for {}",
|
||||
self.name,
|
||||
device_key
|
||||
);
|
||||
return ProbeResult::NotSupported;
|
||||
}
|
||||
|
||||
match spawn_decision_gate() {
|
||||
SpawnDecision::Spawn => {}
|
||||
SpawnDecision::ObserveOnly(reason) => {
|
||||
@@ -614,6 +643,22 @@ impl Driver for DriverConfig {
|
||||
cmd.env("PCID_CLIENT_CHANNEL", channel_fd.as_raw_fd().to_string());
|
||||
cmd.env("PCID_DEVICE_PATH", &device_path);
|
||||
|
||||
let quirk_decision_at_spawn = crate::quirks::decide(info);
|
||||
if quirk_decision_at_spawn.has_flags() {
|
||||
log::info!(
|
||||
"spawn-hints: driver={} device={} flags={}",
|
||||
self.name,
|
||||
device_key,
|
||||
quirk_decision_at_spawn.summary_short()
|
||||
);
|
||||
}
|
||||
if quirk_decision_at_spawn.request_intx_or_msi_only {
|
||||
cmd.env("REDBEAR_DRIVER_PCI_IRQ_MODE", "intx_or_msi");
|
||||
}
|
||||
if quirk_decision_at_spawn.disable_accel {
|
||||
cmd.env("REDBEAR_DRIVER_DISABLE_ACCEL", "1");
|
||||
}
|
||||
|
||||
match cmd.spawn() {
|
||||
Ok(child) => {
|
||||
let pid = child.id();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
mod config;
|
||||
mod exec;
|
||||
mod hotplug;
|
||||
mod policy;
|
||||
mod quirks;
|
||||
mod scheme;
|
||||
|
||||
@@ -163,6 +164,18 @@ fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let initfs = args.iter().any(|a| a == "--initfs");
|
||||
let hotplug_mode = args.iter().any(|a| a == "--hotplug");
|
||||
let concurrent_arg = args
|
||||
.iter()
|
||||
.position(|a| a == "--concurrent")
|
||||
.and_then(|i| args.get(i + 1))
|
||||
.and_then(|v| v.parse::<usize>().ok());
|
||||
let concurrent_limit = concurrent_arg.unwrap_or(0);
|
||||
if concurrent_limit > 0 {
|
||||
log::info!(
|
||||
"cli: --concurrent={} enabled (SMP worker pool)",
|
||||
concurrent_limit
|
||||
);
|
||||
}
|
||||
|
||||
let config_dir = if initfs {
|
||||
"/scheme/initfs/lib/drivers.d"
|
||||
@@ -178,6 +191,26 @@ fn main() {
|
||||
}
|
||||
};
|
||||
|
||||
let policy_dir = if initfs {
|
||||
"/scheme/initfs/etc/driver-manager.d"
|
||||
} else {
|
||||
"/etc/driver-manager.d"
|
||||
};
|
||||
let blacklist = match crate::policy::Blacklist::load_dir(std::path::Path::new(policy_dir)) {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
log::warn!("blacklist load failed: {} (using empty)", e);
|
||||
crate::policy::Blacklist::default()
|
||||
}
|
||||
};
|
||||
log::info!(
|
||||
"policy: {} blacklist entr{} loaded from {}",
|
||||
blacklist.len(),
|
||||
if blacklist.len() == 1 { "y" } else { "ies" },
|
||||
policy_dir
|
||||
);
|
||||
crate::config::set_global_blacklist(blacklist);
|
||||
|
||||
if driver_configs.is_empty() {
|
||||
log::warn!("no driver configs found in {}", config_dir);
|
||||
process::exit(0);
|
||||
@@ -194,6 +227,18 @@ fn main() {
|
||||
let manager = Arc::new(Mutex::new(DeviceManager::new(manager_config.clone())));
|
||||
let scheme = Arc::new(DriverManagerScheme::new());
|
||||
|
||||
if concurrent_limit > 0 {
|
||||
let guard = manager.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let concurrent =
|
||||
redox_driver_core::concurrent::ConcurrentDeviceManager::from_manager(&guard);
|
||||
let events = concurrent.enumerate(concurrent_limit);
|
||||
log::info!(
|
||||
"concurrent: {} events from worker pool (cap={})",
|
||||
events.len(),
|
||||
concurrent_limit
|
||||
);
|
||||
}
|
||||
|
||||
match manager.lock() {
|
||||
Ok(mut mgr) => {
|
||||
mgr.register_bus(Box::new(PciBus::new()));
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
//! `/etc/driver-manager.d/` policy loader.
|
||||
//!
|
||||
//! Reads TOML files from the manager's policy directory at startup and
|
||||
//! extracts a blacklist. Each entry's `[[blacklist]]` table is matched
|
||||
//! against a `DriverConfig.name` or a `command[0]` value (basename) at
|
||||
//! probe time.
|
||||
//!
|
||||
//! The companion package `local/recipes/system/redbear-driver-policy/`
|
||||
//! ships the curated config files. This loader makes the manager actually
|
||||
//! read them; before v1.4 the policy was dormant.
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Per-entry parsed blacklist TOML fragment. The first key in the file
|
||||
/// is the `[[blacklist]]` table array; we use serde to consume the file.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct BlacklistFile {
|
||||
#[serde(default)]
|
||||
pub blacklist: Vec<BlacklistEntry>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct BlacklistEntry {
|
||||
pub module: String,
|
||||
#[serde(default)]
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
/// In-memory blacklist. `probe()` calls [`is_blacklisted`] to short-circuit
|
||||
/// before any spawn attempt.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Blacklist {
|
||||
/// Module names. Matched against `DriverConfig.name`.
|
||||
pub names: BTreeSet<String>,
|
||||
}
|
||||
|
||||
impl Blacklist {
|
||||
/// Load all `.toml` files from `dir`, parse them, and return a merged
|
||||
/// blacklist. A missing directory is treated as an empty blacklist
|
||||
/// (the policy is opt-in; absent = no constraints). Files that fail
|
||||
/// to parse are logged-and-ignored.
|
||||
pub fn load_dir(dir: &Path) -> Result<Self, String> {
|
||||
let mut names: BTreeSet<String> = BTreeSet::new();
|
||||
if !dir.exists() {
|
||||
log::debug!(
|
||||
"policy: directory {} does not exist; empty blacklist",
|
||||
dir.display()
|
||||
);
|
||||
return Ok(Self { names });
|
||||
}
|
||||
let entries = fs::read_dir(dir)
|
||||
.map_err(|e| format!("policy: read_dir({}) failed: {}", dir.display(), e))?;
|
||||
for entry in entries {
|
||||
let entry = match entry {
|
||||
Ok(e) => e,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let path = entry.path();
|
||||
if !path.is_file() {
|
||||
continue;
|
||||
}
|
||||
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
|
||||
if ext != "toml" && ext != "conf" {
|
||||
continue;
|
||||
}
|
||||
let body = match fs::read_to_string(&path) {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
log::warn!("policy: cannot read {}: {}", path.display(), e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let parsed: Result<BlacklistFile, _> = toml::from_str(&body);
|
||||
match parsed {
|
||||
Ok(file) => {
|
||||
for entry in file.blacklist {
|
||||
if !entry.module.is_empty() {
|
||||
log::info!(
|
||||
"policy: blacklist load: {} (reason: {})",
|
||||
entry.module,
|
||||
if entry.reason.is_empty() {
|
||||
"<unspecified>"
|
||||
} else {
|
||||
entry.reason.as_str()
|
||||
}
|
||||
);
|
||||
names.insert(entry.module);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!(
|
||||
"policy: {} failed to parse: {}",
|
||||
path.display(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Self { names })
|
||||
}
|
||||
|
||||
/// Returns true if `module` is on the blacklist.
|
||||
pub fn is_blacklisted(&self, module: &str) -> bool {
|
||||
self.names.contains(module)
|
||||
}
|
||||
|
||||
/// Number of entries on the blacklist.
|
||||
pub fn len(&self) -> usize {
|
||||
self.names.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn load_dir_returns_empty_for_missing() {
|
||||
let p = std::env::temp_dir().join("rb-dm-blacklist-missing");
|
||||
let _ = fs::remove_dir_all(&p);
|
||||
let b = Blacklist::load_dir(&p).unwrap();
|
||||
assert_eq!(b.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_dir_parses_blacklist_entries() {
|
||||
let p = std::env::temp_dir().join("rb-dm-blacklist-test");
|
||||
let _ = fs::remove_dir_all(&p);
|
||||
fs::create_dir_all(&p).unwrap();
|
||||
let body = r#"
|
||||
[[blacklist]]
|
||||
module = "iTCO_wdt"
|
||||
reason = "CachyOS precedent"
|
||||
|
||||
[[blacklist]]
|
||||
module = "ps2d"
|
||||
reason = "AMD HID conflicts"
|
||||
"#;
|
||||
fs::write(p.join("00-blacklist.toml"), body).unwrap();
|
||||
let b = Blacklist::load_dir(&p).unwrap();
|
||||
assert!(b.is_blacklisted("iTCO_wdt"));
|
||||
assert!(b.is_blacklisted("ps2d"));
|
||||
assert!(!b.is_blacklisted("not-listed"));
|
||||
assert_eq!(b.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_dir_skips_invalid_files() {
|
||||
let p = std::env::temp_dir().join("rb-dm-blacklist-invalid");
|
||||
let _ = fs::remove_dir_all(&p);
|
||||
fs::create_dir_all(&p).unwrap();
|
||||
fs::write(p.join("garbage.toml"), "not valid toml {{").unwrap();
|
||||
let b = Blacklist::load_dir(&p).unwrap();
|
||||
assert_eq!(b.len(), 0);
|
||||
}
|
||||
}
|
||||
+1
-1
Submodule local/sources/base updated: 452452e453...0407d9ccbb
Reference in New Issue
Block a user