Replace the inotify + /run/udev/watch/ symlink machinery with fanotify inode
marks (FAN_CLOSE_WRITE). The point is not merely a different backend; fanotify
removes several structural costs that inotify imposed on udevd:
- An inotify event only identifies the watch by a watch descriptor, which udevd
had to translate back to a device. That mapping was maintained as a table of
symlinks under /run/udev/watch/. A fanotify event instead carries the watched
inode's file handle (FAN_REPORT_FID), which is resolved to the device directly
via open_by_handle_at()+fstat(). The wd->device translation, and with it
/run/udev/watch/ entirely, is no longer needed.
- Without that shared symlink store to coordinate, a worker can add and remove
its own device marks directly on the fanotify group fd. Previously the watch
state was owned by the manager, and workers had to request (un)registration
over the notification socket (sd_notify()+SIGUSR1). Dropping that round-trip
both simplifies the code and is expected to be faster.
- A fanotify mark lives on the inode and is dropped by the kernel once the inode
is gone, so the special handling for removed device nodes is no longer needed.
The group fd is handed over across restarts via the service manager's fd store
and the kernel keeps the marks, so nothing is rebuilt in-process; the fd is also
propagated to each worker. Watches left behind by an older, inotify-based udevd
under /run/udev/watch/ are migrated to fanotify marks on first start, then the
directory is removed.
Device watch falls back to inotify on kernels < v5.13, when CONFIG_SHMEM=n
(devtmpfs backed by ramfs), or when CONFIG_FANOTIFY is disabled. This fallback
can also be forced via $SYSTEMD_UDEV_USE_INOTIFY.