Skip to content

libsystemd: mounts as devices, a rule key to run a unit on removal, configuration directories of mount points - #9

Merged
JohnAmadis merged 7 commits into
mainfrom
feat/per-mount-config-dirs
Oct 25, 2026
Merged

JohnAmadis merged 7 commits into
mainfrom
feat/per-mount-config-dirs

Conversation

@JaxCalder

@JaxCalder JaxCalder commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

What

libsystemd hears every mount and unmount (dmfsi's _mount_changed dif, called by dmvfs) and uses it for three things:

  • The mount is a device of class mount - named after the mount point (/mnt/SD -> mnt_SD, /ext -> ext, / -> root), the mount point as its value (%v). The rules decide what that means, and whatever they start does its work in a process of its own, with the stack its module asks for.
  • Rules: a new remove key. A section may have start, remove or both; remove is a unit started when a device of the class goes away (after the units start started are stopped), with %name and the value the device was reported with as %v. The removal waits for it (up to 20 s each) - an unmount must not go on before the units of the file system are done.
  • The configuration directory of the mount point, loaded by libsystemd itself - no API for anyone to call. <mount point>/cfg/services and cfg/rules are added to what libsystemd_scan() / libsystemd_load_rules() loaded (nothing is reloaded or restarted) when a file system is mounted, and its units start in their dependency order; before the unmount the remove units run, then everything that came from there stops and is dropped (template instances included). A full reload keeps the loaded directories, the units directory of libsystemd_scan() is never loaded twice, a unit or template whose name is taken stays the first one. %m = the mount point the unit comes from, e.g. exec=%m/bin/app.dmfc, so a unit stays bound to its own card. The module search path is invalidated first - /mnt/<label>/bin is on it, cached, and automount only gets to it after the mount returned.
  • Registry lock: libsystemd is called from several threads (dmdevfs hot-plug, the shell, systemd) - two of them starting the same template instance registered it twice on the board. A recursive lock guards the lists only and is never held while a unit is spawned, stopped or waited for. libsystemd_forget_device() leaked the device's user value.

The drivers of a mount point (cfg/drivers) are not libsystemd's: dmdevfs loads them, asked to by a service a rule starts (devscan, choco-technologies/dmdevfs#75).

Stack

The dif is called in the thread that mounts - automount's. Loading a directory and starting a unit from a card there peaked at 2596 bytes of automount's stack on the board (a card unit, carhmi, plus the one-shot devscan); automount is released with 2 kB (2560 with the overhead), so it needs 4 kB (choco-technologies/dmblock#6, services/automount/CMakeLists.txt) - without it the stack overflows (vApplicationStackOverflowHook).

Testing

  • Host: test_libsystemd 73/73 (10 new: the dif is implemented, a mount is a device the start rule matches with the mount point as %v, an unmount starts the remove unit with the remembered value, a rule with only remove; a mount adds/starts and an unmount removes the units of cfg/services, the first definition stays, rules and templates of a mount point, survival of a full reload, no double loading of the scanned directory, a mount without cfg/), test_systemd / test_service 1/1. The host loader needs Dmod_InvalidateModuleSearchPaths (dmod develop).
  • STM32F746G-DISCO with dmod-boot#148: after a cold boot the card is mounted, carhmi starts from <card>/cfg/services/carhmi/carhmi.ini by itself and devscan runs; a probe unit in /ext/cfg/services: umount /ext + mount loads it (fresh instance each cycle, %m = /ext, exactly one), devscan-remove@ext runs on every unmount.

Needs dmfsi with the _mount_changed dif (choco-technologies/dmfsi#21, merged). Part of: choco-technologies/dmdevfs#75, choco-technologies/dmod-boot#148.

🤖 Generated with Claude Code

JaxCalder and others added 2 commits October 24, 2026 11:03
libsystemd_add_config_dir(mount_point) loads <mount_point>/cfg/services and
<mount_point>/cfg/rules in addition to what libsystemd_scan() and
libsystemd_load_rules() loaded and starts the new units in their dependency
order; libsystemd_remove_config_dir() stops and removes exactly what came from
there (template instances included). A full reload keeps the loaded
directories. The root file system's directory is the scanned one and is not
loaded twice; a unit or template whose name is taken stays the first one.

%m expands to the mount point the unit comes from - in plain units too, where
it is the only specifier - so a unit on a card names its own module and files
(exec=%m/bin/app.dmfc) and stays bound to that card.

libsystemd does not follow mounts itself (it would have to require dmvfs,
which the host loader does not have): the module that does calls both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
libsystemd is called from several threads (dmdevfs's hot-plug thread, the
module following mounts, the shell, systemd): two of them starting the same
template instance at once registered it twice. The lists of the registry (units,
templates, rules, devices, configuration directories) are guarded by a recursive
lock held only while a list is read or changed - never while a unit is spawned,
stopped or waited for. libsystemd_scan() replaces the registry at once and stops
the previous generation outside the lock; a removed configuration directory's
units are taken out under it and stopped after. libsystemd_forget_device()
leaked the user value of the device.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
JaxCalder and others added 4 commits October 25, 2026 08:05
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
libsystemd implements dmfsi's _mount_changed dif and reports every mount as a
device of class "mount" (named after the mount point, the mount point as its
value) - nothing else: what it means is up to the rules, and whatever they start
does its work in a process of its own with its own stack.

For that a rule section may now have a "remove" key: a unit started when a
device of the class goes away (after the units "start" started are stopped),
with %name and the value the device was reported with as %v. The removal waits
for it (up to 20 s) - an unmount must not go on before the units of the file
system are done.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@JaxCalder JaxCalder changed the title libsystemd: configuration directories of mount points, registry lock libsystemd: mounts as devices, a rule key to run a unit on removal, configuration directories of mount points Oct 25, 2026
A mounted file system's configuration is nothing libsystemd should know
about: loading it is the job of whoever owns the thing it configures (for
/dev that is dmdevfs). Remove libsystemd_add_config_dir()/remove_config_dir(),
the %m specifier and everything built for them.

What stays is generic:
- dmfsi's _mount_changed dif is implemented, a mount is reported as a device
  of class "mount" (named after the mount point, %v = the mount point);
- the `remove` key of a rule, started when a device of the class goes away
  and waited for;
- a registry lock, so units can be started from several threads at once;
- the user_value of a forgotten device is freed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@JaxCalder JaxCalder changed the title libsystemd: mounts as devices, a rule key to run a unit on removal, configuration directories of mount points libsystemd: mounts as devices, a rule key to run a unit on removal Oct 25, 2026
@JohnAmadis
JohnAmadis merged commit a854fad into main Oct 25, 2026
1 check passed
@JaxCalder JaxCalder changed the title libsystemd: mounts as devices, a rule key to run a unit on removal libsystemd: mounts as devices, a rule key to run a unit on removal, configuration directories of mount points Oct 25, 2026
JohnAmadis added a commit that referenced this pull request Oct 26, 2026
…-libsystemd

libsystemd: load the configuration directory of a mount point by itself (follow-up to #9)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants