From: <daniel.turull@ericsson.com>
To: <openembedded-core@lists.openembedded.org>
Cc: <qi.chen@windriver.com>, <alex.kanavin@gmail.com>,
<richard.purdie@linuxfoundation.org>, <Ross.Burton@arm.com>,
<mathieu.dubois-briand@bootlin.com>,
Daniel Turull <daniel.turull@ericsson.com>
Subject: [PATCH v3 3/3] systemd: add native hwdb generator for hosts without STATX_MNT_ID
Date: Tue, 30 Jun 2026 13:50:24 +0200 [thread overview]
Message-ID: <20260630115028.4001775-4-daniel.turull@ericsson.com> (raw)
In-Reply-To: <20260630115028.4001775-1-daniel.turull@ericsson.com>
From: Daniel Turull <daniel.turull@ericsson.com>
systemd 261 requires STATX_MNT_ID (kernel >= 5.8) for path resolution.
On older hosts (e.g. RHEL 8 with kernel 4.18), the QEMU-emulated
udevadm hwdb fails during image construction.
Add systemd-hwdb-native recipe that builds systemd-hwdb natively with:
- A patch restoring /proc/self/fdinfo mount-ID fallback for kernels
lacking STATX_MNT_ID (applied only to native recipes)
- A patch forcing compat mode in hwdb generation to avoid embedding
build-host paths in hwdb.bin (reproducibility)
Update the update_udev_hwdb intercept to prefer the native
systemd-hwdb over QEMU emulation, with a test -s check to catch
silent failures from either path.
Tested on RHEL 8.10 and Ubuntu 22.04.5
AI-Generated: Claude-opus-4.6
Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
---
I'm not sure who should be the maitainer of the new native recipe.
is it Qi Chen, who is the maintainer for the rest of systemd recipes,
unassigned or me? The question I'm asking is because all need to be
updated at the same time.
---
meta/conf/distro/include/maintainers.inc | 1 +
.../systemd/systemd-hwdb-native_261.bb | 32 ++++
.../systemd/systemd-systemctl-native_261.bb | 3 +
...idfd_open-and-STATX_MNT_ID-on-older-.patch | 176 ++++++++++++++++++
...t-mode-for-reproducible-cross-builds.patch | 36 ++++
meta/recipes-core/systemd/systemd_261.bb | 2 +-
scripts/postinst-intercepts/update_udev_hwdb | 24 ++-
7 files changed, 269 insertions(+), 5 deletions(-)
create mode 100644 meta/recipes-core/systemd/systemd-hwdb-native_261.bb
create mode 100644 meta/recipes-core/systemd/systemd/Handle-missing-pidfd_open-and-STATX_MNT_ID-on-older-.patch
create mode 100644 meta/recipes-core/systemd/systemd/hwdb-use-compat-mode-for-reproducible-cross-builds.patch
diff --git a/meta/conf/distro/include/maintainers.inc b/meta/conf/distro/include/maintainers.inc
index 4c6307086c..b51c66ea18 100644
--- a/meta/conf/distro/include/maintainers.inc
+++ b/meta/conf/distro/include/maintainers.inc
@@ -831,6 +831,7 @@ RECIPE_MAINTAINER:pn-systemd-boot-native = "Viswanath Kraleti <quic_vkraleti@qui
RECIPE_MAINTAINER:pn-systemd-bootchart = "Chen Qi <Qi.Chen@windriver.com>"
RECIPE_MAINTAINER:pn-systemd-bootconf = "Chen Qi <Qi.Chen@windriver.com>"
RECIPE_MAINTAINER:pn-systemd-conf = "Chen Qi <Qi.Chen@windriver.com>"
+RECIPE_MAINTAINER:pn-systemd-hwdb-native = "Unassigned <unassigned@yoctoproject.org>"
RECIPE_MAINTAINER:pn-systemd-machine-units = "Chen Qi <Qi.Chen@windriver.com>"
RECIPE_MAINTAINER:pn-systemd-serialgetty = "Chen Qi <Qi.Chen@windriver.com>"
RECIPE_MAINTAINER:pn-systemd-systemctl-native = "Chen Qi <Qi.Chen@windriver.com>"
diff --git a/meta/recipes-core/systemd/systemd-hwdb-native_261.bb b/meta/recipes-core/systemd/systemd-hwdb-native_261.bb
new file mode 100644
index 0000000000..d328fc3c44
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd-hwdb-native_261.bb
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: MIT
+FILESEXTRAPATHS:prepend := "${THISDIR}/systemd:"
+
+SUMMARY = "Hardware database management tool from systemd"
+
+require systemd.inc
+
+DEPENDS = "gperf-native libcap-native util-linux-native python3-jinja2-native"
+
+# TODO: Remove STATX_MNT_ID patch once minimum supported build host kernel is >= 5.8 (RHEL 8 EOL: 2029)
+SRC_URI += "file://Handle-missing-pidfd_open-and-STATX_MNT_ID-on-older-.patch \
+ file://hwdb-use-compat-mode-for-reproducible-cross-builds.patch \
+ "
+
+inherit pkgconfig meson native
+
+MESON_TARGET = "systemd-hwdb"
+
+# Override prefix so compiled-in UDEVLIBEXECDIR (/usr/lib/udev) matches the
+# target rootfs layout. This allows --root $D --usr to find hwdb.d source
+# files and write hwdb.bin to the correct location.
+EXTRA_OEMESON += "--prefix /usr"
+EXTRA_OEMESON += "-Dhwdb=true -Dlink-udev-shared=false"
+EXTRA_OEMESON += "-Dpam=disabled -Daudit=disabled -Dselinux=disabled"
+EXTRA_OEMESON += "-Dacl=disabled -Dapparmor=disabled -Dseccomp=disabled"
+EXTRA_OEMESON += "-Dlibcryptsetup=disabled -Dlibcurl=disabled -Dlibfido2=disabled"
+EXTRA_OEMESON += "-Dpcre2=disabled -Dp11kit=disabled -Dopenssl=disabled"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${B}/systemd-hwdb ${D}${bindir}/systemd-hwdb
+}
diff --git a/meta/recipes-core/systemd/systemd-systemctl-native_261.bb b/meta/recipes-core/systemd/systemd-systemctl-native_261.bb
index 28fddc79df..ac09c804a5 100644
--- a/meta/recipes-core/systemd/systemd-systemctl-native_261.bb
+++ b/meta/recipes-core/systemd/systemd-systemctl-native_261.bb
@@ -6,6 +6,9 @@ require systemd.inc
DEPENDS = "gperf-native libcap-native util-linux-native python3-jinja2-native"
+# TODO: Remove STATX_MNT_ID patch once minimum supported build host kernel is >= 5.8 (RHEL 8 EOL: 2029)
+SRC_URI += "file://Handle-missing-pidfd_open-and-STATX_MNT_ID-on-older-.patch"
+
inherit pkgconfig meson native
MESON_TARGET = "systemctl"
diff --git a/meta/recipes-core/systemd/systemd/Handle-missing-pidfd_open-and-STATX_MNT_ID-on-older-.patch b/meta/recipes-core/systemd/systemd/Handle-missing-pidfd_open-and-STATX_MNT_ID-on-older-.patch
new file mode 100644
index 0000000000..c63423cc96
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/Handle-missing-pidfd_open-and-STATX_MNT_ID-on-older-.patch
@@ -0,0 +1,176 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Turull <daniel.turull@ericsson.com>
+Date: Mon, 23 Jun 2026 12:00:00 +0200
+Subject: [PATCH] Handle missing pidfd_open and STATX_MNT_ID on older kernels
+
+On hosts lacking pidfd_open (kernel < 5.3) or STATX_MNT_ID (kernel < 5.8,
+e.g. RHEL 8), native tools (systemctl --root, systemd-hwdb --root) fail
+during path resolution. Fix by:
+
+- Treating ENOSYS/EOPNOTSUPP from pidfd_open as graceful fallback.
+- Adding fd_get_mount_id() to read mnt_id from /proc/self/fdinfo (available
+ since kernel 3.15) and using it as fallback when statx returns -EUNATCH in
+ fds_inode_and_mount_same() and chase_statx().
+
+This restores the /proc/self/fdinfo fallback that existed in systemd 259
+(fd_fdinfo_mnt_id in mountpoint-util.c) but was removed upstream in 260+.
+
+This patch is only applied to native recipes (systemd-systemctl-native,
+systemd-hwdb-native) where /proc/self/fdinfo is guaranteed available.
+Do NOT apply to the target systemd recipe.
+
+Upstream-Status: Inappropriate [oe specific]
+
+Assisted-by: kiro:claude-opus-4.6
+Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
+---
+ src/basic/chase.c | 20 ++++++++++++++-
+ src/basic/fd-util.c | 63 +++++++++++++++++++++++++++++++++++++++++++--
+ src/basic/fd-util.h | 1 +
+ src/basic/pidref.c | 4 +--
+ 4 files changed, 83 insertions(+), 5 deletions(-)
+
+--- a/src/basic/pidref.c 2026-06-25 14:01:12.007875484 +0200
++++ b/src/basic/pidref.c 2026-06-25 14:01:55.098770206 +0200
+@@ -106,8 +106,8 @@ int pidref_set_pid(PidRef *pidref, pid_t
+
+ fd = pidfd_open(pid, 0);
+ if (fd < 0) {
+- /* Graceful fallback in case the kernel is out of fds */
+- if (!ERRNO_IS_RESOURCE(errno))
++ /* Graceful fallback in case the kernel is out of fds or lacks pidfd support */
++ if (!ERRNO_IS_RESOURCE(errno) && !ERRNO_IS_NOT_SUPPORTED(errno))
+ return log_debug_errno(errno, "Failed to open pidfd for pid " PID_FMT ": %m", pid);
+
+ fd = -EBADF;
+--- a/src/basic/fd-util.h 2026-06-25 14:01:12.009875526 +0200
++++ b/src/basic/fd-util.h 2026-06-25 14:01:20.909060415 +0200
+@@ -188,6 +188,7 @@ static inline int dir_fd_is_root_or_cwd(
+ }
+
+ int fds_inode_and_mount_same(int fd1, int fd2);
++int fd_get_mount_id(int fd, uint64_t *ret);
+
+ int resolve_xat_fdroot(int *fd, const char **path, char **ret_buffer);
+
+--- a/src/basic/fd-util.c 2026-06-25 14:01:12.011875567 +0200
++++ b/src/basic/fd-util.c 2026-06-25 14:01:40.007456905 +0200
+@@ -1082,6 +1082,38 @@ int path_is_root_at(int dir_fd, const ch
+ return fds_inode_and_mount_same(dir_fd, XAT_FDROOT);
+ }
+
++int fd_get_mount_id(int fd, uint64_t *ret) {
++ char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
++ _cleanup_close_ int real_fd = -EBADF;
++ _cleanup_free_ char *p = NULL;
++ uint64_t mnt_id;
++ int r;
++
++ assert(ret);
++
++ /* /proc/self/fdinfo/ requires a real fd; resolve AT_FDCWD/XAT_FDROOT via O_PATH. */
++ if (fd == AT_FDCWD || fd == XAT_FDROOT) {
++ real_fd = open(fd == XAT_FDROOT ? "/" : ".", O_PATH|O_CLOEXEC);
++ if (real_fd < 0)
++ return -errno;
++ fd = real_fd;
++ }
++
++ assert(fd >= 0);
++ xsprintf(path, "/proc/self/fdinfo/%i", fd);
++
++ r = get_proc_field(path, "mnt_id", &p);
++ if (r < 0)
++ return r;
++
++ r = safe_atou64(p, &mnt_id);
++ if (r < 0)
++ return r;
++
++ *ret = mnt_id;
++ return 0;
++}
++
+ int fds_inode_and_mount_same(int fd1, int fd2) {
+ struct statx sx1, sx2;
+ int r;
+@@ -1092,7 +1124,20 @@ int fds_inode_and_mount_same(int fd1, in
+ r = xstatx(fd1, /* path = */ NULL, AT_EMPTY_PATH,
+ STATX_TYPE|STATX_INO|STATX_MNT_ID,
+ &sx1);
+- if (r < 0)
++ if (r == -EUNATCH) {
++ uint64_t mnt_id;
++
++ /* Kernel lacks STATX_MNT_ID; fall back to /proc/self/fdinfo. */
++ r = xstatx(fd1, /* path = */ NULL, AT_EMPTY_PATH,
++ STATX_TYPE|STATX_INO, &sx1);
++ if (r < 0)
++ return r;
++ r = fd_get_mount_id(fd1, &mnt_id);
++ if (r < 0)
++ return r;
++ sx1.stx_mnt_id = mnt_id;
++ sx1.stx_mask |= STATX_MNT_ID;
++ } else if (r < 0)
+ return r;
+
+ if (fd1 == fd2) /* Shortcut things if fds are the same (only after validating the fd) */
+@@ -1101,7 +1146,19 @@ int fds_inode_and_mount_same(int fd1, in
+ r = xstatx(fd2, /* path = */ NULL, AT_EMPTY_PATH,
+ STATX_TYPE|STATX_INO|STATX_MNT_ID,
+ &sx2);
+- if (r < 0)
++ if (r == -EUNATCH) {
++ uint64_t mnt_id;
++
++ r = xstatx(fd2, /* path = */ NULL, AT_EMPTY_PATH,
++ STATX_TYPE|STATX_INO, &sx2);
++ if (r < 0)
++ return r;
++ r = fd_get_mount_id(fd2, &mnt_id);
++ if (r < 0)
++ return r;
++ sx2.stx_mnt_id = mnt_id;
++ sx2.stx_mask |= STATX_MNT_ID;
++ } else if (r < 0)
+ return r;
+
+ r = statx_mount_same(&sx1, &sx2);
+--- a/src/basic/chase.c 2026-06-25 14:01:12.013875609 +0200
++++ b/src/basic/chase.c 2026-06-25 14:01:47.117604514 +0200
+@@ -40,7 +40,9 @@
+ (CHASE_MUST_BE_DIRECTORY|CHASE_MUST_BE_REGULAR|CHASE_MUST_BE_SOCKET)
+
+ static int chase_statx(int fd, struct statx *ret) {
+- return xstatx_full(fd,
++ int r;
++
++ r = xstatx_full(fd,
+ /* path= */ NULL,
+ /* statx_flags= */ 0,
+ XSTATX_MNT_ID_BEST,
+@@ -48,6 +50,23 @@ static int chase_statx(int fd, struct st
+ /* optional_mask= */ 0,
+ /* mandatory_attributes= */ 0,
+ ret);
++ if (r == -EUNATCH) {
++ uint64_t mnt_id;
++
++ /* Kernel lacks STATX_MNT_ID; fall back to /proc/self/fdinfo. */
++ r = xstatx(fd, /* path= */ NULL, /* statx_flags= */ 0,
++ STATX_TYPE|STATX_UID|STATX_INO,
++ ret);
++ if (r < 0)
++ return r;
++ r = fd_get_mount_id(fd, &mnt_id);
++ if (r < 0)
++ return r;
++ ret->stx_mnt_id = mnt_id;
++ ret->stx_mask |= STATX_MNT_ID;
++ }
++
++ return r;
+ }
+
+ static int chase_openat2(int root_fd, int dir_fd, const char *path, ChaseFlags chase_flags) {
diff --git a/meta/recipes-core/systemd/systemd/hwdb-use-compat-mode-for-reproducible-cross-builds.patch b/meta/recipes-core/systemd/systemd/hwdb-use-compat-mode-for-reproducible-cross-builds.patch
new file mode 100644
index 0000000000..bb90105cbd
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/hwdb-use-compat-mode-for-reproducible-cross-builds.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Daniel Turull <daniel.turull@ericsson.com>
+Date: Wed, 25 Jun 2026 10:00:00 +0200
+Subject: [PATCH] hwdb: use compat mode to avoid embedding source paths
+
+Use compat=true in systemd-hwdb's verb_update() so that source
+filenames, line numbers, and priorities are not embedded in hwdb.bin.
+
+Without this, when --root $D is used during cross-compilation, the
+absolute build paths (e.g. /tmp/work/.../rootfs/usr/lib/udev/hwdb.d/...)
+are written into the database, causing:
+- Non-reproducible builds (different TMPDIR → different hwdb.bin)
+- Build directory path leakage into the target image
+
+The compat format matches what udevadm hwdb (the deprecated path)
+has always produced, and is the expected format for cross-built images.
+
+Upstream-Status: Inappropriate [oe specific]
+
+AI-Generated: Claude Opus 4.6
+Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
+---
+ src/hwdb/hwdb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/src/hwdb/hwdb.c
++++ b/src/hwdb/hwdb.c
+@@ -27,7 +27,7 @@ static int verb_update(int argc, char *argv[], uintptr_t _data, void *userdata)
+ if (hwdb_bypass())
+ return 0;
+
+- return hwdb_update(arg_root, arg_hwdb_bin_dir, arg_strict, false);
++ return hwdb_update(arg_root, arg_hwdb_bin_dir, arg_strict, true);
+ }
+
+ static int help(void) {
diff --git a/meta/recipes-core/systemd/systemd_261.bb b/meta/recipes-core/systemd/systemd_261.bb
index eedce348c3..22bd4ca5fc 100644
--- a/meta/recipes-core/systemd/systemd_261.bb
+++ b/meta/recipes-core/systemd/systemd_261.bb
@@ -910,7 +910,7 @@ pkg_prerm:${PN}:libc-glibc () {
fi
}
-PACKAGE_WRITE_DEPS += "qemuwrapper-cross"
+PACKAGE_WRITE_DEPS += "qemuwrapper-cross systemd-hwdb-native"
pkg_postinst:udev-hwdb () {
if test -n "$D"; then
diff --git a/scripts/postinst-intercepts/update_udev_hwdb b/scripts/postinst-intercepts/update_udev_hwdb
index 8b3f5de791..d7a4ffc294 100644
--- a/scripts/postinst-intercepts/update_udev_hwdb
+++ b/scripts/postinst-intercepts/update_udev_hwdb
@@ -19,7 +19,23 @@ case "${PREFERRED_PROVIDER_udev}" in
;;
esac
-rm -f $D${UDEVLIBDIR}/udev/hwdb.bin
-PSEUDO_UNLOAD=1 ${binprefix}qemuwrapper -L $D $D${UDEVADM} hwdb --update --root $D ${UDEV_EXTRA_ARGS} ||
- PSEUDO_UNLOAD=1 qemuwrapper -L $D $D${UDEVADM} hwdb --update --root $D ${UDEV_EXTRA_ARGS}
-chown root:root $D${UDEVLIBDIR}/udev/hwdb.bin
+hwdb_bin="$D${UDEVLIBDIR}/udev/hwdb.bin"
+rm -f "$hwdb_bin"
+
+# Use native systemd-hwdb to generate hwdb.bin at build time.
+# This avoids QEMU user-mode emulation and works on host kernels < 5.8
+# (e.g. RHEL 8) where systemd 261+ would fail due to missing STATX_MNT_ID.
+NATIVE_HWDB="${STAGING_DIR_NATIVE}/usr/bin/systemd-hwdb"
+if test -x "$NATIVE_HWDB" && test "${PREFERRED_PROVIDER_udev}" = "systemd"; then
+ PSEUDO_UNLOAD=1 $NATIVE_HWDB update --root $D ${UDEV_EXTRA_ARGS}
+else
+ PSEUDO_UNLOAD=1 ${binprefix}qemuwrapper -L $D $D${UDEVADM} hwdb --update --root $D ${UDEV_EXTRA_ARGS} ||
+ PSEUDO_UNLOAD=1 qemuwrapper -L $D $D${UDEVADM} hwdb --update --root $D ${UDEV_EXTRA_ARGS}
+fi
+
+if ! test -s "$hwdb_bin"; then
+ echo "ERROR: hwdb.bin was not created at $hwdb_bin" >&2
+ echo "The hwdb generation command exited successfully but produced no output." >&2
+ exit 1
+fi
+chown root:root "$hwdb_bin"
next prev parent reply other threads:[~2026-06-30 11:50 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-30 11:50 [PATCH v3 0/3] systemd: update to 261 and be compatible with rhel8 daniel.turull
2026-06-30 11:50 ` [PATCH v3 1/3] dlopen-deps.inc: treat soname list as ordered alternatives daniel.turull
2026-06-30 11:50 ` [PATCH v3 2/3] systemd: upgrade to 261 daniel.turull
2026-06-30 23:08 ` [OE-core] " Khem Raj
2026-07-01 7:12 ` Daniel Turull
2026-06-30 11:50 ` daniel.turull [this message]
2026-07-02 8:36 ` [PATCH v3 0/3] systemd: update to 261 and be compatible with rhel8 Mathieu Dubois-Briand
2026-07-02 8:58 ` Daniel Turull
2026-07-02 9:54 ` Mathieu Dubois-Briand
2026-07-02 11:03 ` Alexander Kanavin
2026-07-02 13:19 ` Daniel Turull
2026-07-02 13:34 ` Richard Purdie
2026-07-02 14:03 ` Daniel Turull
2026-07-02 17:12 ` Alexander Kanavin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260630115028.4001775-4-daniel.turull@ericsson.com \
--to=daniel.turull@ericsson.com \
--cc=Ross.Burton@arm.com \
--cc=alex.kanavin@gmail.com \
--cc=mathieu.dubois-briand@bootlin.com \
--cc=openembedded-core@lists.openembedded.org \
--cc=qi.chen@windriver.com \
--cc=richard.purdie@linuxfoundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.