private: module_loaded ignores a module left in memory by a failed _init (G7) #9

Merged
toasterson merged 2 commits from g7-module-busy into main 2026-10-05 16:35:15 +00:00
Owner

Anima work item: G7 01a1028d-7fdb-7411-9ddb-af9b0f9d4444

Stacked on #8 (r5a-char-table). ddi::private::module_loaded no longer counts a module that is only in memory.

Why

A module that another module requires is loaded by krtld and initialised by mod_install_requisites(), which does not unload it when its _init fails; modunload cannot either (moduninstall answers EALREADY for a module that is not installed), modinfo does not list it, and it keeps mod_loaded set until it is loaded again. The first G7 guest run of illumos-drm found that this kept misc/drm_core out after a refused modload drv/i915 (gfx-drm's misc/drm, loaded as i915's dependency, refused in its _init and stayed in memory), until misc/drm was loaded again (logs/hephaistos/illumos-drm/20261003-g7-run1-guards.log).

Change

  • module_loaded is true for a module that is installed (mod_installed), or in memory and busy (mod_loaded && mod_busy), as it is while its _init or _fini runs. mod_busy changes under mod_lock, and mod_installed is set before the module is released, so the walk sees an initialising module busy or installed.
  • Two modules that refuse each other in _init still exclude each other: each is in memory and busy before its own _init checks, and both checks hold mod_lock, so the second sees the first.
  • Docs: the wrapper, modctl binding (mod_busy under mod_lock), DESIGN.md §5.12 row. Host unit test of the flag rule (in_memory): installed, in memory and busy count; only in memory, only busy, nothing do not.

Evidence

  • Host: cargo test -p ddi --no-default-features --lib 12 passed; --features unstable-gate-cda5b9a49f-virtio --lib 18 passed (incl. in_memory_from_flags, name_matches_like_strcmp); doctests (--target x86_64-unknown-illumos) pass; clippy with the private-tier feature, fmt and rustdoc clean.
  • Guest (illumos-drm G7 run3, illumos 7e802e88a3, misc/drm_core built at this pin): a refused drv/i915 left misc/drm in memory (::modctl bits l) and misc/drm_core then loaded; a DTrace chill holding misc/drm in modinstall (loaded and busy, before _init) made misc/drm_core refuse; 100 concurrent loads of both cores ended with exactly one loaded each time. Logs logs/hephaistos/illumos-drm/20261003-g7-run3-{guards,overlap}.log in the workspace.
  • The rselftest checks (genunix, unix loaded; no_such_module_xyz not) still hold by construction (primary modules are installed) but were not rerun in a kernel.

Open

  • rselftest not rerun on this commit.
Anima work item: G7 `01a1028d-7fdb-7411-9ddb-af9b0f9d4444` Stacked on #8 (`r5a-char-table`). `ddi::private::module_loaded` no longer counts a module that is only in memory. ## Why A module that another module requires is loaded by krtld and initialised by `mod_install_requisites()`, which does not unload it when its `_init` fails; `modunload` cannot either (`moduninstall` answers `EALREADY` for a module that is not installed), `modinfo` does not list it, and it keeps `mod_loaded` set until it is loaded again. The first G7 guest run of illumos-drm found that this kept `misc/drm_core` out after a refused `modload drv/i915` (gfx-drm's `misc/drm`, loaded as i915's dependency, refused in its `_init` and stayed in memory), until `misc/drm` was loaded again (`logs/hephaistos/illumos-drm/20261003-g7-run1-guards.log`). ## Change - `module_loaded` is `true` for a module that is installed (`mod_installed`), or in memory and busy (`mod_loaded && mod_busy`), as it is while its `_init` or `_fini` runs. `mod_busy` changes under `mod_lock`, and `mod_installed` is set before the module is released, so the walk sees an initialising module busy or installed. - Two modules that refuse each other in `_init` still exclude each other: each is in memory and busy before its own `_init` checks, and both checks hold `mod_lock`, so the second sees the first. - Docs: the wrapper, `modctl` binding (`mod_busy` under `mod_lock`), DESIGN.md §5.12 row. Host unit test of the flag rule (`in_memory`): installed, in memory and busy count; only in memory, only busy, nothing do not. ## Evidence - Host: `cargo test -p ddi --no-default-features --lib` 12 passed; `--features unstable-gate-cda5b9a49f-virtio --lib` 18 passed (incl. `in_memory_from_flags`, `name_matches_like_strcmp`); doctests (`--target x86_64-unknown-illumos`) pass; clippy with the private-tier feature, fmt and rustdoc clean. - Guest (illumos-drm G7 run3, illumos `7e802e88a3`, misc/drm_core built at this pin): a refused `drv/i915` left `misc/drm` in memory (`::modctl` bits `l`) and `misc/drm_core` then loaded; a DTrace chill holding `misc/drm` in `modinstall` (loaded and busy, before `_init`) made `misc/drm_core` refuse; 100 concurrent loads of both cores ended with exactly one loaded each time. Logs `logs/hephaistos/illumos-drm/20261003-g7-run3-{guards,overlap}.log` in the workspace. - The `rselftest` checks (`genunix`, `unix` loaded; `no_such_module_xyz` not) still hold by construction (primary modules are installed) but were not rerun in a kernel. ## Open - rselftest not rerun on this commit.
A module that another module requires is loaded by krtld and initialised
by mod_install_requisites(), which does not unload it when its _init
fails; modunload cannot either (moduninstall answers EALREADY for a
module that is not installed), and modinfo does not list it. Such a
record keeps mod_loaded set until the module is loaded again. Counting
it as loaded kept illumos-drm's misc/drm_core out after a refused load of
gfx-drm's i915 (whose dependency misc/drm refused in its _init) until
misc/drm was loaded again.

module_loaded now answers true for a module that is installed, or in
memory and busy (mod_busy, which the framework holds while _init or _fini
runs, and which changes under mod_lock), and false for one that is only in
memory. Two modules that refuse each other in _init still exclude each
other: each is in memory and busy before its _init checks, and the
mutex_enter of mod_lock orders those stores before the walk.
private: module_loaded: the exclusion rests on mod_lock
All checks were successful
ci / kmod-illumos (pull_request) Successful in 22m17s
ci / check-hosted (pull_request) Successful in 27m29s
6e65077fb1
Both checks hold mod_lock, so the second sees what the first module
stored before its check, on any architecture; say so instead of naming
the ordering of one mutex_enter.
toasterson changed target branch from r5a-char-table to main 2026-10-05 16:35:08 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
illumos/illumos-ddi!9
No description provided.