Skip to content

Commit

Permalink
man: sd_notify() race is gone with sd_notify_barrier
Browse files Browse the repository at this point in the history
Add note for change of behaviour in systemd-notify, where parent pid trick
is only used when --no-block is passed, and with enough privileges ofcourse.

Also, fix a small error in systemd(1).
  • Loading branch information
kkdwivedi committed Apr 28, 2020
1 parent c872224 commit c047b75
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 12 deletions.
32 changes: 22 additions & 10 deletions man/systemd-notify.xml
Expand Up @@ -48,21 +48,24 @@
<para>Note that systemd will refuse reception of status updates from this command unless
<varname>NotifyAccess=</varname> is set for the service unit this command is called from.</para>

<para>Note that <function>sd_notify()</function> notifications may be attributed to units correctly only if either
<para>If <option>--no-block</option> is used, <command>systemd-notify</command> will first attempt to invoke
<function>sd_notify()</function> pretending to have the PID of the invoking process. This will only succeed
when invoked with sufficient privileges. On failure, it will then fall back to invoking it under its own PID.
This behaviour is useful in order that when the tool is invoked from a shell script the shell process — and
not the <command>systemd-notify</command> process — appears as sender of the message, which in turn is helpful
if the shell process is the main process of a service, due to the limitations of <varname>NotifyAccess=</varname>
<option>all</option> when <option>--no-block</option> is used.</para>

<para>Specifically, <function>sd_notify()</function> notifications may be attributed to units correctly only if either
the sending process is still around at the time PID 1 processes the message, or if the sending process is
explicitly runtime-tracked by the service manager. The latter is the case if the service manager originally forked
off the process, i.e. on all processes that match <varname>NotifyAccess=</varname><option>main</option> or
<varname>NotifyAccess=</varname><option>exec</option>. Conversely, if an auxiliary process of the unit sends an
<function>sd_notify()</function> message and immediately exits, the service manager might not be able to properly
attribute the message to the unit, and thus will ignore it, even if
<varname>NotifyAccess=</varname><option>all</option> is set for it.</para>

<para><command>systemd-notify</command> will first attempt to invoke <function>sd_notify()</function> pretending to
have the PID of the invoking process. This will only succeed when invoked with sufficient privileges. On failure,
it will then fall back to invoking it under its own PID. This behaviour is useful in order that when the tool is
invoked from a shell script the shell process — and not the <command>systemd-notify</command> process — appears as
sender of the message, which in turn is helpful if the shell process is the main process of a service, due to the
limitations of <varname>NotifyAccess=</varname><option>all</option> described above.</para>
attribute the message to the unit, and thus will ignore it, even if <varname>NotifyAccess=</varname><option>all
</option> is set for it. When <option>--no-block</option> is used, all synchronization for reception of notifications
is disabled, and hence the aforementioned race may occur.</para>

</refsect1>

<refsect1>
Expand Down Expand Up @@ -128,6 +131,15 @@
with systemd. </para></listitem>
</varlistentry>

<varlistentry>
<term><option>--no-block</option></term>

<listitem><para>Do not synchronously wait for the requested operation
to finish. Use of this option is only recommended when systemd-notify
is spawned directly by the service manager, because sending notifications
with this option set is prone to race conditions.</para></listitem>
</varlistentry>

<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
Expand Down
9 changes: 8 additions & 1 deletion man/systemd.service.xml
Expand Up @@ -959,7 +959,14 @@
<option>exec</option>. Conversely, if an auxiliary process of the unit sends an
<function>sd_notify()</function> message and immediately exits, the service manager might not be able to
properly attribute the message to the unit, and thus will ignore it, even if
<varname>NotifyAccess=</varname><option>all</option> is set for it.</para></listitem>
<varname>NotifyAccess=</varname><option>all</option> is set for it.</para>

<para>Hence, to eliminate all race conditions involving lookup of the client's unit and attribution of notifications
to units correctly, <function>sd_notify_barrier()</function> may be used. This call acts as a synchronization point
and ensures all notifications sent before this call have been picked up by the service manager when it returns
successfully. Use of <function>sd_notify_barrier()</function> is needed for clients which are not invoked by the
service manager, otherwise this synchronization mechanism is unnecessary for attribution of notifications to the
unit.</para></listitem>
</varlistentry>

<varlistentry>
Expand Down
2 changes: 1 addition & 1 deletion man/systemd.xml
Expand Up @@ -257,7 +257,7 @@
execution compared to the target unit's state and is marked successful and
complete when both satisfy. However, this job also pulls in other
dependencies due to the defined relationships and thus leads to, in our
our example, start jobs for any of those inactive units getting queued as
example, start jobs for any of those inactive units getting queued as
well.</para>

<para>systemd contains native implementations of various tasks
Expand Down

0 comments on commit c047b75

Please sign in to comment.