Compare commits

...

2 Commits

Author SHA1 Message Date
Federico Giovanardi 32d4a94da2
Merge 9d58f3b81e into d99198819c 2024-11-22 04:33:17 +01:00
Federico Giovanardi 9d58f3b81e 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.
2024-11-21 09:00:51 +01:00
8 changed files with 96 additions and 20 deletions

View File

@ -577,6 +577,17 @@
<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>

View 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

View 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.]' \

View File

@ -1058,3 +1058,8 @@ global:
sd_device_monitor_get_timeout;
sd_device_monitor_receive;
} LIBSYSTEMD_256;
LIBSYSTEMD_258 {
global:
sd_device_enumerator_add_all_parents;
} LIBSYSTEMD_257;

View 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;
}

View File

@ -499,6 +499,41 @@ TEST(sd_device_enumerator_add_match_parent) {
}
}
TEST(sd_device_enumerator_add_all_parents) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
unsigned devices_count_with_parents = 0;
unsigned devices_count_without_parents = 0;
/* 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"));
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 int 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;

View 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 */

View 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;