selftests/Makefile builds each test with OUTPUT on the make command line:

  $(MAKE) OUTPUT=$$BUILD/$$TARGET -C $$TARGET

That OUTPUT is authoritative (command-line origin) and travels through
MAKEFLAGS into every sub-make.  For tests that set TEST_GEN_MODS_DIR
(currently mm/page_frag and livepatch/test_modules) the gen_mods_dir rule
recurses into a kernel module build:

  $(MAKE) -C $(TEST_GEN_MODS_DIR)
  # -> make -C $(KDIR) M=... modules

which may in turn (re)build tools/bpf/resolve_btfids as a kernel "prepare"
dependency (CONFIG_DEBUG_INFO_BTF).  resolve_btfids derives its OUTPUT from
O= via tools/scripts/Makefile.include:

  OUTPUT := $(ABSOLUTE_O)/$(if $(subdir),$(subdir)/)

but a command-line OUTPUT inherited from kselftest overrides that
assignment, so resolve_btfids builds into the kselftest test directory.
Because that directory lacks a trailing '/', the tools/build pattern rules
$(OUTPUT)%.o are corrupted as well: ".../mmmain.o" instead of
".../mm/main.o", ending in:

  ld: cannot find .../resolve_btfids-in.o: No such file or directory

Fix this at the source of the leak: strip OUTPUT from the command-line
overrides handed to the gen_mods_dir/clean_mods_dir sub-make only.  OUTPUT,
if still present, then reaches the kernel build merely as an overridable
environment default, which the tools build overrides with its O=-derived
value (which always carries a trailing '/').  The assignment is
target-specific, so other selftest sub-makes -- and the test programs that
rely on OUTPUT -- are unaffected; selftests that build resolve_btfids
themselves with an explicit OUTPUT= (bpf, hid) do not use gen_mods_dir and
are untouched.

This supersedes the earlier attempt to normalise OUTPUT with an override in
tools/bpf/resolve_btfids/Makefile.  That override lives in the outer
resolve_btfids make and is invisible to the nested
"$(MAKE) $(build)=resolve_btfids" sub-make in which the pattern rules
actually run, so it did not fix the corruption; it also risked the
explicit-OUTPUT builds used by bpf/hid.

Reproduce the leak (before this fix), e.g. with a kernel configured for
CONFIG_DEBUG_INFO_BTF and a TEST_GEN_MODS_DIR test such as mm/page_frag:

  $ make kselftest-all
  ...
  HOSTLD  .../mmresolve_btfids-in.o
  gcc: error: .../mm/resolve_btfids-in.o: No such file or directory

Tested:
  * With a real lib.mk gen_mods_dir descent, OUTPUT no longer reaches a
    resolve_btfids-style sub-make as command-line (origin becomes
    environment); the O=-derived "OUTPUT := " assignment then wins.
  * make -C tools/bpf/resolve_btfids
    make -C tools/bpf/resolve_btfids OUTPUT=/tmp/o/resolve_btfids/
    both still build.
  * make OUTPUT=/tmp/build/kcmp -C tools/testing/selftests/kcmp still
    honours OUTPUT for its own programs.

Signed-off-by: Jiangshan Yi <[email protected]>

---
v2:
 - Reworked the fix: instead of overriding OUTPUT in
   tools/bpf/resolve_btfids/Makefile (v1), which is invisible to the
   nested "$(MAKE) $(build)=resolve_btfids" sub-make where the pattern
   rules actually run and also clobbers the explicit OUTPUT= used by
   bpf/hid, strip OUTPUT from the command-line overrides of the
   gen_mods_dir/clean_mods_dir sub-make in tools/testing/selftests/lib.mk
   so the leak is fixed at its source.
v1:
 - initial submission

 tools/testing/selftests/lib.mk | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk
index f02cc8a2e4ae..5345be76223a 100644
--- a/tools/testing/selftests/lib.mk
+++ b/tools/testing/selftests/lib.mk
@@ -142,9 +142,26 @@ else
        @$(call RUN_TESTS, $(TEST_GEN_PROGS) $(TEST_CUSTOM_PROGS) $(TEST_PROGS))
 endif
 
+# The build of TEST_GEN_MODS_DIR recurses into the kernel build (it builds
+# out-of-tree modules via "make -C \$(KDIR) M=..."), which may in turn build
+# tools/bpf/resolve_btfids as a kernel "prepare" dependency.  That tools build
+# derives its own OUTPUT from O=, but a command-line OUTPUT inherited from here
+# (e.g. the per-test output directory that selftests/Makefile passes on its
+# command line) is authoritative and overrides that derivation, corrupting the
+# paths produced by the tools/build pattern rules (e.g. ".../mmmain.o" instead
+# of ".../mm/main.o", and a missing resolve_btfids-in.o).
+#
+# Strip OUTPUT from the command-line overrides handed to this sub-make only, so
+# it can no longer override the O=-derived value downstream.  The variable, if
+# still present, then reaches the kernel build merely as an overridable
+# environment default, which the tools build ignores in favour of its 
O=-derived
+# OUTPUT.  This is target-specific so that other sub-makes, which may 
legitimately
+# rely on the inherited OUTPUT, are unaffected.
+gen_mods_dir: MAKEOVERRIDES := $(filter-out OUTPUT=%,$(MAKEOVERRIDES))
 gen_mods_dir:
        $(Q)$(MAKE) -C $(TEST_GEN_MODS_DIR)
 
+clean_mods_dir: MAKEOVERRIDES := $(filter-out OUTPUT=%,$(MAKEOVERRIDES))
 clean_mods_dir:
        $(Q)$(MAKE) -C $(TEST_GEN_MODS_DIR) clean
 
-- 
2.25.1


Reply via email to