Several udev rules depends on the previous behavior, i.e. that udev
replaces the devlink with the newer device node when the priority is
equivalent. Let's relax the optimization done by
331aa7aa15.
Follow-up for 331aa7aa15.
Note, the offending commit drops O(N) of file reads per uevent, and this
commit does not change the computational order. So, hopefully the
performance impact of this change is small enough.
Fixes#28141.
path_simplify_full()/path_simplify() are changed to allow a NULL path, for
which a NULL is returned. Generally, callers have already asserted before that
the argument is nonnull. This way path_simplify_full()/path_simplify() and
path_simplify_alloc() behave consistently.
In sd-device.c, logging in device_set_syspath() is intentionally dropped: other
branches don't log.
In mount-tool.c, logging in parse_argv() is changed to log the user-specified
value, not the simplified string. In an error message, we should show the
actual argument we got, not some transformed version.
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>
The priority of device node symlink can be negative. So the
initialization is confusing.
Fortunately, this changes no functionality, as we only compare the
priorities of symlinks only when we parsed at least one device node and
its priority.
We likely always want to open the directory via a slink.
There's currently only one caller so it doesn't make any difference in practice
but I think it's still nicer.
No functional change.
-1 was used everywhere, but -EBADF or -EBADFD started being used in various
places. Let's make things consistent in the new style.
Note that there are two candidates:
EBADF 9 Bad file descriptor
EBADFD 77 File descriptor in bad state
Since we're initializating the fd, we're just assigning a value that means
"no fd yet", so it's just a bad file descriptor, and the first errno fits
better. If instead we had a valid file descriptor that became invalid because
of some operation or state change, the other errno would fit better.
In some places, initialization is dropped if unnecessary.
If the filename of a device symlink is too long, then the temporary
filename may become invalid, and we fail to create symlink.
The function `tempfn_random()` used in symlink_atomic_full() generates
a safe temporary filename.
Note that, thanks to the PR #23043, now only one worker can handle
the same symlink simultaneously. Hence, the device ID based temporary
filename is not necessary.
Previously, the stack directory contains empty regular files named with
device ID, and we create sd_device object from the device name.
Hence, we implicitly checked the existence of the device node.
However, now the files in the stack directory are symlink, and we
retrieve the path to the device node and its priority from the symlink.
Hence, the existence of the device node is not checked.
Let's check if the device node is still exist.
By locking the stack directory, we can safely determine the device node
with the highest priority for a symlink. So, the multiple try-and-wait
loops can be dropped, and the code becomes quite simple.
Then, we can always assume the directory exists, and the code become
slightly simpler.
Note, unused directories are removed by the main udevd process in a
later commit.
This merges the various labelling calls into a single label_fix_full(),
which can operate on paths, on inode fds, and in a dirfd/fname style
(i.e. like openat()). It also systematically separates the path to look
up in the db from the path we actually use to reference the inode to
relabel.
This then ports tmpfiles over to labelling by fd. This should make the
code a bit less racy, as we'll try hard to always operate on the very
same inode, pinning it via an fd.
User-visibly the behaviour should not change.
No actual code changes, just splitting out of some dev_t handling
related calls from stat-util.[ch], they are quite a number already, and
deserve their own module now I think.
Also, try to settle on the name "devnum" as the name for the concept,
instead of "devno" or "dev" or "devid". "devnum" is the name exported in
udev APIs, hence probably best to stick to that. (this just renames a
few symbols to "devum", local variables are left untouched, to make the
patch not too invasive)
No actual code changes.
The variable is not useful outside of the loop (it'll always be null
after the loop is finished), so we can declare it inline in the loop.
This saves one variable declaration and reduces the chances that somebody
tries to use the variable outside of the loop.
For consistency, 'de' is used everywhere for the var name.
Previously the mkdir_label() family of calls was implemented in
src/shared/mkdir-label.c but its functions partly declared ins
src/shared/label.h and partly in src/basic/mkdir.h (!!). That's weird
(and wrong).
Let's clean this up, and add a proper mkdir-label.h matching the .c
file.
Previously, the devlink was created based on the priority saved in udev
database. So, we needed to reevaluate devlinks after database is saved.
But now the priority is stored in the symlink under /run/udev/links, and
the loop of devlink creation is controlled with the timestamp of the
directory. So, the double evaluation is not necessary anymore.
By the previous commit, it is not necessary to distinguish if the devlink
already exists. Also, I cannot find any significant advantages of the
previous complecated logic, that is, first try to create directly, and then
fallback to atomically creation. Moreover, such logic increases the chance
of conflicts between multiple udev workers.
This makes devlinks always created atomically. Hopefully, this reduces the
conflicts between the workers.
During creating a symlink to a device node, if another device node which
requests the same symlink is added/removed, `stat_inode_unmodified()`
should always detects that. We do not need to continue the loop
unconditionally.
Previously, we only store device IDs in /run/udev/links, and when
creating/removing device node symlink, we create sd_device object
corresponds to the IDs and read device node and priority from the
object. That requires parsing uevent and udev database files.
This makes link_find_prioritized() get the most prioritzed device node
without parsing the files.
This makes the last 11 chars are always preserved for hashed string.
So, it is hard to generate a path which conflicts to another path.
Fixes an issue demonstrated in the previous commit.