Skip to content

lkl: fix incremental build via tools/lkl#635

Open
clingfei wants to merge 1 commit into
lkl:masterfrom
clingfei:master
Open

lkl: fix incremental build via tools/lkl#635
clingfei wants to merge 1 commit into
lkl:masterfrom
clingfei:master

Conversation

@clingfei
Copy link
Copy Markdown

make -C tools/lkl had two related problems:

  1. Correctness: modifying any kernel source file did not trigger a rebuild. tools/lkl/Makefile's lib/lkl.o rule depended only on bin/stat and $(DOT_CONFIG), so the recursive kernel make was never invoked when only kernel sources changed. Host libraries got relinked over a stale lib/lkl.o, masking the failure.

  2. Performance: even with no source changes, several pipeline stages unconditionally bumped output mtimes, causing the whole chain (objcopy -> install -> all ~200 LKL headers -> every host .o -> liblkl.a -> every .so) to fire on every make.

The patch consists of following modifications:

tools/lkl/Makefile: add FORCE to lib/lkl.o so the recursive make is always entered; kbuild's own incremental check then decides what to rebuild from source timestamps.

arch/lkl/include/uapi/asm/Kbuild: declare syscall_defs.h as generated-y. Without this, scripts/Makefile.asm-generic treats the file as a stale wrapper and REMOVEs it on every build, forcing arch/lkl/Makefile to re-extract it via objcopy.

arch/lkl/Makefile: rewrite the lkl.o and syscall_defs.h rules to objcopy to a tmp file and cmp before replacing $@. vmlinux is PHONY in the top-level Makefile so its recipe always runs; if_changed cannot be used here (newer-prereqs filters out PHONY prereqs and would silently skip real vmlinux content changes), so an in-recipe cmp preserves mtime on no-op rebuilds while still updating on real changes. Pass -p to the install cp so the preserved mtime propagates to tools/lkl/lib/lkl.o.

arch/lkl/scripts/headers_install.py: stage the two-pass install. The first pass writes scripts/headers_install.sh output to dst.raw. The second pass (update_header) reads dst.raw, produces the final lkl_-prefixed content, and only writes dst when the content differs from the existing destination.

After applying this patch, editing any kernel source correctly propagates to the final libraries, and a no-op make in tools/lkl performs no host-side work -- only the two unavoidable OBJCOPY invocations against the PHONY vmlinux target. A no-op make would run as follows:

make -C tools/lkl MMU=1 -j128
make: Entering directory '/path/to/linux/tools/lkl'
  CALL    scripts/checksyscalls.sh
  OBJCOPY lkl.o
  OBJCOPY arch/lkl/include/generated/uapi/asm/syscall_defs.h
make -C ../.. ARCH=lkl  install INSTALL_PATH=/path/to/linux/tools/lkl/
  INSTALL       linux/tools/lkl//lib/lkl.o
make: Leaving directory '/path/to/linux/tools/lkl'

`make -C tools/lkl` had two related problems:

1. Correctness: modifying any kernel source file did not trigger a
   rebuild. tools/lkl/Makefile's lib/lkl.o rule depended only on
   bin/stat and $(DOT_CONFIG), so the recursive kernel make was never
   invoked when only kernel sources changed. Host libraries got
   relinked over a stale lib/lkl.o, masking the failure.

2. Performance: even with no source changes, several pipeline stages
   unconditionally bumped output mtimes, causing the whole chain
   (objcopy -> install -> all ~200 LKL headers -> every host .o ->
   liblkl.a -> every .so) to fire on every make.

The patch consists of following modifications:

tools/lkl/Makefile: add FORCE to lib/lkl.o so the recursive make is
always entered; kbuild's own incremental check then decides what to
rebuild from source timestamps.

arch/lkl/include/uapi/asm/Kbuild: declare syscall_defs.h as
generated-y. Without this, scripts/Makefile.asm-generic treats the
file as a stale wrapper and REMOVEs it on every build, forcing
arch/lkl/Makefile to re-extract it via objcopy.

arch/lkl/Makefile: rewrite the lkl.o and syscall_defs.h rules to
objcopy to a tmp file and cmp before replacing $@. vmlinux is PHONY
in the top-level Makefile so its recipe always runs; if_changed
cannot be used here (newer-prereqs filters out PHONY prereqs and
would silently skip real vmlinux content changes), so an in-recipe
cmp preserves mtime on no-op rebuilds while still updating on real
changes. Pass -p to the install cp so the preserved mtime propagates
to tools/lkl/lib/lkl.o.

arch/lkl/scripts/headers_install.py: stage the two-pass install. The
first pass writes scripts/headers_install.sh output to dst.raw. The
second pass (update_header) reads dst.raw, produces the final
lkl_-prefixed content, and only writes dst when the content differs
from the existing destination.

After applying this patch, editing any kernel source correctly
propagates to the final libraries, and a no-op `make` in tools/lkl
performs no host-side work -- only the two unavoidable OBJCOPY
invocations against the PHONY vmlinux target. A no-op make would run
as follows:

```
make -C tools/lkl MMU=1 -j128
make: Entering directory '/path/to/linux/tools/lkl'
  CALL    scripts/checksyscalls.sh
  OBJCOPY lkl.o
  OBJCOPY arch/lkl/include/generated/uapi/asm/syscall_defs.h
make -C ../.. ARCH=lkl  install INSTALL_PATH=/path/to/linux/tools/lkl/
  INSTALL       linux/tools/lkl//lib/lkl.o
make: Leaving directory '/path/to/linux/tools/lkl'
```

Signed-off-by: Cheng Lingfei <1599101385@qq.com>
@clingfei
Copy link
Copy Markdown
Author

I think this could fix #554.
CC @tavip
Close #554

@github-actions
Copy link
Copy Markdown

Test Results

106 files  ±0  106 suites  ±0   7m 9s ⏱️ +12s
252 tests ±0  241 ✅ ±0  11 💤 ±0  0 ❌ ±0 
821 runs  ±0  765 ✅ ±0  56 💤 ±0  0 ❌ ±0 

Results for commit 0ad6b8b. ± Comparison against base commit 0d3712a.

This pull request removes 64 and adds 64 tests. Note that renamed tests count towards both.
lklfuse btrfs ‑ lklfuse_basic /tmp/tmp.F4N0EPT13y
lklfuse btrfs ‑ lklfuse_basic /tmp/tmp.JPoQXJ6VlR
lklfuse btrfs ‑ lklfuse_basic /tmp/tmp.MMQLXAB78Y
lklfuse btrfs ‑ lklfuse_basic /tmp/tmp.WfHBsdtOyP
lklfuse btrfs ‑ lklfuse_lock_conflict /tmp/tmp.0iVKkQXcAt btrfs /tmp/tmp.0iVKkQXcAt
lklfuse btrfs ‑ lklfuse_lock_conflict /tmp/tmp.KweflCXt92 btrfs /tmp/tmp.KweflCXt92
lklfuse btrfs ‑ lklfuse_lock_conflict /tmp/tmp.qfhani4GZq btrfs /tmp/tmp.qfhani4GZq
lklfuse btrfs ‑ lklfuse_lock_conflict /tmp/tmp.wv1YYbfrdP btrfs /tmp/tmp.wv1YYbfrdP
lklfuse btrfs ‑ lklfuse_mount /tmp/tmp.0iVKkQXcAt /tmp/tmp.MMQLXAB78Y btrfs /tmp/tmp.0iVKkQXcAt
lklfuse btrfs ‑ lklfuse_mount /tmp/tmp.KweflCXt92 /tmp/tmp.JPoQXJ6VlR btrfs /tmp/tmp.KweflCXt92
…
lklfuse btrfs ‑ lklfuse_basic /tmp/tmp.2pneB6qQwj
lklfuse btrfs ‑ lklfuse_basic /tmp/tmp.Q43At08eEK
lklfuse btrfs ‑ lklfuse_basic /tmp/tmp.VLBcypYihp
lklfuse btrfs ‑ lklfuse_basic /tmp/tmp.v0fm2MKyNh
lklfuse btrfs ‑ lklfuse_lock_conflict /tmp/tmp.Xz93T1Io6r btrfs /tmp/tmp.Xz93T1Io6r
lklfuse btrfs ‑ lklfuse_lock_conflict /tmp/tmp.bTR2OWGL8K btrfs /tmp/tmp.bTR2OWGL8K
lklfuse btrfs ‑ lklfuse_lock_conflict /tmp/tmp.c9MW0PqOwK btrfs /tmp/tmp.c9MW0PqOwK
lklfuse btrfs ‑ lklfuse_lock_conflict /tmp/tmp.opB63KNbDF btrfs /tmp/tmp.opB63KNbDF
lklfuse btrfs ‑ lklfuse_mount /tmp/tmp.Xz93T1Io6r /tmp/tmp.Q43At08eEK btrfs /tmp/tmp.Xz93T1Io6r
lklfuse btrfs ‑ lklfuse_mount /tmp/tmp.bTR2OWGL8K /tmp/tmp.v0fm2MKyNh btrfs /tmp/tmp.bTR2OWGL8K
…

clingfei added a commit to clingfei/linux that referenced this pull request May 20, 2026
Same issue commit 8b61f60 ("lkl tests: avoid variable test names")
fixed for disk.sh: lklfuse.sh passes the random mktemp paths $file/$dir
/$lock_file as arguments to lkl_test_run, which embeds them into the test
name. The GitHub test reporter then sees 64 "removed" and 64 "added"
tests on every CI run because the temp paths differ run to run.
See lkl#635 (comment).

Drop the random-path arguments from lkl_test_run calls and reference
the outer-scope $file/$dir/$lock_file directly inside each function.
$fstype stays as an argument since it is stable across runs.

Also update the commented-out stress-ng call so a future uncomment
does not re-introduce the issue.

Signed-off-by: Cheng Lingfei <1599101385@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant