From 9e871965a02a18cca080edf0fc2cf629d7569e06 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 10 Mar 2022 19:08:04 +0900 Subject: [PATCH 01/11] sd-device-enumerator: introduce sound_device_compare() and devpath_is_late_block() helper functions --- src/libsystemd/sd-device/device-enumerator.c | 80 ++++++++++++-------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 4942ee43a8..3f61ed8f88 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -223,49 +223,63 @@ int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator) return 1; } -static int device_compare(sd_device * const *_a, sd_device * const *_b) { - sd_device *a = *(sd_device **)_a, *b = *(sd_device **)_b; - const char *devpath_a, *devpath_b, *sound_a; - bool delay_a, delay_b; - int r; +static int sound_device_compare(const char *devpath_a, const char *devpath_b) { + const char *sound_a, *sound_b; + size_t prefix_len; - assert_se(sd_device_get_devpath(a, &devpath_a) >= 0); - assert_se(sd_device_get_devpath(b, &devpath_b) >= 0); + assert(devpath_a); + assert(devpath_b); + + /* For sound cards the control device must be enumerated last to make sure it's the final + * device node that gets ACLs applied. Applications rely on this fact and use ACL changes on + * the control node as an indicator that the ACL change of the entire sound card completed. The + * kernel makes this guarantee when creating those devices, and hence we should too when + * enumerating them. */ sound_a = strstr(devpath_a, "/sound/card"); - if (sound_a) { - /* For sound cards the control device must be enumerated last to - * make sure it's the final device node that gets ACLs applied. - * Applications rely on this fact and use ACL changes on the - * control node as an indicator that the ACL change of the - * entire sound card completed. The kernel makes this guarantee - * when creating those devices, and hence we should too when - * enumerating them. */ - sound_a += STRLEN("/sound/card"); - sound_a = strchr(sound_a, '/'); + if (!sound_a) + return 0; - if (sound_a) { - unsigned prefix_len; + sound_a += STRLEN("/sound/card"); + sound_a = strchr(devpath_a, '/'); + if (!sound_a) + return 0; - prefix_len = sound_a - devpath_a; + prefix_len = sound_a - devpath_a; - if (strneq(devpath_a, devpath_b, prefix_len)) { - const char *sound_b; + if (!strneq(devpath_a, devpath_b, prefix_len)) + return 0; - sound_b = devpath_b + prefix_len; + sound_b = devpath_b + prefix_len; - r = CMP(!!startswith(sound_a, "/controlC"), - !!startswith(sound_b, "/controlC")); - if (r != 0) - return r; - } - } - } + return CMP(!!startswith(sound_a, "/controlC"), + !!startswith(sound_b, "/controlC")); +} + +static bool devpath_is_late_block(const char *devpath) { + assert(devpath); + + return strstr(devpath, "/block/md") || strstr(devpath, "/block/dm-"); +} + +static int device_compare(sd_device * const *a, sd_device * const *b) { + const char *devpath_a, *devpath_b; + int r; + + assert(a); + assert(b); + assert(*a); + assert(*b); + + assert_se(sd_device_get_devpath(*(sd_device**) a, &devpath_a) >= 0); + assert_se(sd_device_get_devpath(*(sd_device**) b, &devpath_b) >= 0); + + r = sound_device_compare(devpath_a, devpath_b); + if (r != 0) + return r; /* md and dm devices are enumerated after all other devices */ - delay_a = strstr(devpath_a, "/block/md") || strstr(devpath_a, "/block/dm-"); - delay_b = strstr(devpath_b, "/block/md") || strstr(devpath_b, "/block/dm-"); - r = CMP(delay_a, delay_b); + r = CMP(devpath_is_late_block(devpath_a), devpath_is_late_block(devpath_b)); if (r != 0) return r; From deac0c9c044302d22549e1aabbf6f730c3161c97 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 4 Mar 2022 21:09:26 +0900 Subject: [PATCH 02/11] sd-device-enumerator: introduce device_enumerator_unref_devices() helper function --- src/libsystemd/sd-device/device-enumerator.c | 27 ++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 3f61ed8f88..c69da5947c 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -62,11 +62,24 @@ _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) { return 0; } +static void device_unref_many(sd_device **devices, size_t n) { + assert(devices || n == 0); + + for (size_t i = 0; i < n; i++) + sd_device_unref(devices[i]); +} + +static void device_enumerator_unref_devices(sd_device_enumerator *enumerator) { + assert(enumerator); + + device_unref_many(enumerator->devices, enumerator->n_devices); + enumerator->n_devices = 0; +} + static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumerator) { assert(enumerator); - for (size_t i = 0; i < enumerator->n_devices; i++) - sd_device_unref(enumerator->devices[i]); + device_enumerator_unref_devices(enumerator); free(enumerator->devices); set_free(enumerator->match_subsystem); @@ -744,10 +757,7 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumerator) { enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES) return 0; - for (size_t i = 0; i < enumerator->n_devices; i++) - sd_device_unref(enumerator->devices[i]); - - enumerator->n_devices = 0; + device_enumerator_unref_devices(enumerator); if (!set_isempty(enumerator->match_tag)) { k = enumerator_scan_devices_tags(enumerator); @@ -810,10 +820,7 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) { enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS) return 0; - for (size_t i = 0; i < enumerator->n_devices; i++) - sd_device_unref(enumerator->devices[i]); - - enumerator->n_devices = 0; + device_enumerator_unref_devices(enumerator); /* modules */ if (match_subsystem(enumerator, "module")) { From 87c3a0f9f87b02166bfe1e25c859c3a28892822b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 4 Mar 2022 22:40:49 +0900 Subject: [PATCH 03/11] sd-device-enumerator: introduce device_enumerator_sort_devices() and devices are sorted when the iteration started. Previously, devices added by udev_enumerate_add_syspath() -> device_enumerator_add_device() are not sorted. This fixes the issue. --- src/libsystemd/sd-device/device-enumerator.c | 111 +++++++++++-------- 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index c69da5947c..e35ae638d9 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -28,9 +28,11 @@ struct sd_device_enumerator { unsigned n_ref; DeviceEnumerationType type; + Hashmap *devices_by_syspath; sd_device **devices; size_t n_devices, current_device_index; bool scan_uptodate; + bool sorted; Set *match_subsystem; Set *nomatch_subsystem; @@ -72,7 +74,9 @@ static void device_unref_many(sd_device **devices, size_t n) { static void device_enumerator_unref_devices(sd_device_enumerator *enumerator) { assert(enumerator); + hashmap_clear_with_destructor(enumerator->devices_by_syspath, sd_device_unref); device_unref_many(enumerator->devices, enumerator->n_devices); + enumerator->devices = mfree(enumerator->devices); enumerator->n_devices = 0; } @@ -81,7 +85,7 @@ static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumer device_enumerator_unref_devices(enumerator); - free(enumerator->devices); + hashmap_free(enumerator->devices_by_syspath); set_free(enumerator->match_subsystem); set_free(enumerator->nomatch_subsystem); hashmap_free(enumerator->match_sysattr); @@ -299,16 +303,55 @@ static int device_compare(sd_device * const *a, sd_device * const *b) { return strcmp(devpath_a, devpath_b); } +static int enumerator_sort_devices(sd_device_enumerator *enumerator) { + sd_device **devices; + sd_device *device; + size_t n = 0; + + assert(enumerator); + + if (enumerator->sorted) + return 0; + + devices = new(sd_device*, hashmap_size(enumerator->devices_by_syspath)); + if (!devices) + return -ENOMEM; + + HASHMAP_FOREACH(device, enumerator->devices_by_syspath) + devices[n++] = sd_device_ref(device); + + typesafe_qsort(devices, n, device_compare); + + device_unref_many(enumerator->devices, enumerator->n_devices); + + enumerator->n_devices = n; + free_and_replace(enumerator->devices, devices); + + enumerator->sorted = true; + return 0; +} + int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) { + const char *syspath; + int r; + assert_return(enumerator, -EINVAL); assert_return(device, -EINVAL); - if (!GREEDY_REALLOC(enumerator->devices, enumerator->n_devices + 1)) - return -ENOMEM; + r = sd_device_get_syspath(device, &syspath); + if (r < 0) + return r; - enumerator->devices[enumerator->n_devices++] = sd_device_ref(device); + r = hashmap_ensure_put(&enumerator->devices_by_syspath, &string_hash_ops, syspath, device); + if (IN_SET(r, -EEXIST, 0)) + return 0; + if (r < 0) + return r; - return 0; + sd_device_ref(device); + + enumerator->sorted = false; + return 1; } static bool match_property(sd_device_enumerator *enumerator, sd_device *device) { @@ -721,33 +764,6 @@ static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) { return r; } -static void device_enumerator_dedup_devices(sd_device_enumerator *enumerator) { - sd_device **a, **b, **end; - - assert(enumerator); - - if (enumerator->n_devices <= 1) - return; - - a = enumerator->devices + 1; - b = enumerator->devices; - end = enumerator->devices + enumerator->n_devices; - - for (; a < end; a++) { - const char *devpath_a, *devpath_b; - - assert_se(sd_device_get_devpath(*a, &devpath_a) >= 0); - assert_se(sd_device_get_devpath(*b, &devpath_b) >= 0); - - if (path_equal(devpath_a, devpath_b)) - sd_device_unref(*a); - else - *(++b) = *a; - } - - enumerator->n_devices = b - enumerator->devices + 1; -} - int device_enumerator_scan_devices(sd_device_enumerator *enumerator) { int r = 0, k; @@ -773,9 +789,6 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumerator) { r = k; } - typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare); - device_enumerator_dedup_devices(enumerator); - enumerator->scan_uptodate = true; enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES; @@ -783,12 +796,12 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumerator) { } _public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) { - int r; - assert_return(enumerator, NULL); - r = device_enumerator_scan_devices(enumerator); - if (r < 0) + if (device_enumerator_scan_devices(enumerator) < 0) + return NULL; + + if (enumerator_sort_devices(enumerator) < 0) return NULL; enumerator->current_device_index = 0; @@ -803,6 +816,7 @@ _public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *e assert_return(enumerator, NULL); if (!enumerator->scan_uptodate || + !enumerator->sorted || enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES || enumerator->current_device_index + 1 >= enumerator->n_devices) return NULL; @@ -848,9 +862,6 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) { r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m"); } - typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare); - device_enumerator_dedup_devices(enumerator); - enumerator->scan_uptodate = true; enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS; @@ -858,12 +869,12 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) { } _public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) { - int r; - assert_return(enumerator, NULL); - r = device_enumerator_scan_subsystems(enumerator); - if (r < 0) + if (device_enumerator_scan_subsystems(enumerator) < 0) + return NULL; + + if (enumerator_sort_devices(enumerator) < 0) return NULL; enumerator->current_device_index = 0; @@ -878,6 +889,7 @@ _public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator assert_return(enumerator, NULL); if (!enumerator->scan_uptodate || + !enumerator->sorted || enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS || enumerator->current_device_index + 1 >= enumerator->n_devices) return NULL; @@ -891,6 +903,9 @@ sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) { if (!enumerator->scan_uptodate) return NULL; + if (enumerator_sort_devices(enumerator) < 0) + return NULL; + enumerator->current_device_index = 0; if (enumerator->n_devices == 0) @@ -903,6 +918,7 @@ sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) { assert_return(enumerator, NULL); if (!enumerator->scan_uptodate || + !enumerator->sorted || enumerator->current_device_index + 1 >= enumerator->n_devices) return NULL; @@ -916,6 +932,9 @@ sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size if (!enumerator->scan_uptodate) return NULL; + if (enumerator_sort_devices(enumerator) < 0) + return NULL; + *ret_n_devices = enumerator->n_devices; return enumerator->devices; } From 95a6f969fc760d850e9803f329e39d1d242ff197 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 8 Mar 2022 01:20:42 +0900 Subject: [PATCH 04/11] sd-device-enumerator: introduce device_enumerator_add_prioritized_subsystem() If a subsystem is specified, then matching devices and their parents are listed at first. --- .../sd-device/device-enumerator-private.h | 1 + src/libsystemd/sd-device/device-enumerator.c | 102 +++++++++++++++++- 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/src/libsystemd/sd-device/device-enumerator-private.h b/src/libsystemd/sd-device/device-enumerator-private.h index 9c6437dbed..92334a9e69 100644 --- a/src/libsystemd/sd-device/device-enumerator-private.h +++ b/src/libsystemd/sd-device/device-enumerator-private.h @@ -8,6 +8,7 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumeartor); int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device); int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator); int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent); +int device_enumerator_add_prioritized_subsystem(sd_device_enumerator *enumerator, const char *subsystem); sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator); sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator); sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices); diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index e35ae638d9..3878bdde70 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -34,6 +34,7 @@ struct sd_device_enumerator { bool scan_uptodate; bool sorted; + char **prioritized_subsystems; Set *match_subsystem; Set *nomatch_subsystem; Hashmap *match_sysattr; @@ -86,6 +87,7 @@ static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumer device_enumerator_unref_devices(enumerator); hashmap_free(enumerator->devices_by_syspath); + strv_free(enumerator->prioritized_subsystems); set_free(enumerator->match_subsystem); set_free(enumerator->nomatch_subsystem); hashmap_free(enumerator->match_sysattr); @@ -100,6 +102,24 @@ static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumer DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device_enumerator, sd_device_enumerator, device_enumerator_free); +int device_enumerator_add_prioritized_subsystem(sd_device_enumerator *enumerator, const char *subsystem) { + int r; + + assert(enumerator); + assert(subsystem); + + if (strv_contains(enumerator->prioritized_subsystems, subsystem)) + return 0; + + r = strv_extend(&enumerator->prioritized_subsystems, subsystem); + if (r < 0) + return r; + + enumerator->scan_uptodate = false; + + return 1; +} + _public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match) { Set **set; int r; @@ -304,9 +324,10 @@ static int device_compare(sd_device * const *a, sd_device * const *b) { } static int enumerator_sort_devices(sd_device_enumerator *enumerator) { + size_t n_sorted = 0, n = 0; sd_device **devices; sd_device *device; - size_t n = 0; + int r; assert(enumerator); @@ -317,10 +338,82 @@ static int enumerator_sort_devices(sd_device_enumerator *enumerator) { if (!devices) return -ENOMEM; + STRV_FOREACH(prioritized_subsystem, enumerator->prioritized_subsystems) { + + for (;;) { + const char *syspath; + size_t m = n; + + HASHMAP_FOREACH_KEY(device, syspath, enumerator->devices_by_syspath) { + _cleanup_free_ char *p = NULL; + const char *subsys; + + if (sd_device_get_subsystem(device, &subsys) < 0) + continue; + + if (!streq(subsys, *prioritized_subsystem)) + continue; + + devices[n++] = sd_device_ref(device); + + for (;;) { + _cleanup_free_ char *q = NULL; + + r = path_extract_directory(p ?: syspath, &q); + if (r == -EADDRNOTAVAIL) + break; + if (r < 0) + goto failed; + + device = hashmap_get(enumerator->devices_by_syspath, q); + if (device) + devices[n++] = sd_device_ref(device); + + free_and_replace(p, q); + } + + break; + } + + /* We cannot remove multiple entries in the loop HASHMAP_FOREACH_KEY() above. */ + for (size_t i = m; i < n; i++) { + r = sd_device_get_syspath(devices[i], &syspath); + if (r < 0) + goto failed; + + assert_se(hashmap_remove(enumerator->devices_by_syspath, syspath) == devices[i]); + sd_device_unref(devices[i]); + } + + if (m == n) + break; + } + + typesafe_qsort(devices + n_sorted, n - n_sorted, device_compare); + n_sorted = n; + } + HASHMAP_FOREACH(device, enumerator->devices_by_syspath) devices[n++] = sd_device_ref(device); - typesafe_qsort(devices, n, device_compare); + /* Move all devices back to the hashmap. Otherwise, devices added by + * udev_enumerate_add_syspath() -> device_enumerator_add_device() may not be listed. */ + for (size_t i = 0; i < n_sorted; i++) { + const char *syspath; + + r = sd_device_get_syspath(devices[i], &syspath); + if (r < 0) + goto failed; + + r = hashmap_put(enumerator->devices_by_syspath, syspath, devices[i]); + if (r < 0) + goto failed; + assert(r > 0); + + sd_device_ref(devices[i]); + } + + typesafe_qsort(devices + n_sorted, n - n_sorted, device_compare); device_unref_many(enumerator->devices, enumerator->n_devices); @@ -329,6 +422,11 @@ static int enumerator_sort_devices(sd_device_enumerator *enumerator) { enumerator->sorted = true; return 0; + +failed: + device_unref_many(devices, n); + free(devices); + return r; } int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) { From 37cf83d9bfdd9f6859b6f2654d8ec3bbb17873b2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 19 Mar 2022 09:35:32 +0900 Subject: [PATCH 05/11] sd-device-enumerator: drop /sys/subsystem support This addresses the comment by Lennart https://github.com/systemd/systemd/pull/22662#discussion_r829799863: > /sys/subsystem is preparation for a future that never came. > And given that the main proponent of this left Linux kernel > development (Kay), I doubt this will ever come. So maybe we > should start dropping references to /sys/subsystem/ given it's > unlikely to materialize anytime soon. --- src/libsystemd/sd-device/device-enumerator.c | 33 ++++++-------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 3878bdde70..668a92ca0c 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -838,26 +838,17 @@ static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) { } static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) { - int r = 0; + int k, r = 0; log_debug("sd-device-enumerator: Scan all dirs"); - if (access("/sys/subsystem", F_OK) >= 0) { - /* we have /subsystem/, forget all the old stuff */ - r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL); - if (r < 0) - return log_debug_errno(r, "sd-device-enumerator: Failed to scan /sys/subsystem: %m"); - } else { - int k; + k = enumerator_scan_dir(enumerator, "bus", "devices", NULL); + if (k < 0) + r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m"); - k = enumerator_scan_dir(enumerator, "bus", "devices", NULL); - if (k < 0) - r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m"); - - k = enumerator_scan_dir(enumerator, "class", NULL, NULL); - if (k < 0) - r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m"); - } + k = enumerator_scan_dir(enumerator, "class", NULL, NULL); + if (k < 0) + r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m"); return r; } @@ -923,7 +914,6 @@ _public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *e } int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) { - const char *subsysdir; int r = 0, k; assert(enumerator); @@ -941,21 +931,16 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) { r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m"); } - if (access("/sys/subsystem", F_OK) >= 0) - subsysdir = "subsystem"; - else - subsysdir = "bus"; - /* subsystems (only buses support coldplug) */ if (match_subsystem(enumerator, "subsystem")) { - k = enumerator_scan_dir_and_add_devices(enumerator, subsysdir, NULL, NULL); + k = enumerator_scan_dir_and_add_devices(enumerator, "bus", NULL, NULL); if (k < 0) r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m"); } /* subsystem drivers */ if (match_subsystem(enumerator, "drivers")) { - k = enumerator_scan_dir(enumerator, subsysdir, "drivers", "drivers"); + k = enumerator_scan_dir(enumerator, "bus", "drivers", "drivers"); if (k < 0) r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m"); } From 3c5cc23a93d0fc89bc2f90aea25c2945cefe4121 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 4 Mar 2022 21:40:41 +0900 Subject: [PATCH 06/11] sd-device-enumerator: introduce device_enumerator_scan_devices_and_subsystems() --- .../sd-device/device-enumerator-private.h | 1 + src/libsystemd/sd-device/device-enumerator.c | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/libsystemd/sd-device/device-enumerator-private.h b/src/libsystemd/sd-device/device-enumerator-private.h index 92334a9e69..d74198822c 100644 --- a/src/libsystemd/sd-device/device-enumerator-private.h +++ b/src/libsystemd/sd-device/device-enumerator-private.h @@ -5,6 +5,7 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumeartor); int device_enumerator_scan_subsystems(sd_device_enumerator *enumeartor); +int device_enumerator_scan_devices_and_subsystems(sd_device_enumerator *enumerator); int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device); int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator); int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent); diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 668a92ca0c..df8753dec9 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -20,6 +20,7 @@ typedef enum DeviceEnumerationType { DEVICE_ENUMERATION_TYPE_DEVICES, DEVICE_ENUMERATION_TYPE_SUBSYSTEMS, + DEVICE_ENUMERATION_TYPE_ALL, _DEVICE_ENUMERATION_TYPE_MAX, _DEVICE_ENUMERATION_TYPE_INVALID = -EINVAL, } DeviceEnumerationType; @@ -980,6 +981,58 @@ _public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator return enumerator->devices[++enumerator->current_device_index]; } +int device_enumerator_scan_devices_and_subsystems(sd_device_enumerator *enumerator) { + int r = 0, k; + + assert(enumerator); + + if (enumerator->scan_uptodate && + enumerator->type == DEVICE_ENUMERATION_TYPE_ALL) + return 0; + + device_enumerator_unref_devices(enumerator); + + if (!set_isempty(enumerator->match_tag)) { + k = enumerator_scan_devices_tags(enumerator); + if (k < 0) + r = k; + } else if (enumerator->match_parent) { + k = enumerator_scan_devices_children(enumerator); + if (k < 0) + r = k; + } else { + k = enumerator_scan_dir(enumerator, "class", NULL, NULL); + if (k < 0) + r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m"); + + k = enumerator_scan_dir(enumerator, "bus", "devices", NULL); + if (k < 0) + r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m"); + + if (match_subsystem(enumerator, "module")) { + k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL); + if (k < 0) + r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m"); + } + if (match_subsystem(enumerator, "subsystem")) { + k = enumerator_scan_dir_and_add_devices(enumerator, "bus", NULL, NULL); + if (k < 0) + r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m"); + } + + if (match_subsystem(enumerator, "drivers")) { + k = enumerator_scan_dir(enumerator, "bus", "drivers", "drivers"); + if (k < 0) + r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m"); + } + } + + enumerator->scan_uptodate = true; + enumerator->type = DEVICE_ENUMERATION_TYPE_ALL; + + return r; +} + sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) { assert_return(enumerator, NULL); From 873cf95c2f214aa8619f0a06cad53bf5ef233744 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 5 Mar 2022 00:23:13 +0900 Subject: [PATCH 07/11] udevadm trigger: introduce --prioritized-subsystem option --- man/udevadm.xml | 13 ++++++++ shell-completion/bash/udevadm | 3 +- shell-completion/zsh/_udevadm | 3 +- src/udev/udevadm-trigger.c | 58 +++++++++++++++++++++++------------ 4 files changed, 55 insertions(+), 22 deletions(-) diff --git a/man/udevadm.xml b/man/udevadm.xml index 1f872111e5..99599634e3 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -297,6 +297,19 @@ + + + + Takes a comma separated list of subsystems. When triggering events for devices, the + devices from the specified subsystems and their parents are triggered first. For example, + if , then firstly all block devices and + their parents are triggered, in the next all network devices and their parents are + triggered, and lastly the other devices are triggered. This option can be specified + multiple times, and in that case the lists of the subsystems will be merged. That is, + is equivalent to + . + + diff --git a/shell-completion/bash/udevadm b/shell-completion/bash/udevadm index 08b4ab43a0..b68a332500 100644 --- a/shell-completion/bash/udevadm +++ b/shell-completion/bash/udevadm @@ -54,7 +54,8 @@ _udevadm() { [TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon --uuid' [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' + -g --tag-match -y --sysname-match --name-match -b --parent-match + --prioritized-subsystem' [SETTLE]='-t --timeout -E --exit-if-exists' [CONTROL_STANDALONE]='-e --exit -s --stop-exec-queue -S --start-exec-queue -R --reload --ping' [CONTROL_ARG]='-l --log-priority -p --property -m --children-max -t --timeout' diff --git a/shell-completion/zsh/_udevadm b/shell-completion/zsh/_udevadm index 14efe24808..d9d995fb33 100644 --- a/shell-completion/zsh/_udevadm +++ b/shell-completion/zsh/_udevadm @@ -34,7 +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.]' \ - '--uuid[Print synthetic uevent UUID.]' + '--uuid[Print synthetic uevent UUID.]' \ + '--prioritized-subsystem=[Trigger events for devices which belong to a matching subsystem earlier.]' } (( $+functions[_udevadm_settle] )) || diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index a88823cc21..900e307c06 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -229,7 +229,9 @@ static int help(void) { " -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" - " --uuid Print synthetic uevent UUID\n", + " --uuid Print synthetic uevent UUID\n" + " --prioritized-subsystem=SUBSYSTEM[,SUBSYSTEM…]\n" + " Trigger devices from a matching subsystem first\n", program_invocation_short_name); return 0; @@ -240,28 +242,30 @@ int trigger_main(int argc, char *argv[], void *userdata) { ARG_NAME = 0x100, ARG_PING, ARG_UUID, + ARG_PRIORITIZED_SUBSYSTEM, }; static const struct option options[] = { - { "verbose", no_argument, NULL, 'v' }, - { "dry-run", no_argument, NULL, 'n' }, - { "quiet", no_argument, NULL, 'q' }, - { "type", required_argument, NULL, 't' }, - { "action", required_argument, NULL, 'c' }, - { "subsystem-match", required_argument, NULL, 's' }, - { "subsystem-nomatch", required_argument, NULL, 'S' }, - { "attr-match", required_argument, NULL, 'a' }, - { "attr-nomatch", required_argument, NULL, 'A' }, - { "property-match", required_argument, NULL, 'p' }, - { "tag-match", required_argument, NULL, 'g' }, - { "sysname-match", required_argument, NULL, 'y' }, - { "name-match", required_argument, NULL, ARG_NAME }, - { "parent-match", required_argument, NULL, 'b' }, - { "settle", no_argument, NULL, 'w' }, - { "wait-daemon", optional_argument, NULL, ARG_PING }, - { "version", no_argument, NULL, 'V' }, - { "help", no_argument, NULL, 'h' }, - { "uuid", no_argument, NULL, ARG_UUID }, + { "verbose", no_argument, NULL, 'v' }, + { "dry-run", no_argument, NULL, 'n' }, + { "quiet", no_argument, NULL, 'q' }, + { "type", required_argument, NULL, 't' }, + { "action", required_argument, NULL, 'c' }, + { "subsystem-match", required_argument, NULL, 's' }, + { "subsystem-nomatch", required_argument, NULL, 'S' }, + { "attr-match", required_argument, NULL, 'a' }, + { "attr-nomatch", required_argument, NULL, 'A' }, + { "property-match", required_argument, NULL, 'p' }, + { "tag-match", required_argument, NULL, 'g' }, + { "sysname-match", required_argument, NULL, 'y' }, + { "name-match", required_argument, NULL, ARG_NAME }, + { "parent-match", required_argument, NULL, 'b' }, + { "settle", no_argument, NULL, 'w' }, + { "wait-daemon", optional_argument, NULL, ARG_PING }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, + { "uuid", no_argument, NULL, ARG_UUID }, + { "prioritized-subsystem", required_argument, NULL, ARG_PRIORITIZED_SUBSYSTEM }, {} }; enum { @@ -405,6 +409,20 @@ int trigger_main(int argc, char *argv[], void *userdata) { arg_uuid = true; break; + case ARG_PRIORITIZED_SUBSYSTEM: { + _cleanup_strv_free_ char **subsystems = NULL; + + subsystems = strv_split(optarg, ","); + if (!subsystems) + return log_error_errno(r, "Failed to parse prioritized subsystem '%s': %m", optarg); + + STRV_FOREACH(p, subsystems) { + r = device_enumerator_add_prioritized_subsystem(e, *p); + if (r < 0) + return log_error_errno(r, "Failed to add prioritized subsystem '%s': %m", *p); + } + break; + } case 'V': return print_version(); case 'h': From 1baeee5784f1b859d2a1446f6776efe6d7fde7b6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 4 Mar 2022 21:45:24 +0900 Subject: [PATCH 08/11] udevadm trigger: introduce --type=all option --- man/udevadm.xml | 6 +++--- shell-completion/bash/udevadm | 2 +- shell-completion/zsh/_udevadm | 2 +- src/udev/udevadm-trigger.c | 8 ++++++++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/man/udevadm.xml b/man/udevadm.xml index 99599634e3..24ed4a29c7 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -280,9 +280,9 @@ - Trigger a specific type of devices. Valid types are: - devices, subsystems. - The default value is devices. + Trigger a specific type of devices. Valid types are all, + devices, and subsystems. The default value is + devices. diff --git a/shell-completion/bash/udevadm b/shell-completion/bash/udevadm index b68a332500..4d52597cbf 100644 --- a/shell-completion/bash/udevadm +++ b/shell-completion/bash/udevadm @@ -118,7 +118,7 @@ _udevadm() { if __contains_word "$prev" ${OPTS[TRIGGER_ARG]}; then case $prev in -t|--type) - comps='devices subsystems' + comps='all devices subsystems' ;; -c|--action) comps=$( udevadm trigger --action help ) diff --git a/shell-completion/zsh/_udevadm b/shell-completion/zsh/_udevadm index d9d995fb33..8a10237e3d 100644 --- a/shell-completion/zsh/_udevadm +++ b/shell-completion/zsh/_udevadm @@ -24,7 +24,7 @@ _udevadm_trigger(){ '--verbose[Print the list of devices which will be triggered.]' \ '--dry-run[Do not actually trigger the event.]' \ '--quiet[Suppress error logging in triggering events.]' \ - '--type=[Trigger a specific type of devices.]:types:(devices subsystems failed)' \ + '--type=[Trigger a specific type of devices.]:types:(all devices subsystems failed)' \ '--action=[Type of event to be triggered.]:actions:(add change remove move online offline bind unbind)' \ '--subsystem-match=[Trigger events for devices which belong to a matching subsystem.]' \ '--subsystem-nomatch=[Do not trigger events for devices which belong to a matching subsystem.]' \ diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 900e307c06..e4b3150e60 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -271,6 +271,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { enum { TYPE_DEVICES, TYPE_SUBSYSTEMS, + TYPE_ALL, } device_type = TYPE_DEVICES; sd_device_action_t action = SD_DEVICE_CHANGE; _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; @@ -313,6 +314,8 @@ int trigger_main(int argc, char *argv[], void *userdata) { device_type = TYPE_DEVICES; else if (streq(optarg, "subsystems")) device_type = TYPE_SUBSYSTEMS; + else if (streq(optarg, "all")) + device_type = TYPE_ALL; else return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg); break; @@ -495,6 +498,11 @@ int trigger_main(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to scan devices: %m"); break; + case TYPE_ALL: + r = device_enumerator_scan_devices_and_subsystems(e); + if (r < 0) + return log_error_errno(r, "Failed to scan devices and subsystems: %m"); + break; default: assert_not_reached(); } From 2336bde96420475ccb054326f27290fa0228f27d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 8 Mar 2022 01:33:29 +0900 Subject: [PATCH 09/11] unit: make systemd-udev-trigger.service use --prioritized-subsystem Replaces #19637 and #22643. --- units/systemd-udev-trigger.service | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/units/systemd-udev-trigger.service b/units/systemd-udev-trigger.service index 3d0f7b4f20..5e91995060 100644 --- a/units/systemd-udev-trigger.service +++ b/units/systemd-udev-trigger.service @@ -19,5 +19,4 @@ ConditionPathIsReadWrite=/sys [Service] Type=oneshot RemainAfterExit=yes -ExecStart=-udevadm trigger --type=subsystems --action=add -ExecStart=-udevadm trigger --type=devices --action=add +ExecStart=-udevadm trigger --type=all --action=add --prioritized-subsystem=block,tpmrm From d8b50e5df7e01983279e70c6d970fb60d053df97 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 8 Mar 2022 13:58:02 +0900 Subject: [PATCH 10/11] sd-device-enumerator: support to list only initialized or uninitialized devices --- .../sd-device/device-enumerator-private.h | 11 ++- src/libsystemd/sd-device/device-enumerator.c | 71 +++++++++++-------- src/libudev/libudev-enumerate.c | 2 +- 3 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/libsystemd/sd-device/device-enumerator-private.h b/src/libsystemd/sd-device/device-enumerator-private.h index d74198822c..54fc13c43b 100644 --- a/src/libsystemd/sd-device/device-enumerator-private.h +++ b/src/libsystemd/sd-device/device-enumerator-private.h @@ -3,11 +3,20 @@ #include "sd-device.h" +typedef enum MatchInitializedType { + MATCH_INITIALIZED_NO, /* only devices without a db entry */ + MATCH_INITIALIZED_YES, /* only devices with a db entry */ + MATCH_INITIALIZED_ALL, /* all devices */ + MATCH_INITIALIZED_COMPAT, /* only devices that have no devnode/ifindex or have a db entry */ + _MATCH_INITIALIZED_MAX, + _MATCH_INITIALIZED_INVALID = -EINVAL, +} MatchInitializedType; + int device_enumerator_scan_devices(sd_device_enumerator *enumeartor); int device_enumerator_scan_subsystems(sd_device_enumerator *enumeartor); int device_enumerator_scan_devices_and_subsystems(sd_device_enumerator *enumerator); int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device); -int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator); +int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator, MatchInitializedType type); int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent); int device_enumerator_add_prioritized_subsystem(sd_device_enumerator *enumerator, const char *subsystem); sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator); diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index df8753dec9..1379764156 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -44,7 +44,7 @@ struct sd_device_enumerator { Set *match_sysname; Set *match_tag; Set *match_parent; - bool match_allow_uninitialized; + MatchInitializedType match_initialized; }; _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) { @@ -59,6 +59,7 @@ _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) { *enumerator = (sd_device_enumerator) { .n_ref = 1, .type = _DEVICE_ENUMERATION_TYPE_INVALID, + .match_initialized = MATCH_INITIALIZED_COMPAT, }; *ret = TAKE_PTR(enumerator); @@ -244,17 +245,18 @@ _public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumera _public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator) { assert_return(enumerator, -EINVAL); - enumerator->match_allow_uninitialized = true; + enumerator->match_initialized = MATCH_INITIALIZED_ALL; enumerator->scan_uptodate = false; return 1; } -int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator) { +int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator, MatchInitializedType type) { assert_return(enumerator, -EINVAL); + assert_return(type >= 0 && type < _MATCH_INITIALIZED_MAX, -EINVAL); - enumerator->match_allow_uninitialized = false; + enumerator->match_initialized = type; enumerator->scan_uptodate = false; @@ -513,10 +515,42 @@ static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname) return false; } +static int match_initialized(sd_device_enumerator *enumerator, sd_device *device) { + int r; + + assert(enumerator); + assert(device); + + if (enumerator->match_initialized == MATCH_INITIALIZED_ALL) + return true; + + r = sd_device_get_is_initialized(device); + if (r == -ENOENT) /* this is necessarily racey, so ignore missing devices */ + return false; + if (r < 0) + return r; + + if (enumerator->match_initialized == MATCH_INITIALIZED_COMPAT) { + /* only devices that have no devnode/ifindex or have a db entry are accepted. */ + if (r > 0) + return true; + + if (sd_device_get_devnum(device, NULL) >= 0) + return true; + + if (sd_device_get_ifindex(device, NULL) >= 0) + return true; + + return false; + } + + return (enumerator->match_initialized == MATCH_INITIALIZED_NO) == (r == 0); +} + static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, const char *basedir, const char *subdir1, const char *subdir2) { _cleanup_closedir_ DIR *dir = NULL; char *path; - int r = 0; + int k, r = 0; assert(enumerator); assert(basedir); @@ -537,7 +571,6 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, FOREACH_DIRENT_ALL(de, dir, return -errno) { _cleanup_(sd_device_unrefp) sd_device *device = NULL; char syspath[strlen(path) + 1 + strlen(de->d_name) + 1]; - int initialized, k; if (de->d_name[0] == '.') continue; @@ -556,31 +589,13 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, continue; } - initialized = sd_device_get_is_initialized(device); - if (initialized < 0) { - if (initialized != -ENOENT) - /* this is necessarily racey, so ignore missing devices */ - r = initialized; - + k = match_initialized(enumerator, device); + if (k <= 0) { + if (k < 0) + r = k; continue; } - /* - * All devices with a device node or network interfaces - * possibly need udev to adjust the device node permission - * or context, or rename the interface before it can be - * reliably used from other processes. - * - * For now, we can only check these types of devices, we - * might not store a database, and have no way to find out - * for all other types of devices. - */ - if (!enumerator->match_allow_uninitialized && - !initialized && - (sd_device_get_devnum(device, NULL) >= 0 || - sd_device_get_ifindex(device, NULL) >= 0)) - continue; - if (!device_match_parent(device, enumerator->match_parent, NULL)) continue; diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c index 2dc695bd03..d71a31c566 100644 --- a/src/libudev/libudev-enumerate.c +++ b/src/libudev/libudev-enumerate.c @@ -365,7 +365,7 @@ _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev assert_return(udev_enumerate, -EINVAL); - r = device_enumerator_add_match_is_initialized(udev_enumerate->enumerator); + r = device_enumerator_add_match_is_initialized(udev_enumerate->enumerator, MATCH_INITIALIZED_COMPAT); if (r < 0) return r; From 678f2b16676cd566c50bdec78350f732a9a3ee41 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Mon, 14 Jun 2021 17:46:00 +0200 Subject: [PATCH 11/11] udevadm: trigger: implement --initialized-match/nomatch arguments 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 | 29 +++++++++++++++++++++++++++++ shell-completion/bash/udevadm | 3 ++- shell-completion/zsh/_udevadm | 2 ++ src/udev/udevadm-trigger.c | 13 +++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/man/udevadm.xml b/man/udevadm.xml index 24ed4a29c7..af48571122 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -395,6 +395,35 @@ then each matching result is ORed, that is, all children of each specified device are triggered. + + + + + When is specified, trigger events for devices + that are already initialized by systemd-udevd, and skip devices that + are not initialized yet. + When is specified, trigger events for devices + that are not initialized by systemd-udevd yet, and skip devices that + are already initialized. + Here, initialized devices are those for which at least one udev rule already + completed execution – for any action but remove — 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 remove 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. + WARNING: 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. + ATTRS or IMPORT{parent} keys, see + udev7 + for more details), the final state of the device becomes easily unstable with this option. + + + diff --git a/shell-completion/bash/udevadm b/shell-completion/bash/udevadm index 4d52597cbf..23ce02365c 100644 --- a/shell-completion/bash/udevadm +++ b/shell-completion/bash/udevadm @@ -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 diff --git a/shell-completion/zsh/_udevadm b/shell-completion/zsh/_udevadm index 8a10237e3d..63df8b7c9e 100644 --- a/shell-completion/zsh/_udevadm +++ b/shell-completion/zsh/_udevadm @@ -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.]' } diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index e4b3150e60..56921e2cc6 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -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':