Skip to content

logind starts at the first login and not at the boot, and that is 24ms - #5

Merged
aledbf merged 1 commit into
mainfrom
logind-on-demand
Sep 12, 2026
Merged

logind starts at the first login and not at the boot, and that is 24ms#5
aledbf merged 1 commit into
mainfrom
logind-on-demand

Conversation

@aledbf

@aledbf aledbf commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

pam_systemd decides whether to register a session by calling logind_running(), which is access("/run/systemd/seats/") — a test for "is this a system with logind", not for "is logind up". On a false answer it logs "Skipping logind registration as logind is not running" and returns PAM_SUCCESS: the login authenticates and lands with no XDG_RUNTIME_DIR, no XDG_SESSION_ID and no user manager, and nothing anywhere reports an error.

logind creates that directory itself, so the guard is false exactly while logind has never run. Creating it on the Varlink socket, which carries Service=systemd-logind.service, makes the guard tell the truth before logind runs and turns pam_systemd's connection into what starts it. Every login path activates it, not only SSH: the console getty and su go through the same module.

Worth 24ms: 249/287 against 273/297 with logind wanted by multi-user.target, p50/p95 over 25 boots each, reproduced in two runs. The fork gives 4ms of that back and buys the sessions; masking logind outright would be 7ms better again and would leave every login without one.

The want is overridden with a /dev/null symlink and not removed, because it is not in /etc to begin with: the package ships it in /usr. The first version of this used rm -f on the /etc path, removed nothing at all, and produced an image that built green and still started logind at boot. build.sh now asserts the override is present rather than the /etc path absent, which is the check that would have caught it.

Two dead ends, both of which measure well and leave a machine whose logins have no session, because a console marker needs none: ordering sshd after logind repairs SSH and only SSH, and ordering the getty too hands the saving straight back; and RuntimeDirectory= on the socket creates nothing, since a unit with no Exec* line never applies its execution context.

task boot:logind is what holds the half of this that a boot time cannot show: the shipped image passes, and SPIN_LOGIND_NO_SEATS=1 removes the drop-in and fails at the console login before it ever reaches SSH.

Claude-Session: https://claude.ai/code/session_01CaRJvsQ773TwLQaY6tLZ9c

pam_systemd decides whether to register a session by calling logind_running(),
which is access("/run/systemd/seats/") — a test for "is this a system with
logind", not for "is logind up". On a false answer it logs "Skipping logind
registration as logind is not running" and returns PAM_SUCCESS: the login
authenticates and lands with no XDG_RUNTIME_DIR, no XDG_SESSION_ID and no user
manager, and nothing anywhere reports an error.

logind creates that directory itself, so the guard is false exactly while logind
has never run. Creating it on the Varlink socket, which carries
Service=systemd-logind.service, makes the guard tell the truth before logind
runs and turns pam_systemd's connection into what starts it. Every login path
activates it, not only SSH: the console getty and su go through the same module.

Worth 24ms: 249/287 against 273/297 with logind wanted by multi-user.target,
p50/p95 over 25 boots each, reproduced in two runs. The fork gives 4ms of that
back and buys the sessions; masking logind outright would be 7ms better again
and would leave every login without one.

The want is overridden with a /dev/null symlink and not removed, because it is
not in /etc to begin with: the package ships it in /usr. The first version of
this used `rm -f` on the /etc path, removed nothing at all, and produced an
image that built green and still started logind at boot. build.sh now asserts
the override is present rather than the /etc path absent, which is the check
that would have caught it.

Two dead ends, both of which measure well and leave a machine whose logins have
no session, because a console marker needs none: ordering sshd after logind
repairs SSH and only SSH, and ordering the getty too hands the saving straight
back; and RuntimeDirectory= on the socket creates nothing, since a unit with no
Exec* line never applies its execution context.

task boot:logind is what holds the half of this that a boot time cannot show:
the shipped image passes, and SPIN_LOGIND_NO_SEATS=1 removes the drop-in and
fails at the console login before it ever reaches SSH.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CaRJvsQ773TwLQaY6tLZ9c
@aledbf
aledbf merged commit bb6bb89 into main Sep 12, 2026
2 checks passed
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.

1 participant