From: Federico Giovanardi Date: Thu, 17 Oct 2024 13:29:51 +0000 (+0200) Subject: udev: add option to trigger parent devices despite filters X-Git-Tag: v258-rc1~1845 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7fd45eec37840036f6659fa15e73a9fd896d5613;p=thirdparty%2Fsystemd.git udev: add option to trigger parent devices despite filters 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. --- diff --git a/man/udevadm.xml b/man/udevadm.xml index eb77356d869..ca6fa0353a2 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -577,6 +577,17 @@ + + + + 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. + + + + diff --git a/shell-completion/bash/udevadm b/shell-completion/bash/udevadm index 3842d722e75..e5626c9301a 100644 --- a/shell-completion/bash/udevadm +++ b/shell-completion/bash/udevadm @@ -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 diff --git a/shell-completion/zsh/_udevadm b/shell-completion/zsh/_udevadm index 9ff87d83123..5f5761cbfa3 100644 --- a/shell-completion/zsh/_udevadm +++ b/shell-completion/zsh/_udevadm @@ -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.]' \ diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 35f55d0cddd..6fbe621c3dd 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -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; diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 00d33284717..ca7e70393b8 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -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; } diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c index 620615b6bb7..230493ed183 100644 --- a/src/libsystemd/sd-device/test-sd-device.c +++ b/src/libsystemd/sd-device/test-sd-device.c @@ -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; diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index 41e67199630..f627ae6daed 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -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 */ diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 13413a1f723..695f440b8f3 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -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;