From a33edfde6ec413a7dd23a43d86ff631f623a67bc Mon Sep 17 00:00:00 2001 From: Brad House Date: Sat, 23 May 2026 17:15:30 +0000 Subject: [PATCH] [debian/rules]: atomic symlink replacement for /lib/modules//{build,source} Replace the racy `rm` + `ln -s` pair with `ln -sfn`. The two-step form leaves a window of tens-to-hundreds of milliseconds where /lib/modules/$(KVER_ARCH)/build and /lib/modules/$(KVER_ARCH)/source do not exist on disk. `ln -sfn` performs the unlink + symlink in a single rename(2) syscall via a hidden temp path, so the target name is never absent from a concurrent observer's point of view. This race fails sibling platform-modules-* recipes in sonic-buildimage that build concurrently. Each of those recipes iterates over its MODULE_DIRS calling make -C /lib/modules/$(KVER_ARCH)/build M=... clean per platform. If a single iteration lands in the window between this recipe's `rm` and `ln -s`, GNU make's chdir fails with "No such file or directory" on the kernel build dir, aborting the whole recipe. Observed in a sonic-buildimage Broadcom build: make[3]: *** /lib/modules/6.12.41+deb13-sonic-amd64/build: \ No such file or directory. Stop. [...] make: *** [slave.mk:915: target/debs/trixie/\ platform-modules-z9100_1.1_amd64.deb] Error 1 The dell platform-modules iteration succeeded for the first six platforms (s6000 .. s5224f) and failed on the seventh (s5232f), exactly the kind of stochastic window-strike that a non-atomic symlink replacement produces. The non-DNX variant `saibcm-modules/debian/rules` already uses this idiom (lines 92-93 at HEAD of sdk-6.5.32-gpl): cd /; sudo ln -sfn /usr/src/linux-headers-$(KVER_COMMON)/ \ /lib/modules/$(KVER_ARCH)/source cd /; sudo ln -sfn /usr/src/linux-headers-$(KVER_ARCH)/ \ /lib/modules/$(KVER_ARCH)/build so this is a delta the DNX branches missed. Behaviorally identical when no concurrent observer is racing; race-free when one is. Signed-off-by: Brad House --- debian/rules | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/debian/rules b/debian/rules index 2fa10b7..2c05de2 100755 --- a/debian/rules +++ b/debian/rules @@ -87,12 +87,24 @@ build-arch: configure-stamp build-arch-stamp build-arch-stamp: dh_testdir - # create links + # Create the /lib/modules/$(KVER_ARCH)/{build,source} symlinks + # atomically. Using `rm` followed by `ln -s` leaves a window of + # tens to hundreds of milliseconds where the symlink does not + # exist on disk. Other concurrent platform-modules-* recipes + # (e.g. sonic-platform-modules-dell's debian/rules) iterate over + # their MODULE_DIRS running `make -C /lib/modules/$(KVER_ARCH)/build + # M=... clean` per platform, and a single iteration that lands in + # that window fails with "No such file or directory" on the + # kernel build dir, aborting the whole recipe. + # + # `ln -sfn` performs the unlink + symlink in a single rename(2) + # syscall (via a hidden temp path), so the target name is never + # absent from a concurrent observer's point of view. The non-DNX + # variant of this Makefile (`platform/broadcom/saibcm-modules/`) + # already uses this form. cd /; sudo mkdir -p /lib/modules/$(KVER_ARCH) - cd /; sudo rm /lib/modules/$(KVER_ARCH)/build - cd /; sudo rm /lib/modules/$(KVER_ARCH)/source - cd /; sudo ln -s /usr/src/linux-headers-$(KVER_COMMON)/ /lib/modules/$(KVER_ARCH)/source - cd /; sudo ln -s /usr/src/linux-headers-$(KVER_ARCH)/ /lib/modules/$(KVER_ARCH)/build + cd /; sudo ln -sfn /usr/src/linux-headers-$(KVER_COMMON)/ /lib/modules/$(KVER_ARCH)/source + cd /; sudo ln -sfn /usr/src/linux-headers-$(KVER_ARCH)/ /lib/modules/$(KVER_ARCH)/build if [ ! -e /usr/src/linux-headers-$(KVER_COMMON)/include/generated ]; then \ sudo ln -s /usr/src/linux-headers-$(KVER_ARCH)/include/generated/ /usr/src/linux-headers-$(KVER_COMMON)/include/generated; \ fi