1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-09 01:18:19 +03:00

udev-node: optimize device node symlink creation

If multiple devices requested the same device node symlink with the same
priority, then previously we read O(N^2) of files saved in
/run/udev/links.

This makes if the requested symlink already exists with equal or higher
priority, then the symlink is kept, and skip to read all existing files,
except for one related to the current device node, in /run/udev/links.
Hence, the total amount of file read becomes O(N).

This improves performance of testcase_simultaneous_events_2 added by the
previous commit about 30%.
Before (32.8 sec):
```
 ## 3 iterations start: 11:13:44.690953163
 ## 3 iterations end: 11:14:17.493974927
```
After (23.8 sec):
```
 ## 3 iterations start: 11:17:53.869938387
 ## 3 iterations end: 11:18:17.624268345
```

This is based on the idea and analysis by Franck Bui.

Replaces #25839.

Co-authored-by: Franck Bui <fbui@suse.com>
This commit is contained in:
Yu Watanabe 2023-01-13 13:25:43 +09:00 committed by Lennart Poettering
parent 0b75d6579b
commit 331aa7aa15

View File

@ -392,11 +392,43 @@ static int stack_directory_open(sd_device *dev, const char *slink, int *ret_dirf
return 0;
}
static int link_update(sd_device *dev, const char *slink, bool add) {
_cleanup_close_ int dirfd = -EBADF, lockfd = -EBADF;
_cleanup_free_ char *devnode = NULL;
static int node_get_current(const char *slink, int dirfd, char **ret_id, int *ret_prio) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
_cleanup_free_ char *id_dup = NULL;
const char *id;
int r;
assert(slink);
assert(dirfd >= 0);
assert(ret_id);
r = sd_device_new_from_devname(&dev, slink);
if (r < 0)
return r;
r = device_get_device_id(dev, &id);
if (r < 0)
return r;
id_dup = strdup(id);
if (!id_dup)
return -ENOMEM;
if (ret_prio) {
r = stack_directory_read_one(dirfd, id, NULL, ret_prio);
if (r < 0)
return r;
}
*ret_id = TAKE_PTR(id_dup);
return 0;
}
static int link_update(sd_device *dev, const char *slink, bool add) {
_cleanup_free_ char *current_id = NULL, *devnode = NULL;
_cleanup_close_ int dirfd = -EBADF, lockfd = -EBADF;
int r, current_prio;
assert(dev);
assert(slink);
@ -404,10 +436,64 @@ static int link_update(sd_device *dev, const char *slink, bool add) {
if (r < 0)
return r;
r = node_get_current(slink, dirfd, &current_id, add ? &current_prio : NULL);
if (r < 0 && !ERRNO_IS_DEVICE_ABSENT(r))
return log_device_debug_errno(dev, r, "Failed to get the current device node priority for '%s': %m", slink);
r = stack_directory_update(dev, dirfd, add);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to update stack directory for '%s': %m", slink);
if (current_id) {
const char *id;
r = device_get_device_id(dev, &id);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to get device id: %m");
if (add) {
int prio;
r = device_get_devlink_priority(dev, &prio);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to get devlink priority: %m");
if (streq(current_id, id)) {
if (current_prio <= prio)
/* The devlink is ours and already exists, and the new priority is
* equal or higher than the previous. Hence, it is not necessary to
* recreate it. */
return 0;
/* The devlink priority is downgraded. Another device may have a higher
* priority now. Let's find the device node with the highest priority. */
} else {
if (current_prio >= prio)
/* The devlink with equal or higher priority already exists and is
* owned by another device. Hence, it is not necessary to recreate it. */
return 0;
/* This device has a higher priority than the current. Let's create the
* devlink to our device node. */
return node_symlink(dev, NULL, slink);
}
} else {
if (!streq(current_id, id))
/* The devlink already exists and is owned by another device. Hence, it is
* not necessary to recreate it. */
return 0;
/* The current devlink is ours, and the target device will be removed. Hence, we need
* to search the device that has the highest priority. and update the devlink. */
}
} else {
/* The requested devlink does not exist, or the target device does not exist and the devlink
* points to a non-existing device. Let's search the deivce that has the highest priority,
* and update the devlink. */
;
}
r = stack_directory_find_prioritized_devnode(dev, dirfd, add, &devnode);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to determine device node with the highest priority for '%s': %m", slink);