]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev: add option to trigger parent devices despite filters
authorFederico Giovanardi <federico.giovanardi@cnhind.com>
Thu, 17 Oct 2024 13:29:51 +0000 (15:29 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 16 Dec 2024 14:43:52 +0000 (15:43 +0100)
This commit add the `-i` option to `udevadm trigger` that force it to
match parent devices even if they're excluded from filters.
The rationale is that some embedded devices have a huge number of
platform devices ( ~ 4k for MX8 ) they are there because they're defined
in the device tree but there isn't any action or udev rules associated
with them.

So at boot a significant time is spend triggering and processing rules
for devices that don't produce any effect and we would like to filter
them by calling:

```
udevadm trigger --type=device --action=add -s block -s tty
```

instead of the normal

```
udevadm trigger --type=device --action=add
```

so we can use filter to filter out only subsystems for we we know that
we have rules in place that do something useful.

On the other side action / rules are not triggered until the parent is
triggered ( which is part of another subsystem), so the additional option
will allows udev to complete the coldplug with only the devices we care.

Example on iMX8:

.Without the new option
```
root@dev:~# udevadm trigger --dry-run  -s block --action=add -v
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0boot0
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0boot1
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p1
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p2
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p3
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p4
```

.With the new option
```
root@dev:~# udevadm trigger --dry-run -i -s block --action=add -v
/sys/devices/platform
/sys/devices/platform/bus@5b000000
/sys/devices/platform/bus@5b000000/5b010000.mmc
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0boot0
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0boot1
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p1
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p2
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p3
/sys/devices/platform/bus@5b000000/5b010000.mmc/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p4
```
Boot time reduction with this is place is ~ 1 second.

man/udevadm.xml
shell-completion/bash/udevadm
shell-completion/zsh/_udevadm
src/libsystemd/libsystemd.sym
src/libsystemd/sd-device/device-enumerator.c
src/libsystemd/sd-device/test-sd-device.c
src/systemd/sd-device.h
src/udev/udevadm-trigger.c

index eb77356d86918afa50a789d3fea074924b45f923..ca6fa0353a2b75ab20a3d6b9e73b1b293751f6e4 100644 (file)
             <xi:include href="version-info.xml" xpointer="v251"/>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><option>--include-parents</option></term>
+          <listitem>
+            <para>Trigger parent devices of found devices even if the parents
+            won't match the filter condition.
+            This is useful if we are interested to limit the coldplug activities to
+            some devices or subsystems.</para>
+
+            <xi:include href="version-info.xml" xpointer="v258"/>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><option>-w</option></term>
           <term><option>--settle</option></term>
index 3842d722e753a8b7f64b3519ddb6d499caade8e2..e5626c9301ac2f0b1dbdbb040a224194a802db32 100644 (file)
@@ -58,7 +58,7 @@ _udevadm() {
                     --json --subsystem-match --subsystem-nomatch --attr-match --attr-nomatch --property-match
                     --tag-match --sysname-match --name-match --parent-match'
         [TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon --uuid
-                              --initialized-match --initialized-nomatch'
+                              --initialized-match --initialized-nomatch --include-parents'
         [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 9ff87d83123bb5729543c9fe8d68bbaae45cfff2..5f5761cbfa3d5debb0869dcaaa78b66f022fa0af 100644 (file)
@@ -38,6 +38,7 @@ _udevadm_trigger(){
         '--tag-match=[Trigger events for devices with a matching tag.]:TAG' \
         '--sysname-match=[Trigger events for devices with a matching sys device name.]:NAME' \
         '--parent-match=[Trigger events for all children of a given device.]:NAME' \
+        '--include-parents[Also trigger parent devices of found devices.]' \
         '--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.]' \
index 35f55d0cddd498a7bad8b94c585e678b9d968164..6fbe621c3ddf8ffe35245c3b348b158645b246a6 100644 (file)
@@ -1065,4 +1065,5 @@ global:
         sd_json_variant_type_from_string;
         sd_json_variant_type_to_string;
         sd_varlink_reset_fds;
+        sd_device_enumerator_add_all_parents;
 } LIBSYSTEMD_257;
index 00d33284717962648c92f38ebb5e58e73c39c9bf..ca7e70393b879ed14afa56af955cbf2e2ed52f81 100644 (file)
@@ -24,6 +24,17 @@ typedef enum DeviceEnumerationType {
         _DEVICE_ENUMERATION_TYPE_INVALID = -EINVAL,
 } DeviceEnumerationType;
 
+typedef enum MatchFlag {
+        MATCH_NONE        = 0,
+        MATCH_BASIC       = 1u << 0,
+        MATCH_SYSNAME     = 1u << 1,
+        MATCH_SUBSYSTEM   = 1u << 2,
+        MATCH_PARENT      = 1u << 3,
+        MATCH_TAG         = 1u << 4,
+
+        MATCH_ALL         = (1u << 5) - 1,
+} MatchFlag;
+
 struct sd_device_enumerator {
         unsigned n_ref;
 
@@ -46,6 +57,7 @@ struct sd_device_enumerator {
         Set *match_tag;
         Set *match_parent;
         MatchInitializedType match_initialized;
+        MatchFlag parent_match_flags;
 };
 
 _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
@@ -61,6 +73,7 @@ _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
                 .n_ref = 1,
                 .type = _DEVICE_ENUMERATION_TYPE_INVALID,
                 .match_initialized = MATCH_INITIALIZED_COMPAT,
+                .parent_match_flags = MATCH_ALL,
         };
 
         *ret = TAKE_PTR(enumerator);
@@ -273,6 +286,15 @@ _public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enum
 
         return 1;
 }
+_public_ int sd_device_enumerator_add_all_parents(sd_device_enumerator *enumerator) {
+        assert_return(enumerator, -EINVAL);
+
+        enumerator->parent_match_flags = MATCH_NONE;
+
+        enumerator->scan_uptodate = false;
+
+        return 1;
+}
 
 int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator, MatchInitializedType type) {
         assert_return(enumerator, -EINVAL);
@@ -567,15 +589,6 @@ static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsys
         return set_fnmatch(enumerator->match_subsystem, enumerator->nomatch_subsystem, subsystem);
 }
 
-typedef enum MatchFlag {
-        MATCH_SYSNAME     = 1u << 0,
-        MATCH_SUBSYSTEM   = 1u << 1,
-        MATCH_PARENT      = 1u << 2,
-        MATCH_TAG         = 1u << 3,
-
-        MATCH_ALL         = (1u << 4) - 1,
-} MatchFlag;
-
 static int test_matches(
                 sd_device_enumerator *enumerator,
                 sd_device *device,
@@ -618,18 +631,20 @@ static int test_matches(
             !match_tag(enumerator, device))
                 return false;
 
-        r = match_initialized(enumerator, device);
-        if (r <= 0)
-                return r;
+        if (FLAGS_SET(flags, MATCH_BASIC)) {
+                r = match_initialized(enumerator, device);
+                if (r <= 0)
+                        return r;
 
-        if (!match_property(enumerator->match_property, device, /* match_all = */ false))
-                return false;
+                if (!match_property(enumerator->match_property, device, /* match_all = */ false))
+                        return false;
 
-        if (!match_property(enumerator->match_property_required, device, /* match_all = */ true))
-                return false;
+                if (!match_property(enumerator->match_property_required, device, /* match_all = */ true))
+                        return false;
 
-        if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
-                return false;
+                if (!device_match_sysattr(device, enumerator->match_sysattr, enumerator->nomatch_sysattr))
+                        return false;
+        }
 
         return true;
 }
@@ -743,7 +758,7 @@ static int enumerator_scan_dir_and_add_devices(
                 /* Also include all potentially matching parent devices in the enumeration. These are things
                  * like root busses — e.g. /sys/devices/pci0000:00/ or /sys/devices/pnp0/, which ar not
                  * linked from /sys/class/ or /sys/bus/, hence pick them up explicitly here. */
-                k = enumerator_add_parent_devices(enumerator, device, MATCH_ALL);
+                k = enumerator_add_parent_devices(enumerator, device, enumerator->parent_match_flags);
                 if (k < 0)
                         r = k;
         }
index 620615b6bb79a9100d26469bf226cbe778687857..230493ed183ce7c96bcafd7deea7ef26cc5b990c 100644 (file)
@@ -499,6 +499,43 @@ TEST(sd_device_enumerator_add_match_parent) {
         }
 }
 
+TEST(sd_device_enumerator_add_all_parents) {
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+
+        /* STEP 1: enumerate all block devices without all_parents() */
+        ASSERT_OK(sd_device_enumerator_new(&e));
+        ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
+
+        /* filter in only a subsystem */
+        ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
+        ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
+        ASSERT_OK(sd_device_enumerator_add_match_property(e, "DEVTYPE", "partition"));
+
+        unsigned devices_count_with_parents = 0;
+        unsigned devices_count_without_parents = 0;
+        FOREACH_DEVICE(e, dev) {
+                ASSERT_TRUE(device_in_subsystem(dev, "block"));
+                ASSERT_TRUE(device_is_devtype(dev, "partition"));
+                devices_count_without_parents++;
+        }
+
+        log_debug("found %u devices", devices_count_without_parents);
+
+        /* STEP 2: enumerate again with all_parents() */
+        ASSERT_OK(sd_device_enumerator_add_all_parents(e) >= 0);
+
+        unsigned not_filtered_parent_count = 0;
+        FOREACH_DEVICE(e, dev) {
+                if (!device_in_subsystem(dev, "block") || !device_is_devtype(dev, "partition"))
+                        not_filtered_parent_count++;
+                devices_count_with_parents++;
+        }
+        log_debug("found %u devices out of %u that would have been excluded without all_parents()",
+                  not_filtered_parent_count,
+                  devices_count_with_parents);
+        ASSERT_EQ(devices_count_with_parents, devices_count_without_parents + not_filtered_parent_count);
+}
+
 TEST(sd_device_get_child) {
         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
         int r;
index 41e671996306e5006ed4b9a4cb3e1e523bd737ca..f627ae6daed412c8ff58743e2ac315571daafde1 100644 (file)
@@ -137,6 +137,7 @@ int sd_device_enumerator_add_nomatch_sysname(sd_device_enumerator *enumerator, c
 int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag);
 int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent);
 int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator);
+int sd_device_enumerator_add_all_parents(sd_device_enumerator *enumerator);
 
 /* device monitor */
 
index 13413a1f723a2bdf1f029f36fdd7402825298634..695f440b8f3267e59ca8f836cbac5a5f0c901608 100644 (file)
@@ -266,6 +266,7 @@ 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"
+               "     --include-parents              Trigger parent devices of found devices\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"
@@ -287,6 +288,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
                 ARG_PRIORITIZED_SUBSYSTEM,
                 ARG_INITIALIZED_MATCH,
                 ARG_INITIALIZED_NOMATCH,
+                ARG_INCLUDE_PARENTS,
         };
 
         static const struct option options[] = {
@@ -304,6 +306,7 @@ 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'                       },
+                { "include-parents",       no_argument,       NULL, ARG_INCLUDE_PARENTS       },
                 { "initialized-match",     no_argument,       NULL, ARG_INITIALIZED_MATCH     },
                 { "initialized-nomatch",   no_argument,       NULL, ARG_INITIALIZED_NOMATCH   },
                 { "settle",                no_argument,       NULL, 'w'                       },
@@ -428,6 +431,11 @@ int trigger_main(int argc, char *argv[], void *userdata) {
                                 return log_error_errno(r, "Failed to add parent match '%s': %m", optarg);
                         break;
                 }
+                case ARG_INCLUDE_PARENTS:
+                        r = sd_device_enumerator_add_all_parents(e);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to always include all parents: %m");
+                        break;
                 case 'w':
                         arg_settle = true;
                         break;