]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udevadm: trigger: implement --initialized-match/nomatch arguments 22662/head
authorDanilo Krummrich <danilo.krummrich@bmw.de>
Mon, 14 Jun 2021 15:46:00 +0000 (17:46 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 22 Mar 2022 06:54:10 +0000 (15:54 +0900)
systemd-udev-trigger.service by default triggeres all devices regardless
of whether they were already recognized by systemd-udevd.

There are machines (especially in embedded environments) where
systemd-udev-trigger.service is configured to run at a later stage of
the boot sequence, which can lead to quite a lot of devices being
triggered although they were already recognized by systemd-udevd.

Re-triggering a lot of devices is a relatively expensive operation and
therefore should be avoided if unnecessary.

Therefore this patch introduces --initialized-nomatch, which filters out
devices that are already present in the udev database. For consistance
reasons --initialized-match is implemented as well, which filters out devices
that are *not* already present in the udev database.

Replaces #19949.

man/udevadm.xml
shell-completion/bash/udevadm
shell-completion/zsh/_udevadm
src/udev/udevadm-trigger.c

index 24ed4a29c71d06aa9434b9379ab473dff9a628d5..af485711222e21a9e9844f3f50123e7f5b605188 100644 (file)
             then each matching result is ORed, that is, all children of each specified device are triggered.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><option>--initialized-match</option></term>
+          <term><option>--initialized-nomatch</option></term>
+          <listitem>
+            <para>When <option>--initialized-match</option> is specified, trigger events for devices
+            that are already initialized by <command>systemd-udevd</command>, and skip devices that
+            are not initialized yet.</para>
+            <para>When <option>--initialized-nomatch</option> is specified, trigger events for devices
+            that are not initialized by <command>systemd-udevd</command> yet, and skip devices that
+            are already initialized.</para>
+            <para>Here, initialized devices are those for which at least one udev rule already
+            completed execution – for any action but <literal>remove</literal> — that set a property
+            or other device setting (and thus has an entry in the udev device database). Devices are
+            no longer considered initialized if a <literal>remove</literal> action is seen for them
+            (which removes their entry in the udev device database). Note that devices that have no
+            udev rules are never considered initialized, but might still be announced via the sd-device
+            API (or similar). Typically, it is thus essential that applications which intend to use
+            such a match, make sure a suitable udev rule is installed that sets at least one property
+            on devices that shall be matched.</para>
+            <para>WARNING: <option>--initialized-nomatch</option> can potentially save a significant
+            amount of time compared to re-triggering all devices in the system and e.g. can be used to
+            optimize boot time. However, this is not safe to be used in a boot sequence in general.
+            Especially, when udev rules for a device depend on its parent devices (e.g.
+            <literal>ATTRS</literal> or <literal>IMPORT{parent}</literal> keys, see
+            <citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+            for more details), the final state of the device becomes easily unstable with this option.
+            </para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><option>-w</option></term>
           <term><option>--settle</option></term>
index 4d52597cbfdf3cd6c8f45fc87d5844a1ba010eaf..23ce02365c7f0fe3bb782daa239219d963e2b6e4 100644 (file)
@@ -51,7 +51,8 @@ _udevadm() {
         [INFO_STANDALONE]='-r --root -a --attribute-walk -x --export -e --export-db -c --cleanup-db
                            -w --wait-for-initialization --value'
         [INFO_ARG]='-q --query -p --path -n --name -P --export-prefix -d --device-id-of-file --property'
-        [TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon --uuid'
+        [TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon --uuid
+                              --initialized-match --initialized-nomatch'
         [TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch
                        -a --attr-match -A --attr-nomatch -p --property-match
                        -g --tag-match -y --sysname-match --name-match -b --parent-match
index 8a10237e3d662fdeb21d65f67835aa56acedb3e3..63df8b7c9eccf9468d6cd73a80cfb304c0d6a5ba 100644 (file)
@@ -34,6 +34,8 @@ _udevadm_trigger(){
         '--tag-match=property[Trigger events for devices with a matching tag.]' \
         '--sysname-match=[Trigger events for devices with a matching sys device name.]' \
         '--parent-match=[Trigger events for all children of a given device.]' \
+        '--initialized-match[Trigger events for devices that are already initialized.]' \
+        '--initialized-nomatch[Trigger events for devices that are not initialized yet.]' \
         '--uuid[Print synthetic uevent UUID.]' \
         '--prioritized-subsystem=[Trigger events for devices which belong to a matching subsystem earlier.]'
 }
index e4b3150e6039a4febd7d75cfa1498779d3df8873..56921e2cc62ecfcdedc5fcd47b3faf8c6f3d70eb 100644 (file)
@@ -11,6 +11,7 @@
 #include "device-util.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "set.h"
@@ -226,6 +227,8 @@ static int help(void) {
                "  -y --sysname-match=NAME           Trigger devices with this /sys path\n"
                "     --name-match=NAME              Trigger devices with this /dev name\n"
                "  -b --parent-match=NAME            Trigger devices with that parent device\n"
+               "     --initialized-match            Trigger devices that are already initialized\n"
+               "     --initialized-nomatch          Trigger devices that are not initialized yet\n"
                "  -w --settle                       Wait for the triggered events to complete\n"
                "     --wait-daemon[=SECONDS]        Wait for udevd daemon to be initialized\n"
                "                                    before triggering uevents\n"
@@ -243,6 +246,8 @@ int trigger_main(int argc, char *argv[], void *userdata) {
                 ARG_PING,
                 ARG_UUID,
                 ARG_PRIORITIZED_SUBSYSTEM,
+                ARG_INITIALIZED_MATCH,
+                ARG_INITIALIZED_NOMATCH,
         };
 
         static const struct option options[] = {
@@ -260,6 +265,8 @@ int trigger_main(int argc, char *argv[], void *userdata) {
                 { "sysname-match",         required_argument, NULL, 'y'                       },
                 { "name-match",            required_argument, NULL, ARG_NAME                  },
                 { "parent-match",          required_argument, NULL, 'b'                       },
+                { "initialized-match",     no_argument,       NULL, ARG_INITIALIZED_MATCH     },
+                { "initialized-nomatch",   no_argument,       NULL, ARG_INITIALIZED_NOMATCH   },
                 { "settle",                no_argument,       NULL, 'w'                       },
                 { "wait-daemon",           optional_argument, NULL, ARG_PING                  },
                 { "version",               no_argument,       NULL, 'V'                       },
@@ -426,6 +433,12 @@ int trigger_main(int argc, char *argv[], void *userdata) {
                         }
                         break;
                 }
+                case ARG_INITIALIZED_MATCH:
+                case ARG_INITIALIZED_NOMATCH:
+                        r = device_enumerator_add_match_is_initialized(e, c == ARG_INITIALIZED_MATCH ? MATCH_INITIALIZED_YES : MATCH_INITIALIZED_NO);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to set initialized filter: %m");
+                        break;
                 case 'V':
                         return print_version();
                 case 'h':