10.6 The Fd Store
The fd store lets a service keep file descriptors across its own restart. It pushes them to peinit, peinit holds them, and the new process gets them back. That is what lets a stateful daemon — a web server holding a listening socket, say — restart without dropping connections it has already accepted.
FdStoreMax in the definition sets the maximum number of descriptors
peinit will hold. It defaults to 0, which disables the store: most
services do not need it, and holding descriptors on behalf of a service
that will never ask for them back is pure cost.
10.6.1 Storing #
When an authenticated datagram carries FDSTORE=1 with descriptors
attached:
- If
FdStoreMaxis 0, peinit logs the rejection and closes the descriptor. - If the store already holds
FdStoreMaxentries, peinit logs the rejection and closes the descriptor. The existing store is not modified — a full store does not evict. FDNAME=<name>names it; an absent or empty name meansstored.FDPOLL=0marks the descriptor exempt from poll monitoring.
Either rejection emits an fd_store.rejected event carrying the outcome
and the reason, so a service whose descriptors are being silently
dropped can find out why.
Several descriptors may share a name. One FDSTORE=1 carrying N
descriptors creates N entries under the one name, each independently
subject to the limit — so the first few fit and the overflow is
rejected and closed.
peinit does not monitor stored descriptors. The FDPOLL flag is
recorded and nothing reads it, so no stored descriptor is evicted for
becoming invalid.
10.6.2 Removing #
FDSTOREREMOVE=1 with FDNAME=<name> removes every descriptor of that
name and closes them. A name matching nothing is a no-op rather than an
error.
FDSTOREREMOVE=1 without a name aborts the whole fd-store step for
that datagram — so a datagram carrying both an unnamed remove and an
FDSTORE=1 performs neither, and the attached descriptors are dropped
and closed.
10.6.3 Injecting #
When a service restarts, peinit injects the stored descriptors during the child's pre-exec path (§5.4):
- They are placed consecutively from
SD_LISTEN_FDS_START— descriptor 3 — upward, with close-on-exec cleared: the only sanctioned exception to the close-on-exec discipline. LISTEN_FDSis set to the count.LISTEN_FDNAMESis set to a colon-separated list of names in the same order as the descriptor numbers.- The store is cleared. peinit no longer holds them.
Both variables are omitted entirely when the store is empty.
LISTEN_PID, which a conforming client checks against its own PID
before trusting LISTEN_FDS, is not set.
Injection happens for the main process only. Hooks and health checks never receive stored descriptors.
The store is cleared on a successful injection, at the top of the started-launch handling. A launch that fails does not clear it, so the descriptors survive a failed attempt and are available to the next one.
10.6.4 Clearing #
The store is cleared, and its descriptors closed, when:
- The service is stopped explicitly — by an administrator, or by shutdown. The distinction peinit draws is the operation's type and source together: an administrator's stop clears, and a restart-policy-sourced stop does not. The service is not coming back from an explicit stop, so the descriptors are no longer useful.
- The definition is removed and its entry finally discarded (§3.8), immediately if nothing was running and on the instance's exit otherwise.
It survives an automatic restart — crash, restart policy, new start — which is the entire point. The descriptors persist through exactly the restart the service did not choose and cannot prepare for.