Hello Toradex team,
I hope you are all doing great! And thank you for your support.
On our devices that are already provisioned, multi-user.target comes only after the first NTP sync. We think the cause is the stock auto-provisioning.service. With a drop-in that skips the wait, multi-user.target comes about 17 s earlier on Torizon OS 7 and about 32 s earlier on TorizonCore 6. We would like to know if this drop-in is safe.
Hardware:
- SoM Verdin iMX8M Plus Quad 4GB WB IT V1.1A
- Custom Carrier Board based on Verdin
uname:
- Torizon OS 7:
6.6.142-7.7.0 #1-Torizon SMP PREEMPT Fri Jun 19 08:16:23 UTC 2026 aarch64 - TorizonCore 6:
5.15.209-6.8.9+git.3342fc7bf0a9 #1-TorizonCore SMP PREEMPT Thu Jun 18 14:03:37 UTC 2026 aarch64
Images tested:
torizon-docker-verdin-imx8mp-Tezi_7.7.0+build.40.tar, customized with TorizonCore Builder. systemd 255.21torizon-core-docker-verdin-imx8mp-Tezi_6.8.9+build.46.tar, customized with TorizonCore Builder. systemd 250.14
Provisioning:
- Both images: online auto-provisioning (
provisioning: mode: onlineintcbuild.yaml) - All tests on devices that are already provisioned
Issue:
On a provisioned device, multi-user.target comes just after the first NTP sync: at 33.2 s on Torizon OS 7.7.0, and at 46.6 s on TorizonCore 6.8.9 (one boot each, office network). Both versions behave the same.
Until then, graphical.target waits too, and systemctl is-system-running stays starting.
On a network that blocks NTP (UDP 123), multi-user.target would never come, because systemd-time-wait-sync.service has TimeoutStartSec=infinity.
What we found in the unit file:
The stock /usr/lib/systemd/system/auto-provisioning.service is the same on 6.8.9 and 7.7.0:
[Unit]
Description=Automatically provision the device to the Platform Services
After=network-online.target systemd-time-wait-sync.service
Wants=network-online.target
Requires=systemd-time-wait-sync.service
ConditionPathExists=/var/sota/auto-provisioning.json
ConditionPathExists=!/var/sota/import/pkey.pem
[Install]
WantedBy=multi-user.target
- The unit is enabled, so every boot queues it.
Requires=queuessystemd-time-wait-sync.servicewith it. - systemd checks a unit’s conditions only when its job is about to run, after its
After=units. So the twoConditionPathExists=lines do not prevent the wait:systemd-time-wait-syncruns to completion first, and only then isauto-provisioningskipped. - A target is ordered after the units it wants. So
multi-user.targetwaits forauto-provisioning.service, which waits for the first NTP sync.
What the wait does not delay, on our images:
aktualizr-torizon.serviceis not ordered aftertime-sync.target. ItsAfter=holdsnetwork-online.target,nss-lookup.targetandboot-complete.target. So the update client never waited for this.- Nothing is ordered after
time-sync.target:systemctl show time-sync.target -p Beforegives onlyshutdown.target. - Our application containers (
docker-compose.service) do not wait formulti-user.target.
So the wait delays multi-user.target and what comes after it, not the application.
What we tested:
A drop-in, /etc/systemd/system/systemd-time-wait-sync.service.d/override.conf:
[Unit]
RequiresMountsFor=/var/sota/import
ConditionPathExists=!/var/sota/import/pkey.pem
- The condition uses the same marker as the stock
auto-provisioning.service. A device that is not provisioned yet still waits for NTP before it provisions, since TLS needs a correct clock. A provisioned device skips the wait. A unit skipped on a condition still satisfiesRequires=. RequiresMountsFor=is needed, becausesystemd-time-wait-sync.servicehasDefaultDependencies=no. Without it, systemd checked the condition at 4.77 s, before/varwas mounted (5.57 s), saw no key and ran the wait anyway. With it, the check comes after the mount (5.85 s vs 5.83 s) and the wait is skipped.
Result:
Time to multi-user.target, from the journal (Reached target Multi-User System):
| Stock (one boot) | With the drop-in (mean of 10 boots) | Range of the 10 boots | |
|---|---|---|---|
| Torizon OS 7.7.0 | 33.2 s | 15.9 s | 13.8 to 17.1 s |
| TorizonCore 6.8.9 | 46.6 s | 14.5 s | 13.5 to 17.0 s |
systemd-time-wait-syncreportedConditionResult=noon all 20 boots.- The NTP sync still happens, in the background: about 32 s after boot on 7.7.0 (31.9 to 32.7 s over the same 10 boots).
multi-user.targetis now gated bynetwork-online.target(systemd-analyze critical-chain).
Questions:
- Is the wait after provisioning intended? Does any Torizon component (aktualizr, remote access, tzn-mqtt, docker, …) expect
time-sync.target, ormulti-user.target, to mean “the clock is synced” on a provisioned device? - Is this drop-in a safe way to skip the wait? Do you recommend another marker than
/var/sota/import/pkey.pem, or another approach? - Could the stock image do the same, for example with this condition shipped as a drop-in in the auto-provisioning recipe?
Our plan for now: keep this drop-in in our image, unless you see a problem with it.
I can share the boot journals and the systemd-analyze output of the 20 boots if useful.
Best regards,
M