public inbox for bpf@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs
@ 2026-04-15 20:59 Ricardo B. Marlière
  2026-04-15 20:59 ` [PATCH bpf-next v5 01/11] selftests/bpf: Add BPF_STRICT_BUILD toggle Ricardo B. Marlière
                   ` (10 more replies)
  0 siblings, 11 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

Currently the BPF selftests can only be built by using the minimum kernel
configuration defined in tools/testing/selftests/bpf/config*. This poses a
problem in distribution kernels that may have some of the flags disabled or
set as module. For example, we have been running the tests regularly in
openSUSE Tumbleweed [1] [2] but to work around this fact we created a
special package [3] that build the tests against an auxiliary vmlinux with
the BPF Kconfig. We keep a list of known issues that may happen due to,
amongst other things, configuration mismatches [4] [5].

The maintenance of this package is far from ideal, especially for
enterprise kernels. The goal of this series is to enable the common usecase
of running the following in any system:

```sh
make -C tools/testing/selftests install \
     SKIP_TARGETS= \
     TARGETS=bpf \
     BPF_STRICT_BUILD=0 \
     O=/lib/modules/$(uname -r)/build
```

As an example, the following script targeting a minimal config can be used
for testing:

```sh
make defconfig
scripts/config --file .config \
               --enable DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT \
               --enable DEBUG_INFO_BTF \
               --enable BPF_SYSCALL \
               --enable BPF_JIT
make olddefconfig
make -j$(nproc)
make -j$(nproc) -C tools/testing/selftests install \
     SKIP_TARGETS= \
     TARGETS=bpf \
     BPF_STRICT_BUILD=0
```

This produces a test_progs binary with 583 subtests, against the total of
714. Many of them will still fail or be skipped at runtime due to lack of
symbols, but at least there will be a clear way of building the tests.

[1]: https://openqa.opensuse.org/tests/5811715
[2]: https://openqa.opensuse.org/tests/5811730
[3]: https://src.opensuse.org/rmarliere/kselftests
[4]: https://github.com/openSUSE/kernel-qe/blob/main/kselftests_known_issues.yaml
[5]: https://openqa.opensuse.org/tests/5811730/logfile?filename=run_kselftests-config_mismatches.txt

Assisted-by: {codex,claude}
Tested-by: Alan Maguire <alan.maguire@oracle.com>
Signed-off-by: Ricardo B. Marliere <rbm@suse.com>
---
Changes in v5:
- Add BPF_STRICT_BUILD toggle as patch 1 so every subsequent patch
  gates tolerance behind PERMISSIVE from the start, making the series
  bisectable with strict-by-default at every point
- Fix O= commit message; make parent cp conditional (patch 2)
- Tolerate linked skeleton failures (patch 3)
- Skip feature detection for emit_tests (patch 4)
- Clarify bench is all-or-nothing in commit message (patch 8)
- Move stack_mprotect() to testing_helpers.c, drop weak stubs (patch 9)
- Report not-built tests as "SKIP (not built)" in output (patch 10)
- Drop overly broad 2>/dev/null || true from install rsync; rely solely
  on --ignore-missing-args which already handles absent files (patch 11)
- Link to v4: https://patch.msgid.link/20260406-selftests-bpf_misconfig-v4-0-9914f50efdf7@suse.com

Changes in v4:
- Drop the test_kmods kselftest module flow patch: lib.mk gen_mods_dir
  invokes $(MAKE) -C $(TEST_GEN_MODS_DIR) without forwarding
  RESOLVE_BTFIDS, breaking ASAN and GCC BPF CI builds (Makefile.modfinal
  cannot find resolve_btfids in the kbuild output tree)
- Link to v3:
  https://patch.msgid.link/20260406-selftests-bpf_misconfig-v3-0-587a1114263c@suse.com

Changes in v3:
- Split test_kmods patch into two: fix KDIR handling (O= passthrough,
  EXTRA_CFLAGS/EXTRA_LDFLAGS clearing) and wire into lib.mk via
  TEST_GEN_MODS_DIR
- Pass O= through to the kernel module build so artifacts land in the
  output tree, not the source tree
- Clear EXTRA_CFLAGS and EXTRA_LDFLAGS when invoking the kernel build to
  prevent host flags (e.g. -static) leaking into module compilation
- Replace the bespoke test_kmods pattern rule with lib.mk module
  infrastructure (TEST_GEN_MODS_DIR); lib.mk now drives build and clean
  lifecycle
- Make the .ko copy step resilient: emit SKIP instead of failing when a
  module is absent
- Expand the uprobe weak stub comment in bpf_cookie.c to explain why
  noinline is required
- Link to v2:
  https://patch.msgid.link/20260403-selftests-bpf_misconfig-v2-0-f06700380a9d@suse.com

Changes in v2:
- Skip test_kmods build/clean when KDIR directory does not exist
- Use `Module.symvers` instead of `.config` for in-tree detection
- Fix skeleton order-only prereqs commit message
- Guard BTFIDS step when .test.o is absent
- Add `__weak stack_mprotect()` stubs in `bpf_cookie.c` and `iters.c`
- Link to v1:
  https://patch.msgid.link/20260401-selftests-bpf_misconfig-v1-0-3ae42c0af76f@suse.com

To: Alexei Starovoitov <ast@kernel.org>
To: Daniel Borkmann <daniel@iogearbox.net>
To: Andrii Nakryiko <andrii@kernel.org>
To: Martin KaFai Lau <martin.lau@linux.dev>
To: Eduard Zingerman <eddyz87@gmail.com>
To: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: Song Liu <song@kernel.org>
To: Yonghong Song <yonghong.song@linux.dev>
To: Jiri Olsa <jolsa@kernel.org>
To: Shuah Khan <shuah@kernel.org>
To: Nathan Chancellor <nathan@kernel.org>
To: Nick Desaulniers <nick.desaulniers+lkml@gmail.com>
To: Bill Wendling <morbo@google.com>
To: Justin Stitt <justinstitt@google.com>
Cc: bpf@vger.kernel.org
Cc: linux-kselftest@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: llvm@lists.linux.dev

---
Ricardo B. Marlière (11):
      selftests/bpf: Add BPF_STRICT_BUILD toggle
      selftests/bpf: Fix test_kmods KDIR to honor O= and distro kernels
      selftests/bpf: Tolerate BPF and skeleton generation failures
      selftests/bpf: Avoid rebuilds when running emit_tests
      selftests/bpf: Make skeleton headers order-only prerequisites of .test.d
      selftests/bpf: Tolerate test file compilation failures
      selftests/bpf: Allow test_progs to link with a partial object set
      selftests/bpf: Tolerate benchmark build failures
      selftests/bpf: Provide weak definitions for cross-test functions
      selftests/bpf: Skip tests whose objects were not built
      selftests/bpf: Tolerate missing files during install

 tools/testing/selftests/bpf/Makefile               | 160 ++++++++++++++-------
 .../testing/selftests/bpf/prog_tests/bpf_cookie.c  |  17 ++-
 tools/testing/selftests/bpf/prog_tests/iters.c     |   3 +-
 tools/testing/selftests/bpf/prog_tests/test_lsm.c  |  22 ---
 tools/testing/selftests/bpf/test_kmods/Makefile    |  24 +++-
 tools/testing/selftests/bpf/test_progs.c           |  44 +++++-
 tools/testing/selftests/bpf/test_progs.h           |   1 +
 tools/testing/selftests/bpf/testing_helpers.c      |  17 +++
 tools/testing/selftests/bpf/testing_helpers.h      |   1 +
 9 files changed, 199 insertions(+), 90 deletions(-)
---
base-commit: 1f5ffc672165ff851063a5fd044b727ab2517ae3
change-id: 20260401-selftests-bpf_misconfig-4c33ef5c56da

Best regards,
--  
Ricardo B. Marlière <rbm@suse.com>


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH bpf-next v5 01/11] selftests/bpf: Add BPF_STRICT_BUILD toggle
  2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
@ 2026-04-15 20:59 ` Ricardo B. Marlière
  2026-04-15 20:59 ` [PATCH bpf-next v5 02/11] selftests/bpf: Fix test_kmods KDIR to honor O= and distro kernels Ricardo B. Marlière
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

Add BPF_STRICT_BUILD (default 1) to control whether BPF compilation
failures are fatal. When set to 0, failures are tolerated and skipped
objects are reported, as implemented by subsequent patches in this
series. When set to 1 (the default), the build fails on any error,
preserving the existing behavior for CI and direct builds.

Users can opt in to permissive mode on the command line:

  make -C tools/testing/selftests \
       TARGETS=bpf SKIP_TARGETS= BPF_STRICT_BUILD=0

Suggested-by: Alan Maguire <alan.maguire@oracle.com>
Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 tools/testing/selftests/bpf/Makefile | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 78e60040811e..c8ba8ccc2c6d 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -44,6 +44,12 @@ SKIP_LLVM	?=
 SKIP_LIBBFD	?=
 SKIP_CRYPTO	?=
 
+# When BPF_STRICT_BUILD is 1, any BPF object, skeleton, test object, or
+# benchmark compilation failure is fatal. Set to 0 to tolerate failures
+# and continue building the remaining tests.
+BPF_STRICT_BUILD ?= 1
+PERMISSIVE := $(filter 0,$(BPF_STRICT_BUILD))
+
 ifeq ($(srctree),)
 srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH bpf-next v5 02/11] selftests/bpf: Fix test_kmods KDIR to honor O= and distro kernels
  2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
  2026-04-15 20:59 ` [PATCH bpf-next v5 01/11] selftests/bpf: Add BPF_STRICT_BUILD toggle Ricardo B. Marlière
@ 2026-04-15 20:59 ` Ricardo B. Marlière
  2026-04-15 21:18   ` sashiko-bot
  2026-04-15 21:43   ` bot+bpf-ci
  2026-04-15 20:59 ` [PATCH bpf-next v5 03/11] selftests/bpf: Tolerate BPF and skeleton generation failures Ricardo B. Marlière
                   ` (8 subsequent siblings)
  10 siblings, 2 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

test_kmods/Makefile always pointed KDIR at the kernel source tree root,
ignoring O= and KBUILD_OUTPUT. On distro kernels where the source tree has
not been built, the Makefile had no fallback and would fail
unconditionally.

When O= or KBUILD_OUTPUT is set, pass it through so kbuild can locate the
correct kernel build directory (Module.symvers, scripts, etc.). Note that
the module artifacts themselves still land in the M= directory, which is
test_kmods/; O= only controls where kbuild finds its build infrastructure.
Fall back to /lib/modules/$(uname -r)/build when neither an explicit build
directory nor an in-tree Module.symvers is present.

Guard both all and clean against a missing KDIR so the step is silently
skipped rather than fatal. Make the parent Makefile's cp conditional so it
does not abort when modules were not built.

Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 tools/testing/selftests/bpf/Makefile            |  2 +-
 tools/testing/selftests/bpf/test_kmods/Makefile | 24 +++++++++++++++++++++---
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index c8ba8ccc2c6d..5c4cdf1dafc8 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -296,7 +296,7 @@ $(addprefix test_kmods/,$(subst .ko,%ko,$(TEST_KMODS))): $(VMLINUX_BTF) $(RESOLV
 
 $(TEST_KMOD_TARGETS): $(addprefix test_kmods/,$(TEST_KMODS))
 	$(call msg,MOD,,$@)
-	$(Q)cp test_kmods/$(@F) $@
+	$(Q)$(if $(PERMISSIVE),if [ -f test_kmods/$(@F) ]; then )cp test_kmods/$(@F) $@$(if $(PERMISSIVE),; fi)
 
 
 DEFAULT_BPFTOOL := $(HOST_SCRATCH_DIR)/sbin/bpftool
diff --git a/tools/testing/selftests/bpf/test_kmods/Makefile b/tools/testing/selftests/bpf/test_kmods/Makefile
index 63c4d3f6a12f..10f202bd0d8c 100644
--- a/tools/testing/selftests/bpf/test_kmods/Makefile
+++ b/tools/testing/selftests/bpf/test_kmods/Makefile
@@ -1,5 +1,7 @@
 TEST_KMOD_DIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
-KDIR ?= $(abspath $(TEST_KMOD_DIR)/../../../../..)
+SRCTREE_KDIR := $(abspath $(TEST_KMOD_DIR)/../../../../..)
+KMOD_O := $(or $(O),$(KBUILD_OUTPUT))
+KDIR ?= $(if $(KMOD_O),$(SRCTREE_KDIR),$(if $(wildcard $(SRCTREE_KDIR)/Module.symvers),$(SRCTREE_KDIR),/lib/modules/$(shell uname -r)/build))
 
 ifeq ($(V),1)
 Q =
@@ -14,8 +16,24 @@ $(foreach m,$(MODULES),$(eval obj-m += $(m:.ko=.o)))
 
 CFLAGS_bpf_testmod.o = -I$(src)
 
+# When BPF_STRICT_BUILD != 0, a missing KDIR is fatal (the default).
+# When permissive, skip silently.
+PERMISSIVE := $(filter 0,$(BPF_STRICT_BUILD))
+
 all:
-	$(Q)$(MAKE) -C $(KDIR) M=$(TEST_KMOD_DIR) modules
+ifeq ($(PERMISSIVE),)
+	$(Q)$(MAKE) -C $(KDIR) $(if $(KMOD_O),O=$(KMOD_O),KBUILD_OUTPUT=) \
+		M=$(TEST_KMOD_DIR) modules
+else ifneq ("$(wildcard $(KDIR))", "")
+	$(Q)$(MAKE) -C $(KDIR) $(if $(KMOD_O),O=$(KMOD_O),KBUILD_OUTPUT=) \
+		M=$(TEST_KMOD_DIR) modules
+endif
 
 clean:
-	$(Q)$(MAKE) -C $(KDIR) M=$(TEST_KMOD_DIR) clean
+ifeq ($(PERMISSIVE),)
+	$(Q)$(MAKE) -C $(KDIR) $(if $(KMOD_O),O=$(KMOD_O),KBUILD_OUTPUT=) \
+		M=$(TEST_KMOD_DIR) clean
+else ifneq ("$(wildcard $(KDIR))", "")
+	$(Q)$(MAKE) -C $(KDIR) $(if $(KMOD_O),O=$(KMOD_O),KBUILD_OUTPUT=) \
+		M=$(TEST_KMOD_DIR) clean
+endif

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH bpf-next v5 03/11] selftests/bpf: Tolerate BPF and skeleton generation failures
  2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
  2026-04-15 20:59 ` [PATCH bpf-next v5 01/11] selftests/bpf: Add BPF_STRICT_BUILD toggle Ricardo B. Marlière
  2026-04-15 20:59 ` [PATCH bpf-next v5 02/11] selftests/bpf: Fix test_kmods KDIR to honor O= and distro kernels Ricardo B. Marlière
@ 2026-04-15 20:59 ` Ricardo B. Marlière
  2026-04-15 21:15   ` sashiko-bot
  2026-04-15 21:43   ` bot+bpf-ci
  2026-04-15 20:59 ` [PATCH bpf-next v5 04/11] selftests/bpf: Avoid rebuilds when running emit_tests Ricardo B. Marlière
                   ` (7 subsequent siblings)
  10 siblings, 2 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

Some BPF programs cannot be built on distro kernels because required BTF
types or features are missing. A single failure currently aborts the
selftests/bpf build.

Make BPF object and skeleton generation best effort: emit SKIP-BPF or
SKIP-SKEL, remove failed outputs so downstream rules can detect absence,
and continue with remaining tests. Apply the same tolerance to linked
skeletons (TRUNNER_BPF_SKELS_LINKED), which depend on multiple .bpf.o files
and would otherwise abort the build when any dependency is missing.

Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 tools/testing/selftests/bpf/Makefile | 104 +++++++++++++++++++++++------------
 1 file changed, 69 insertions(+), 35 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 5c4cdf1dafc8..a305d13409e4 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -477,22 +477,26 @@ $(OUTPUT)/cgroup_getset_retval_hooks.o: cgroup_getset_retval_hooks.h
 # $4 - binary name
 define CLANG_BPF_BUILD_RULE
 	$(call msg,CLNG-BPF,$4,$2)
-	$(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v3 -o $2
+	$(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v3 -o $2 $(if $(PERMISSIVE),|| \
+		($(RM) $2; printf '  %-12s %s\n' 'SKIP-BPF' '$(notdir $2)' 1>&2))
 endef
 # Similar to CLANG_BPF_BUILD_RULE, but with disabled alu32
 define CLANG_NOALU32_BPF_BUILD_RULE
 	$(call msg,CLNG-BPF,$4,$2)
-	$(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v2 -o $2
+	$(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v2 -o $2 $(if $(PERMISSIVE),|| \
+		($(RM) $2; printf '  %-12s %s\n' 'SKIP-BPF' '$(notdir $2)' 1>&2))
 endef
 # Similar to CLANG_BPF_BUILD_RULE, but with cpu-v4
 define CLANG_CPUV4_BPF_BUILD_RULE
 	$(call msg,CLNG-BPF,$4,$2)
-	$(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v4 -o $2
+	$(Q)$(CLANG) $3 -O2 $(BPF_TARGET_ENDIAN) -c $1 -mcpu=v4 -o $2 $(if $(PERMISSIVE),|| \
+		($(RM) $2; printf '  %-12s %s\n' 'SKIP-BPF' '$(notdir $2)' 1>&2))
 endef
 # Build BPF object using GCC
 define GCC_BPF_BUILD_RULE
 	$(call msg,GCC-BPF,$4,$2)
-	$(Q)$(BPF_GCC) $3 -DBPF_NO_PRESERVE_ACCESS_INDEX -Wno-attributes -O2 -c $1 -o $2
+	$(Q)$(BPF_GCC) $3 -DBPF_NO_PRESERVE_ACCESS_INDEX -Wno-attributes -O2 -c $1 -o $2 $(if $(PERMISSIVE),|| \
+		($(RM) $2; printf '  %-12s %s\n' 'SKIP-BPF' '$(notdir $2)' 1>&2))
 endef
 
 SKEL_BLACKLIST := btf__% test_pinning_invalid.c test_sk_assign.c
@@ -598,47 +602,77 @@ $(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.bpf.o:				\
 					  $$($$<-$2-CFLAGS),$(TRUNNER_BINARY))
 
 $(TRUNNER_BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
-	$$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)
-	$(Q)$$(BPFTOOL) gen object $$(<:.o=.linked1.o) $$<
-	$(Q)$$(BPFTOOL) gen object $$(<:.o=.linked2.o) $$(<:.o=.linked1.o)
-	$(Q)$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o)
-	$(Q)diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
-	$(Q)$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$@
-	$(Q)$$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h)
-	$(Q)rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
+	$(Q)$(if $(PERMISSIVE),if [ ! -f $$< ]; then			\
+		printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
+		exit 0;							\
+	fi;)								\
+	printf '  %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2; \
+	$$(BPFTOOL) gen object $$(<:.o=.linked1.o) $$< &&		\
+	$$(BPFTOOL) gen object $$(<:.o=.linked2.o) $$(<:.o=.linked1.o) && \
+	$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o) && \
+	diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o) &&		\
+	$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$@ && \
+	$$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h) $(if $(PERMISSIVE),|| { \
+		$$(RM) $$@ $$(@:.skel.h=.subskel.h); \
+		printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
+	}); \
+	rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
 
 $(TRUNNER_BPF_LSKELS): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
-	$$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)
-	$(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked1.o) $$<
-	$(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked2.o) $$(<:.o=.llinked1.o)
-	$(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o)
-	$(Q)diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
-	$(Q)$$(BPFTOOL) gen skeleton -L $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@
-	$(Q)rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
+	$(Q)$(if $(PERMISSIVE),if [ ! -f $$< ]; then			\
+		printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
+		exit 0;							\
+	fi;)								\
+	printf '  %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2; \
+	$$(BPFTOOL) gen object $$(<:.o=.llinked1.o) $$< &&		\
+	$$(BPFTOOL) gen object $$(<:.o=.llinked2.o) $$(<:.o=.llinked1.o) && \
+	$$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o) && \
+	diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o) &&		\
+	$$(BPFTOOL) gen skeleton -L $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@ $(if $(PERMISSIVE),|| { \
+		$$(RM) $$@; \
+		printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
+	}); \
+	rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
 
 $(TRUNNER_BPF_LSKELS_SIGNED): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
-	$$(call msg,GEN-SKEL,$(TRUNNER_BINARY) (signed),$$@)
-	$(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked1.o) $$<
-	$(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked2.o) $$(<:.o=.llinked1.o)
-	$(Q)$$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o)
-	$(Q)diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
-	$(Q)$$(BPFTOOL) gen skeleton $(LSKEL_SIGN) $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@
-	$(Q)rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
+	$(Q)$(if $(PERMISSIVE),if [ ! -f $$< ]; then			\
+		printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
+		exit 0;							\
+	fi;)								\
+	printf '  %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY) (signed)] $$(notdir $$@)' 1>&2; \
+	$$(BPFTOOL) gen object $$(<:.o=.llinked1.o) $$< &&		\
+	$$(BPFTOOL) gen object $$(<:.o=.llinked2.o) $$(<:.o=.llinked1.o) && \
+	$$(BPFTOOL) gen object $$(<:.o=.llinked3.o) $$(<:.o=.llinked2.o) && \
+	diff $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o) &&		\
+	$$(BPFTOOL) gen skeleton $(LSKEL_SIGN) $$(<:.o=.llinked3.o) name $$(notdir $$(<:.bpf.o=_lskel)) > $$@ $(if $(PERMISSIVE),|| { \
+		$$(RM) $$@; \
+		printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
+	}); \
+	rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
 
 $(LINKED_BPF_OBJS): %: $(TRUNNER_OUTPUT)/%
 
 # .SECONDEXPANSION here allows to correctly expand %-deps variables as prerequisites
 .SECONDEXPANSION:
 $(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_OUTPUT)/%: $$$$(%-deps) $(BPFTOOL) | $(TRUNNER_OUTPUT)
-	$$(call msg,LINK-BPF,$(TRUNNER_BINARY),$$(@:.skel.h=.bpf.o))
-	$(Q)$$(BPFTOOL) gen object $$(@:.skel.h=.linked1.o) $$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps))
-	$(Q)$$(BPFTOOL) gen object $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked1.o)
-	$(Q)$$(BPFTOOL) gen object $$(@:.skel.h=.linked3.o) $$(@:.skel.h=.linked2.o)
-	$(Q)diff $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked3.o)
-	$$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)
-	$(Q)$$(BPFTOOL) gen skeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$@
-	$(Q)$$(BPFTOOL) gen subskeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$(@:.skel.h=.subskel.h)
-	$(Q)rm -f $$(@:.skel.h=.linked1.o) $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked3.o)
+	$(Q)$(if $(PERMISSIVE),for f in $$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps)); do \
+		if [ ! -f $$$$f ]; then						\
+			printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
+			exit 0;							\
+		fi;								\
+	done;)									\
+	printf '  %-12s %s\n' 'LINK-BPF' '[$(TRUNNER_BINARY)] $$(notdir $$(@:.skel.h=.bpf.o))' 1>&2; \
+	$$(BPFTOOL) gen object $$(@:.skel.h=.linked1.o) $$(addprefix $(TRUNNER_OUTPUT)/,$$($$(@F)-deps)) && \
+	$$(BPFTOOL) gen object $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked1.o) && \
+	$$(BPFTOOL) gen object $$(@:.skel.h=.linked3.o) $$(@:.skel.h=.linked2.o) && \
+	diff $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked3.o) &&	\
+	printf '  %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2 && \
+	$$(BPFTOOL) gen skeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$@ && \
+	$$(BPFTOOL) gen subskeleton $$(@:.skel.h=.linked3.o) name $$(notdir $$(@:.skel.h=)) > $$(@:.skel.h=.subskel.h) $(if $(PERMISSIVE),|| { \
+		$$(RM) $$@ $$(@:.skel.h=.subskel.h);			\
+		printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
+	});									\
+	rm -f $$(@:.skel.h=.linked1.o) $$(@:.skel.h=.linked2.o) $$(@:.skel.h=.linked3.o)
 
 # When the compiler generates a %.d file, only skel basenames (not
 # full paths) are specified as prerequisites for corresponding %.o

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH bpf-next v5 04/11] selftests/bpf: Avoid rebuilds when running emit_tests
  2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
                   ` (2 preceding siblings ...)
  2026-04-15 20:59 ` [PATCH bpf-next v5 03/11] selftests/bpf: Tolerate BPF and skeleton generation failures Ricardo B. Marlière
@ 2026-04-15 20:59 ` Ricardo B. Marlière
  2026-04-15 20:59 ` [PATCH bpf-next v5 05/11] selftests/bpf: Make skeleton headers order-only prerequisites of .test.d Ricardo B. Marlière
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

emit_tests is used while installing selftests to generate the kselftest
list. Pulling in .d files for this goal can trigger BPF rebuild rules and
mix build output into list generation.

Skip dependency file inclusion for emit_tests, like clean goals, so list
generation stays side-effect free. Also add emit_tests to
NON_CHECK_FEAT_TARGETS so that feature detection is skipped; without this,
Makefile.feature's $(info) output leaks into stdout and corrupts the test
list captured by the top-level selftests Makefile.

Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 tools/testing/selftests/bpf/Makefile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index a305d13409e4..040617c01bbb 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -164,7 +164,7 @@ endef
 
 include ../lib.mk
 
-NON_CHECK_FEAT_TARGETS := clean docs-clean
+NON_CHECK_FEAT_TARGETS := clean docs-clean emit_tests
 CHECK_FEAT := $(filter-out $(NON_CHECK_FEAT_TARGETS),$(or $(MAKECMDGOALS), "none"))
 ifneq ($(CHECK_FEAT),)
 FEATURE_USER := .selftests
@@ -719,7 +719,7 @@ $(TRUNNER_TEST_OBJS:.o=.d): $(TRUNNER_OUTPUT)/%.test.d:			\
 			    $(TRUNNER_BPF_SKELS_LINKED)			\
 			    $$(BPFOBJ) | $(TRUNNER_OUTPUT)
 
-ifeq ($(filter clean docs-clean,$(MAKECMDGOALS)),)
+ifeq ($(filter clean docs-clean emit_tests,$(MAKECMDGOALS)),)
 include $(wildcard $(TRUNNER_TEST_OBJS:.o=.d))
 endif
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH bpf-next v5 05/11] selftests/bpf: Make skeleton headers order-only prerequisites of .test.d
  2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
                   ` (3 preceding siblings ...)
  2026-04-15 20:59 ` [PATCH bpf-next v5 04/11] selftests/bpf: Avoid rebuilds when running emit_tests Ricardo B. Marlière
@ 2026-04-15 20:59 ` Ricardo B. Marlière
  2026-04-15 20:59 ` [PATCH bpf-next v5 06/11] selftests/bpf: Tolerate test file compilation failures Ricardo B. Marlière
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

The .test.d dependency files are generated by the C preprocessor and list
the headers each test file actually #includes. Skeleton headers appear in
those generated lists, so the .test.o -> .skel.h dependency is already
tracked by the .d file content.

Making skeletons order-only prerequisites of .test.d means that a missing
or skipped skeleton does not prevent .test.d generation, and regenerating a
skeleton does not force .test.d to be recreated. This avoids unnecessary
recompilation and, more importantly, avoids build errors when a skeleton
was intentionally skipped due to a BPF compilation failure.

Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 tools/testing/selftests/bpf/Makefile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 040617c01bbb..3c9d61023414 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -713,11 +713,11 @@ $(TRUNNER_TEST_OBJS): $(TRUNNER_OUTPUT)/%.test.o:			\
 $(TRUNNER_TEST_OBJS:.o=.d): $(TRUNNER_OUTPUT)/%.test.d:			\
 			    $(TRUNNER_TESTS_DIR)/%.c			\
 			    $(TRUNNER_EXTRA_HDRS)			\
+			    $$(BPFOBJ) | $(TRUNNER_OUTPUT)		\
 			    $(TRUNNER_BPF_SKELS)			\
 			    $(TRUNNER_BPF_LSKELS)			\
 			    $(TRUNNER_BPF_LSKELS_SIGNED)		\
-			    $(TRUNNER_BPF_SKELS_LINKED)			\
-			    $$(BPFOBJ) | $(TRUNNER_OUTPUT)
+			    $(TRUNNER_BPF_SKELS_LINKED)
 
 ifeq ($(filter clean docs-clean emit_tests,$(MAKECMDGOALS)),)
 include $(wildcard $(TRUNNER_TEST_OBJS:.o=.d))

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH bpf-next v5 06/11] selftests/bpf: Tolerate test file compilation failures
  2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
                   ` (4 preceding siblings ...)
  2026-04-15 20:59 ` [PATCH bpf-next v5 05/11] selftests/bpf: Make skeleton headers order-only prerequisites of .test.d Ricardo B. Marlière
@ 2026-04-15 20:59 ` Ricardo B. Marlière
  2026-04-15 20:59 ` [PATCH bpf-next v5 07/11] selftests/bpf: Allow test_progs to link with a partial object set Ricardo B. Marlière
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

Individual test files may fail to compile when headers or kernel features
required by that test are absent. Currently this aborts the entire build.

Make the per-test compilation non-fatal: remove the output object on
failure and print a SKIP-TEST marker to stderr. Guard the BTFIDS
post-processing step so it is skipped when the object file is absent. The
linker step will later ignore absent objects, allowing the remaining tests
to build and run.

Use plain printf and $(Q) instead of $(call msg,...) in the BTFIDS block:
the msg macro expands to @printf which is a make-recipe construct and is
invalid as a shell command inside an if-then-fi body; $(Q) restores echo
suppression at the recipe level where it is meaningful.

Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 tools/testing/selftests/bpf/Makefile | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 3c9d61023414..ee7bbfcd661b 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -704,11 +704,14 @@ $(TRUNNER_TEST_OBJS): $(TRUNNER_OUTPUT)/%.test.o:			\
 		      $(TRUNNER_TESTS_DIR)/%.c				\
 		      | $(TRUNNER_OUTPUT)/%.test.d
 	$$(call msg,TEST-OBJ,$(TRUNNER_BINARY),$$@)
-	$(Q)cd $$(@D) && $$(CC) -I. $$(CFLAGS) -MMD -MT $$@ -c $(CURDIR)/$$< $$(LDLIBS) -o $$(@F)
+	$(Q)cd $$(@D) && $$(CC) -I. $$(CFLAGS) -MMD -MT $$@ -c $(CURDIR)/$$< $$(LDLIBS) -o $$(@F) $(if $(PERMISSIVE),|| \
+		($(RM) $$(@F); printf '  %-12s %s\n' 'SKIP-TEST' '$$(notdir $$@)' 1>&2))
 	$$(if $$(TEST_NEEDS_BTFIDS),						\
-		$$(call msg,BTFIDS,$(TRUNNER_BINARY),$$@)			\
+		$(Q)if [ -f $$@ ]; then						\
+		printf '  %-8s%s %s\n' "BTFIDS" " [$(TRUNNER_BINARY)]" "$$(notdir $$@)"; \
 		$(RESOLVE_BTFIDS) --btf $(TRUNNER_OUTPUT)/btf_data.bpf.o $$@;	\
-		$(RESOLVE_BTFIDS) --patch_btfids $$@.BTF_ids $$@)
+		$(RESOLVE_BTFIDS) --patch_btfids $$@.BTF_ids $$@;		\
+		fi)
 
 $(TRUNNER_TEST_OBJS:.o=.d): $(TRUNNER_OUTPUT)/%.test.d:			\
 			    $(TRUNNER_TESTS_DIR)/%.c			\

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH bpf-next v5 07/11] selftests/bpf: Allow test_progs to link with a partial object set
  2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
                   ` (5 preceding siblings ...)
  2026-04-15 20:59 ` [PATCH bpf-next v5 06/11] selftests/bpf: Tolerate test file compilation failures Ricardo B. Marlière
@ 2026-04-15 20:59 ` Ricardo B. Marlière
  2026-04-15 21:19   ` sashiko-bot
  2026-04-15 21:54   ` bot+bpf-ci
  2026-04-15 20:59 ` [PATCH bpf-next v5 08/11] selftests/bpf: Tolerate benchmark build failures Ricardo B. Marlière
                   ` (3 subsequent siblings)
  10 siblings, 2 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

When individual test files are skipped due to compilation failures, their
.test.o files are absent. The linker step currently lists all expected
.test.o files as explicit prerequisites, so make considers any missing one
an error.

Move TRUNNER_TEST_OBJS to the order-only prerequisite list so that their
absence does not prevent linking. Use $(wildcard ...) in the filter
expression passed to the linker so that only the objects that were actually
built are linked in.

Place the wildcard expansion before $^ in the filter to preserve the
original link order: test objects must precede libbpf.a so that GNU ld,
which scans static archives left-to-right, pulls in archive members that
are referenced exclusively by test objects (e.g. ring_buffer__new from
ringbuf.c).

Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 tools/testing/selftests/bpf/Makefile | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index ee7bbfcd661b..128ea61fd986 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -754,14 +754,14 @@ endif
 # some X.test.o files have runtime dependencies on Y.bpf.o files
 $(OUTPUT)/$(TRUNNER_BINARY): | $(TRUNNER_BPF_OBJS)
 
-$(OUTPUT)/$(TRUNNER_BINARY): $(TRUNNER_TEST_OBJS)			\
-			     $(TRUNNER_EXTRA_OBJS) $$(BPFOBJ)		\
+$(OUTPUT)/$(TRUNNER_BINARY): $(TRUNNER_EXTRA_OBJS) $$(BPFOBJ)		\
 			     $(TRUNNER_LIB_OBJS)			\
 			     $(TRUNNER_BPFTOOL)				\
 			     $(OUTPUT)/veristat				\
-			     | $(TRUNNER_BINARY)-extras
+			     | $(TRUNNER_BINARY)-extras			\
+			     $(TRUNNER_TEST_OBJS)
 	$$(call msg,BINARY,,$$@)
-	$(Q)$$(CC) $$(CFLAGS) $$(filter %.a %.o,$$^) $$(LDLIBS) $$(LLVM_LDLIBS) $$(LDFLAGS) $$(LLVM_LDFLAGS) -o $$@
+	$(Q)$$(CC) $$(CFLAGS) $$(filter %.a %.o,$(if $(PERMISSIVE),$$(wildcard $(TRUNNER_TEST_OBJS)),$(TRUNNER_TEST_OBJS)) $$^) $$(LDLIBS) $$(LLVM_LDLIBS) $$(LDFLAGS) $$(LLVM_LDFLAGS) -o $$@
 	$(Q)ln -sf $(if $2,..,.)/tools/build/bpftool/$(USE_BOOTSTRAP)bpftool \
 		   $(OUTPUT)/$(if $2,$2/)bpftool
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH bpf-next v5 08/11] selftests/bpf: Tolerate benchmark build failures
  2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
                   ` (6 preceding siblings ...)
  2026-04-15 20:59 ` [PATCH bpf-next v5 07/11] selftests/bpf: Allow test_progs to link with a partial object set Ricardo B. Marlière
@ 2026-04-15 20:59 ` Ricardo B. Marlière
  2026-04-15 20:59 ` [PATCH bpf-next v5 09/11] selftests/bpf: Provide weak definitions for cross-test functions Ricardo B. Marlière
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

Benchmark objects depend on skeletons that may be missing when some BPF
programs fail to build. In that case, benchmark object compilation or final
bench linking should not abort the full selftests/bpf build.

Keep both steps non-fatal, emit SKIP-BENCH or SKIP-LINK, and remove failed
outputs so stale objects or binaries are not reused by later incremental
builds. Note that because bench.c statically references every benchmark via
extern symbols, partial linking is not possible: if any single benchmark
object fails, the entire bench binary is skipped. This is by design -- the
error handler catches all compilation failures including genuine ones, but
those are caught by full-config CI runs.

Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 tools/testing/selftests/bpf/Makefile | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 128ea61fd986..163552458327 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -891,7 +891,8 @@ $(OUTPUT)/test_cpp: test_cpp.cpp $(OUTPUT)/test_core_extern.skel.h $(BPFOBJ)
 # Benchmark runner
 $(OUTPUT)/bench_%.o: benchs/bench_%.c bench.h $(BPFOBJ)
 	$(call msg,CC,,$@)
-	$(Q)$(CC) $(CFLAGS) -O2 -c $(filter %.c,$^) $(LDLIBS) -o $@
+	$(Q)$(CC) $(CFLAGS) -O2 -c $(filter %.c,$^) $(LDLIBS) -o $@ $(if $(PERMISSIVE),|| \
+		($(RM) $@; printf '  %-12s %s\n' 'SKIP-BENCH' '$(notdir $@)' 1>&2))
 $(OUTPUT)/bench_rename.o: $(OUTPUT)/test_overhead.skel.h
 $(OUTPUT)/bench_trigger.o: $(OUTPUT)/trigger_bench.skel.h
 $(OUTPUT)/bench_ringbufs.o: $(OUTPUT)/ringbuf_bench.skel.h \
@@ -934,7 +935,8 @@ $(OUTPUT)/bench: $(OUTPUT)/bench.o \
 		 $(OUTPUT)/usdt_2.o \
 		 #
 	$(call msg,BINARY,,$@)
-	$(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(filter %.a %.o,$^) $(LDLIBS) -o $@
+	$(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(filter %.a %.o,$(if $(PERMISSIVE),$(wildcard $^),$^)) $(LDLIBS) -o $@ $(if $(PERMISSIVE),|| \
+		($(RM) $@; printf '  %-12s %s\n' 'SKIP-LINK' '$(notdir $@) (some benchmarks may have been skipped)' 1>&2))
 
 # This works around GCC warning about snprintf truncating strings like:
 #

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH bpf-next v5 09/11] selftests/bpf: Provide weak definitions for cross-test functions
  2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
                   ` (7 preceding siblings ...)
  2026-04-15 20:59 ` [PATCH bpf-next v5 08/11] selftests/bpf: Tolerate benchmark build failures Ricardo B. Marlière
@ 2026-04-15 20:59 ` Ricardo B. Marlière
  2026-04-15 20:59 ` [PATCH bpf-next v5 10/11] selftests/bpf: Skip tests whose objects were not built Ricardo B. Marlière
  2026-04-15 20:59 ` [PATCH bpf-next v5 11/11] selftests/bpf: Tolerate missing files during install Ricardo B. Marlière
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

Some test files reference functions defined in other translation units that
may not be compiled when skeletons are missing. Replace forward
declarations of uprobe_multi_func_{1,2,3}() with weak no-op stubs so the
linker resolves them regardless of which objects are present.

Move stack_mprotect() from test_lsm.c into testing_helpers.c so it is
always available. The previous weak-stub approach returned 0, which would
cause callers expecting -1/EPERM to fail their assertions
deterministically. Having the real implementation in a shared utility
avoids this problem entirely.

Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 .../testing/selftests/bpf/prog_tests/bpf_cookie.c  | 17 +++++++++++------
 tools/testing/selftests/bpf/prog_tests/iters.c     |  3 +--
 tools/testing/selftests/bpf/prog_tests/test_lsm.c  | 22 ----------------------
 tools/testing/selftests/bpf/testing_helpers.c      | 17 +++++++++++++++++
 tools/testing/selftests/bpf/testing_helpers.h      |  1 +
 5 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
index 35adc3f6d443..5a864cd8ad1b 100644
--- a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c
@@ -252,10 +252,17 @@ static void kprobe_multi_attach_api_subtest(void)
 	kprobe_multi__destroy(skel);
 }
 
-/* defined in prog_tests/uprobe_multi_test.c */
-void uprobe_multi_func_1(void);
-void uprobe_multi_func_2(void);
-void uprobe_multi_func_3(void);
+/*
+ * Weak uprobe target stubs. noinline is required because
+ * uprobe_multi_test_run() takes their addresses to configure the BPF
+ * program's attachment points; an inlined function has no stable
+ * address in the binary to probe. The strong definitions in
+ * uprobe_multi_test.c take precedence when that translation unit is
+ * linked.
+ */
+noinline __weak void uprobe_multi_func_1(void) {}
+noinline __weak void uprobe_multi_func_2(void) {}
+noinline __weak void uprobe_multi_func_3(void) {}
 
 static void uprobe_multi_test_run(struct uprobe_multi *skel)
 {
@@ -574,8 +581,6 @@ static void tracing_subtest(struct test_bpf_cookie *skel)
 		close(fmod_ret_fd);
 }
 
-int stack_mprotect(void);
-
 static void lsm_subtest(struct test_bpf_cookie *skel)
 {
 	__u64 cookie;
diff --git a/tools/testing/selftests/bpf/prog_tests/iters.c b/tools/testing/selftests/bpf/prog_tests/iters.c
index a539980a2fbe..7c0b59fdf498 100644
--- a/tools/testing/selftests/bpf/prog_tests/iters.c
+++ b/tools/testing/selftests/bpf/prog_tests/iters.c
@@ -7,6 +7,7 @@
 #include <unistd.h>
 #include <malloc.h>
 #include <stdlib.h>
+#include <linux/compiler.h>
 #include <test_progs.h>
 #include "cgroup_helpers.h"
 
@@ -202,8 +203,6 @@ static void subtest_task_iters(void)
 	iters_task__destroy(skel);
 }
 
-extern int stack_mprotect(void);
-
 static void subtest_css_task_iters(void)
 {
 	struct iters_css_task *skel = NULL;
diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c b/tools/testing/selftests/bpf/prog_tests/test_lsm.c
index bdc4fc06bc5a..d7495efd4a56 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c
@@ -5,36 +5,14 @@
  */
 
 #include <test_progs.h>
-#include <sys/mman.h>
 #include <sys/wait.h>
 #include <unistd.h>
-#include <malloc.h>
-#include <stdlib.h>
 
 #include "lsm.skel.h"
 #include "lsm_tailcall.skel.h"
 
 char *CMD_ARGS[] = {"true", NULL};
 
-#define GET_PAGE_ADDR(ADDR, PAGE_SIZE)					\
-	(char *)(((unsigned long) (ADDR + PAGE_SIZE)) & ~(PAGE_SIZE-1))
-
-int stack_mprotect(void)
-{
-	void *buf;
-	long sz;
-	int ret;
-
-	sz = sysconf(_SC_PAGESIZE);
-	if (sz < 0)
-		return sz;
-
-	buf = alloca(sz * 3);
-	ret = mprotect(GET_PAGE_ADDR(buf, sz), sz,
-		       PROT_READ | PROT_WRITE | PROT_EXEC);
-	return ret;
-}
-
 int exec_cmd(int *monitored_pid)
 {
 	int child_pid, child_status;
diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c
index 6fbe1e995660..3f7ae76c209b 100644
--- a/tools/testing/selftests/bpf/testing_helpers.c
+++ b/tools/testing/selftests/bpf/testing_helpers.c
@@ -5,6 +5,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/mman.h>
 #include <bpf/bpf.h>
 #include <bpf/libbpf.h>
 #include "disasm.h"
@@ -516,3 +517,19 @@ bool is_jit_enabled(void)
 
 	return enabled;
 }
+
+int stack_mprotect(void)
+{
+	void *buf;
+	long sz;
+	int ret;
+
+	sz = sysconf(_SC_PAGESIZE);
+	if (sz < 0)
+		return sz;
+
+	buf = alloca(sz * 3);
+	ret = mprotect((void *)(((unsigned long)(buf + sz)) & ~(sz - 1)), sz,
+		       PROT_READ | PROT_WRITE | PROT_EXEC);
+	return ret;
+}
diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h
index 2ca2356a0b58..2edc6fb7fc52 100644
--- a/tools/testing/selftests/bpf/testing_helpers.h
+++ b/tools/testing/selftests/bpf/testing_helpers.h
@@ -59,5 +59,6 @@ struct bpf_insn;
 int get_xlated_program(int fd_prog, struct bpf_insn **buf, __u32 *cnt);
 int testing_prog_flags(void);
 bool is_jit_enabled(void);
+int stack_mprotect(void);
 
 #endif /* __TESTING_HELPERS_H */

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH bpf-next v5 10/11] selftests/bpf: Skip tests whose objects were not built
  2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
                   ` (8 preceding siblings ...)
  2026-04-15 20:59 ` [PATCH bpf-next v5 09/11] selftests/bpf: Provide weak definitions for cross-test functions Ricardo B. Marlière
@ 2026-04-15 20:59 ` Ricardo B. Marlière
  2026-04-15 21:11   ` sashiko-bot
  2026-04-15 21:43   ` bot+bpf-ci
  2026-04-15 20:59 ` [PATCH bpf-next v5 11/11] selftests/bpf: Tolerate missing files during install Ricardo B. Marlière
  10 siblings, 2 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

When both run_test and run_serial_test are NULL (because the corresponding
.test.o was not compiled), mark the test as not built instead of fatally
aborting.

Report these tests as "SKIP (not built)" in per-test output and include
them in the skip count so they remain visible in CI results and JSON
output. The summary line shows the not-built count when nonzero:

  Summary: 50/55 PASSED, 5 SKIPPED (3 not built), 0 FAILED

Tests filtered out by -t/-n remain invisible as before; only genuinely
unbuilt tests are surfaced.

Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 tools/testing/selftests/bpf/test_progs.c | 44 ++++++++++++++++++++++++++++----
 tools/testing/selftests/bpf/test_progs.h |  1 +
 2 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
index 7fe16b5131b1..759e76d76c57 100644
--- a/tools/testing/selftests/bpf/test_progs.c
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -165,6 +165,7 @@ struct prog_test_def {
 	void (*run_test)(void);
 	void (*run_serial_test)(void);
 	bool should_run;
+	bool not_built;
 	bool need_cgroup_cleanup;
 	bool should_tmon;
 };
@@ -372,6 +373,8 @@ static void print_test_result(const struct prog_test_def *test, const struct tes
 	fprintf(env.stdout_saved, "#%-*d %s:", TEST_NUM_WIDTH, test->test_num, test->test_name);
 	if (test_state->error_cnt)
 		fprintf(env.stdout_saved, "FAIL");
+	else if (test->not_built)
+		fprintf(env.stdout_saved, "SKIP (not built)");
 	else if (!skipped_cnt)
 		fprintf(env.stdout_saved, "OK");
 	else if (skipped_cnt == subtests_cnt || !subtests_cnt)
@@ -1700,8 +1703,13 @@ static void calculate_summary_and_print_errors(struct test_env *env)
 	if (env->json)
 		fclose(env->json);
 
-	printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n",
-	       succ_cnt, sub_succ_cnt, skip_cnt, fail_cnt);
+	if (env->not_built_cnt)
+		printf("Summary: %d/%d PASSED, %d SKIPPED (%d not built), %d FAILED\n",
+		       succ_cnt, sub_succ_cnt, skip_cnt, env->not_built_cnt,
+		       fail_cnt);
+	else
+		printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n",
+		       succ_cnt, sub_succ_cnt, skip_cnt, fail_cnt);
 
 	env->succ_cnt = succ_cnt;
 	env->sub_succ_cnt = sub_succ_cnt;
@@ -1772,6 +1780,19 @@ static void server_main(void)
 		run_one_test(i);
 	}
 
+	/* mark not-built tests as skipped */
+	for (int i = 0; i < prog_test_cnt; i++) {
+		struct prog_test_def *test = &prog_test_defs[i];
+		struct test_state *state = &test_states[i];
+
+		if (test->not_built) {
+			state->tested = true;
+			state->skip_cnt = 1;
+			env.not_built_cnt++;
+			print_test_result(test, state);
+		}
+	}
+
 	/* generate summary */
 	fflush(stderr);
 	fflush(stdout);
@@ -2049,12 +2070,16 @@ int main(int argc, char **argv)
 		test->should_run = should_run(&env.test_selector,
 					      test->test_num, test->test_name);
 
-		if ((test->run_test == NULL && test->run_serial_test == NULL) ||
-		    (test->run_test != NULL && test->run_serial_test != NULL)) {
+		if (test->run_test && test->run_serial_test) {
 			fprintf(stderr, "Test %d:%s must have either test_%s() or serial_test_%sl() defined.\n",
 				test->test_num, test->test_name, test->test_name, test->test_name);
 			exit(EXIT_ERR_SETUP_INFRA);
 		}
+		if (!test->run_test && !test->run_serial_test) {
+			test->not_built = true;
+			test->should_run = false;
+			continue;
+		}
 		if (test->should_run)
 			test->should_tmon = should_tmon(&env.tmon_selector, test->test_name);
 	}
@@ -2106,9 +2131,18 @@ int main(int argc, char **argv)
 
 	for (i = 0; i < prog_test_cnt; i++) {
 		struct prog_test_def *test = &prog_test_defs[i];
+		struct test_state *state = &test_states[i];
 
-		if (!test->should_run)
+		if (!test->should_run) {
+			if (test->not_built && !env.get_test_cnt &&
+			    !env.list_test_names) {
+				state->tested = true;
+				state->skip_cnt = 1;
+				env.not_built_cnt++;
+				print_test_result(test, state);
+			}
 			continue;
+		}
 
 		if (env.get_test_cnt) {
 			env.succ_cnt++;
diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h
index 1a44467f4310..6ee10360e314 100644
--- a/tools/testing/selftests/bpf/test_progs.h
+++ b/tools/testing/selftests/bpf/test_progs.h
@@ -125,6 +125,7 @@ struct test_env {
 	int sub_succ_cnt; /* successful sub-tests */
 	int fail_cnt; /* total failed tests + sub-tests */
 	int skip_cnt; /* skipped tests */
+	int not_built_cnt; /* tests not built */
 
 	int saved_netns_fd;
 	int workers; /* number of worker process */

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH bpf-next v5 11/11] selftests/bpf: Tolerate missing files during install
  2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
                   ` (9 preceding siblings ...)
  2026-04-15 20:59 ` [PATCH bpf-next v5 10/11] selftests/bpf: Skip tests whose objects were not built Ricardo B. Marlière
@ 2026-04-15 20:59 ` Ricardo B. Marlière
  10 siblings, 0 replies; 20+ messages in thread
From: Ricardo B. Marlière @ 2026-04-15 20:59 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, Alan Maguire,
	Ricardo B. Marliere

With partial builds, some TEST_GEN_FILES entries can be absent at install
time. rsync treats missing source arguments as fatal and aborts kselftest
installation.

Override INSTALL_SINGLE_RULE in selftests/bpf to use --ignore-missing-args,
while keeping the existing bpf-specific INSTALL_RULE extension logic. Also
add --ignore-missing-args to the TEST_INST_SUBDIRS rsync loop so that
subdirectories with no .bpf.o files (e.g. when a test runner flavor was
skipped) do not abort installation.

Note that the INSTALL_SINGLE_RULE override applies globally to all file
categories including static source files (TEST_PROGS, TEST_FILES). These
are version-controlled and should always be present, so the practical risk
is negligible.

Signed-off-by: Ricardo B. Marlière <rbm@suse.com>
---
 tools/testing/selftests/bpf/Makefile | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 163552458327..1f4a8e1f7932 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -969,11 +969,22 @@ EXTRA_CLEAN := $(SCRATCH_DIR) $(HOST_SCRATCH_DIR)			\
 # Delete partially updated (corrupted) files on error
 .DELETE_ON_ERROR:
 
+# When permissive, tell rsync to ignore missing source arguments so that
+# partial builds do not abort installation.
+ifneq ($(PERMISSIVE),)
+override define INSTALL_SINGLE_RULE
+	$(if $(INSTALL_LIST),@mkdir -p $(INSTALL_PATH))
+	$(if $(INSTALL_LIST),rsync -a --copy-unsafe-links --ignore-missing-args $(INSTALL_LIST) $(INSTALL_PATH)/)
+endef
+endif
+
 DEFAULT_INSTALL_RULE := $(INSTALL_RULE)
 override define INSTALL_RULE
 	$(DEFAULT_INSTALL_RULE)
-	@for DIR in $(TEST_INST_SUBDIRS); do		  \
-		mkdir -p $(INSTALL_PATH)/$$DIR;   \
-		rsync -a $(OUTPUT)/$$DIR/*.bpf.o $(INSTALL_PATH)/$$DIR;\
+	@for DIR in $(TEST_INST_SUBDIRS); do				  \
+		mkdir -p $(INSTALL_PATH)/$$DIR;				  \
+		rsync -a $(if $(PERMISSIVE),--ignore-missing-args)	  \
+			$(OUTPUT)/$$DIR/*.bpf.o				  \
+			$(INSTALL_PATH)/$$DIR;				  \
 	done
 endef

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH bpf-next v5 10/11] selftests/bpf: Skip tests whose objects were not built
  2026-04-15 20:59 ` [PATCH bpf-next v5 10/11] selftests/bpf: Skip tests whose objects were not built Ricardo B. Marlière
@ 2026-04-15 21:11   ` sashiko-bot
  2026-04-15 21:43   ` bot+bpf-ci
  1 sibling, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-04-15 21:11 UTC (permalink / raw)
  To: Ricardo B. Marlière; +Cc: bpf

Sashiko AI review found 1 potential issue(s):
- [Medium] Unbuilt tests bypass test filters (e.g., `-t`, `-n`) and are always printed and counted as skipped, breaking test isolation and contradicting the commit message.
--

commit 6ad669628925e7e8627a5068e116b6bbdf0f87d0
Author: Ricardo B. Marlière <rbm@suse.com>

selftests/bpf: Skip tests whose objects were not built

When tests are not compiled, this commit marks them as not built instead
of fatally aborting. It surfaces these unbuilt tests as skipped in the
output so they remain visible in CI results.

> Tests filtered out by -t/-n remain invisible as before; only genuinely
> unbuilt tests are surfaced.

Does the implementation actually keep filtered tests invisible? Looking at
how the flags are set during initialization, it appears unbuilt tests
might bypass the test selector:

> diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
> --- a/tools/testing/selftests/bpf/test_progs.c
> +++ b/tools/testing/selftests/bpf/test_progs.c
> @@ -2049,12 +2070,16 @@ int main(int argc, char **argv)
>  		test->should_run = should_run(&env.test_selector,
>  					      test->test_num, test->test_name);
>  
>  		if (test->run_test && test->run_serial_test) {
>  			fprintf(stderr, "Test %d:%s must have either test_%s() or serial_test_%sl() defined.\n",
>  				test->test_num, test->test_name, test->test_name, test->test_name);
>  			exit(EXIT_ERR_SETUP_INFRA);
>  		}
> +		if (!test->run_test && !test->run_serial_test) {
> +			test->not_built = true;
> +			test->should_run = false;
> +			continue;
> +		}

Since test->not_built is set to true regardless of what should_run() returned
for env.test_selector, won't every unbuilt test be flagged as not_built even
if the user filtered it out?

[ ... ]

> @@ -1772,6 +1780,19 @@ static void server_main(void)
>  		run_one_test(i);
>  	}
>  
> +	/* mark not-built tests as skipped */
> +	for (int i = 0; i < prog_test_cnt; i++) {
> +		struct prog_test_def *test = &prog_test_defs[i];
> +		struct test_state *state = &test_states[i];
> +
> +		if (test->not_built) {
> +			state->tested = true;
> +			state->skip_cnt = 1;
> +			env.not_built_cnt++;
> +			print_test_result(test, state);
> +		}
> +	}

Will this unconditionally print every unbuilt test in the test suite when
running in parallel mode, directly contradicting the commit message?

[ ... ]

> @@ -2106,9 +2131,18 @@ int main(int argc, char **argv)
>  
>  	for (i = 0; i < prog_test_cnt; i++) {
>  		struct prog_test_def *test = &prog_test_defs[i];
> +		struct test_state *state = &test_states[i];
>  
> -		if (!test->should_run)
> +		if (!test->should_run) {
> +			if (test->not_built && !env.get_test_cnt &&
> +			    !env.list_test_names) {
> +				state->tested = true;
> +				state->skip_cnt = 1;
> +				env.not_built_cnt++;
> +				print_test_result(test, state);
> +			}
>  			continue;
> +		}

Could a similar issue occur here in sequential mode? If a user runs
"./test_progs -t my_test", wouldn't this logic still print "SKIP (not built)"
for all the other unbuilt tests that were supposed to be ignored?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260415-selftests-bpf_misconfig-v5-0-03d0a52a898a@suse.com?part=10

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH bpf-next v5 03/11] selftests/bpf: Tolerate BPF and skeleton generation failures
  2026-04-15 20:59 ` [PATCH bpf-next v5 03/11] selftests/bpf: Tolerate BPF and skeleton generation failures Ricardo B. Marlière
@ 2026-04-15 21:15   ` sashiko-bot
  2026-04-15 21:43   ` bot+bpf-ci
  1 sibling, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-04-15 21:15 UTC (permalink / raw)
  To: Ricardo B. Marlière; +Cc: bpf

Sashiko AI review found 2 potential issue(s):
- [High] Silent masking of skeleton generation failures when PERMISSIVE is disabled (strict mode).
- [High] Stale skeleton artifacts are left on disk on incremental builds when prerequisite BPF objects fail to compile.
--

commit 3cf9cc67632ce30dc796d085a5a01c842575cf10
Author: Ricardo B. Marlière <rbm@suse.com>

selftests/bpf: Tolerate BPF and skeleton generation failures

Some BPF programs cannot be built on distro kernels because required BTF
types or features are missing. Make BPF object and skeleton generation best
effort: emit SKIP-BPF or SKIP-SKEL, remove failed outputs so downstream rules
can detect absence, and continue with remaining tests.

> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index 5c4cdf1dafc8b..a305d13409e4b 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
[ ... ]
> @@ -598,47 +602,77 @@ $(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.bpf.o:				\
>  					  $$($$<-$2-CFLAGS),$(TRUNNER_BINARY))
>  
>  $(TRUNNER_BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
> -	$$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)
> -	$(Q)$$(BPFTOOL) gen object $$(<:.o=.linked1.o) $$<
> -	$(Q)$$(BPFTOOL) gen object $$(<:.o=.linked2.o) $$(<:.o=.linked1.o)
> -	$(Q)$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o)
> -	$(Q)diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
> -	$(Q)$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$@
> -	$(Q)$$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h)
> -	$(Q)rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
> +	$(Q)$(if $(PERMISSIVE),if [ ! -f $$< ]; then			\
> +		printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
> +		exit 0;							\
> +	fi;)								\

If $$< is missing during an incremental build because a previous permissive run
failed to compile it, does exiting 0 here leave a stale .skel.h on disk?

Since $@ is not removed before exiting, it appears downstream targets might
incorrectly compile against the stale skeleton instead of failing or skipping.

> +	printf '  %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2; \
> +	$$(BPFTOOL) gen object $$(<:.o=.linked1.o) $$< &&		\
> +	$$(BPFTOOL) gen object $$(<:.o=.linked2.o) $$(<:.o=.linked1.o) && \
> +	$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o) && \
> +	diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o) &&		\
> +	$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$@ && \
> +	$$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h) $(if $(PERMISSIVE),|| { \
> +		$$(RM) $$@ $$(@:.skel.h=.subskel.h); \
> +		printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
> +	}); \
> +	rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)

When PERMISSIVE is disabled, does the generated shell command chain hide
generation failures?

Because the $(if) block evaluates to nothing in strict mode, the generated
command ends with a semicolon:

> > $$(@:.skel.h=.subskel.h) ; \
> rm -f ...

If bpftool or diff fails earlier in the && chain, the shell will skip to the
semicolon and execute rm -f. Since rm -f always succeeds, it will return exit
code 0, which seems like it would cause make to silently ignore actual
compilation regressions in strict mode.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260415-selftests-bpf_misconfig-v5-0-03d0a52a898a@suse.com?part=3

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH bpf-next v5 02/11] selftests/bpf: Fix test_kmods KDIR to honor O= and distro kernels
  2026-04-15 20:59 ` [PATCH bpf-next v5 02/11] selftests/bpf: Fix test_kmods KDIR to honor O= and distro kernels Ricardo B. Marlière
@ 2026-04-15 21:18   ` sashiko-bot
  2026-04-15 21:43   ` bot+bpf-ci
  1 sibling, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-04-15 21:18 UTC (permalink / raw)
  To: Ricardo B. Marlière; +Cc: bpf

Sashiko AI review found 2 potential issue(s):
- [High] Skipping module compilation in permissive mode fatally breaks `rsync` during out-of-tree builds.
- [Medium] Silently omitting the kernel modules converts a build skip into unconditional runtime test suite failures.
--

commit 7696fe9d292ef9e4b288adf6be9f441665f1447a
Author: Ricardo B. Marlière <rbm@suse.com>

selftests/bpf: Fix test_kmods KDIR to honor O= and distro kernels

This commit updates test_kmods/Makefile to respect out-of-tree builds using
O= and KBUILD_OUTPUT. It also introduces a permissive mode that silently
skips building modules if the kernel directory is missing.

> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -296,7 +296,7 @@ $(addprefix test_kmods/,$(subst .ko,%ko,$(TEST_KMODS))): $(VMLINUX_BTF) $(RESOLV
>  
>  $(TEST_KMOD_TARGETS): $(addprefix test_kmods/,$(TEST_KMODS))
>  	$(call msg,MOD,,$@)
> -	$(Q)cp test_kmods/$(@F) $@
> +	$(Q)$(if $(PERMISSIVE),if [ -f test_kmods/$(@F) ]; then )cp test_kmods/$(@F) $@$(if $(PERMISSIVE),; fi)

Does skipping the cp command leave the target file missing from
TEST_KMOD_TARGETS, which is subsequently included in TRUNNER_EXTRA_FILES?

During an out-of-tree build where O= is set, the rule
$(TRUNNER_BINARY)-extras runs rsync -aq $$^ $(TRUNNER_OUTPUT)/. Since $$^
evaluates to the prerequisites, it passes the missing .ko file path directly
to rsync.

Because the file was never created, does this cause rsync to fail fatally
with a No such file or directory error and abort the build?

Note that while the later patch selftests/bpf: Tolerate missing files
during install adds --ignore-missing-args to fix make install, it does not
modify the $(TRUNNER_BINARY)-extras target, leaving out-of-tree make all
broken.

> diff --git a/tools/testing/selftests/bpf/test_kmods/Makefile b/tools/testing/selftests/bpf/test_kmods/Makefile
> --- a/tools/testing/selftests/bpf/test_kmods/Makefile
> +++ b/tools/testing/selftests/bpf/test_kmods/Makefile
[ ... ]
> @@ -14,8 +16,24 @@ $(foreach m,$(MODULES),$(eval obj-m += $(m:.ko=.o)))
>  
>  CFLAGS_bpf_testmod.o = -I$(src)
>  
> +# When BPF_STRICT_BUILD != 0, a missing KDIR is fatal (the default).
> +# When permissive, skip silently.
> +PERMISSIVE := $(filter 0,$(BPF_STRICT_BUILD))
> +
>  all:
> -	$(Q)$(MAKE) -C $(KDIR) M=$(TEST_KMOD_DIR) modules
> +ifeq ($(PERMISSIVE),)
> +	$(Q)$(MAKE) -C $(KDIR) $(if $(KMOD_O),O=$(KMOD_O),KBUILD_OUTPUT=) \
> +		M=$(TEST_KMOD_DIR) modules
> +else ifneq ("$(wildcard $(KDIR))", "")
> +	$(Q)$(MAKE) -C $(KDIR) $(if $(KMOD_O),O=$(KMOD_O),KBUILD_OUTPUT=) \
> +		M=$(TEST_KMOD_DIR) modules
> +endif

If permissive mode silently skips module compilation, does this convert a
build skip into unconditional runtime test suite failures?

While test_progs.c attempts to gracefully skip tests by checking
env.has_testmod, other runners and tests fail unconditionally.

For example, test_verifier.c explicitly calls load_bpf_testmod() and
immediately returns EXIT_FAILURE if it fails, aborting the entire
verification test suite.

Similarly, tests like bpf_mod_race.c contain strict assertions
(ASSERT_OK(load_bpf_testmod(false), ...)) in their recovery paths that fail
when the module is missing.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260415-selftests-bpf_misconfig-v5-0-03d0a52a898a@suse.com?part=2

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH bpf-next v5 07/11] selftests/bpf: Allow test_progs to link with a partial object set
  2026-04-15 20:59 ` [PATCH bpf-next v5 07/11] selftests/bpf: Allow test_progs to link with a partial object set Ricardo B. Marlière
@ 2026-04-15 21:19   ` sashiko-bot
  2026-04-15 21:54   ` bot+bpf-ci
  1 sibling, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-04-15 21:19 UTC (permalink / raw)
  To: Ricardo B. Marlière; +Cc: bpf

Sashiko AI review found 2 potential issue(s):
- [Medium] Moving `$(TRUNNER_TEST_OBJS)` to order-only prerequisites silently breaks incremental linking for BPF programs and headers.
- [Medium] Linking with a partial object set introduces a regression that causes the test runner to unconditionally abort at runtime.
--

commit 26b01d6050c56240db40d2043c1d68b4a725414c
Author: Ricardo B. Marlière <rbm@suse.com>

selftests/bpf: Allow test_progs to link with a partial object set

This commit modifies the Makefile to move test objects to the order-only
prerequisite list and uses wildcard expansion to only link built test
objects. This allows the test suite to link even if some test objects
fail to compile.

> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
[ ... ]
> -$(OUTPUT)/$(TRUNNER_BINARY): $(TRUNNER_TEST_OBJS)			\
> -			     $(TRUNNER_EXTRA_OBJS) $$(BPFOBJ)		\
> +$(OUTPUT)/$(TRUNNER_BINARY): $(TRUNNER_EXTRA_OBJS) $$(BPFOBJ)		\
>  			     $(TRUNNER_LIB_OBJS)			\
>  			     $(TRUNNER_BPFTOOL)				\
>  			     $(OUTPUT)/veristat				\
> -			     | $(TRUNNER_BINARY)-extras
> +			     | $(TRUNNER_BINARY)-extras			\
> +			     $(TRUNNER_TEST_OBJS)

Will moving TRUNNER_TEST_OBJS to the order-only prerequisites break
incremental builds?

In GNU Make, order-only prerequisites ensure build order but do not trigger
a rebuild of the target when they are updated.

Modifying a BPF program correctly recompiles the BPF object and the test
object file. However, because TRUNNER_TEST_OBJS is no longer a normal
prerequisite, it appears the binary will not be relinked unless a manual
clean is performed, silently ignoring changes to BPF programs.

>  	$$(call msg,BINARY,,$$@)
> -	$(Q)$$(CC) $$(CFLAGS) $$(filter %.a %.o,$$^) $$(LDLIBS) $$(LLVM_LDLIBS) $$(LDFLAGS) $$(LLVM_LDFLAGS) -o $$@
> +	$(Q)$$(CC) $$(CFLAGS) $$(filter %.a %.o,$(if $(PERMISSIVE),$$(wildcard $(TRUNNER_TEST_OBJS)),$(TRUNNER_TEST_OBJS)) $$^) $$(LDLIBS) $$(LLVM_LDLIBS) $$(LDFLAGS) $$(LLVM_LDFLAGS) -o $$@

Does linking with a partial object set cause the test framework to
unconditionally abort at runtime?

The test framework dynamically generates prog_tests/tests.h which expands
into weak symbols in test_progs.c. If a test object is omitted due to a build
failure, its weak symbols correctly resolve to NULL.

During initialization, the test_progs binary iterates over registered tests
and validates that every test has a valid function pointer. It prints an error
and immediately aborts via exit(EXIT_ERR_SETUP_INFRA) if it encounters a NULL
pointer.

While this is addressed later in the series by commit 6ad669628925e
("selftests/bpf: Skip tests whose objects were not built"), does this patch
introduce a temporary break in test infrastructure functionality?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260415-selftests-bpf_misconfig-v5-0-03d0a52a898a@suse.com?part=7

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH bpf-next v5 10/11] selftests/bpf: Skip tests whose objects were not built
  2026-04-15 20:59 ` [PATCH bpf-next v5 10/11] selftests/bpf: Skip tests whose objects were not built Ricardo B. Marlière
  2026-04-15 21:11   ` sashiko-bot
@ 2026-04-15 21:43   ` bot+bpf-ci
  1 sibling, 0 replies; 20+ messages in thread
From: bot+bpf-ci @ 2026-04-15 21:43 UTC (permalink / raw)
  To: rbm, andrii, eddyz87, ast, daniel, martin.lau, memxor, song,
	yonghong.song, jolsa, shuah, nathan, nick.desaulniers+lkml, morbo,
	justinstitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, alan.maguire, rbm, ast,
	andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
	ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 2919 bytes --]

> diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
> index 7fe16b5131b1..759e76d76c57 100644
> --- a/tools/testing/selftests/bpf/test_progs.c
> +++ b/tools/testing/selftests/bpf/test_progs.c

[ ... ]

> @@ -2049,12 +2070,16 @@ int main(int argc, char **argv)
>  		test->should_run = should_run(&env.test_selector,
>  					      test->test_num, test->test_name);
>
> +		if (test->run_test && test->run_serial_test) {
>  			fprintf(stderr, "Test %d:%s must have either test_%s() or serial_test_%sl() defined.\n",
>  				test->test_num, test->test_name, test->test_name, test->test_name);
>  			exit(EXIT_ERR_SETUP_INFRA);
>  		}
> +		if (!test->run_test && !test->run_serial_test) {
> +			test->not_built = true;
> +			test->should_run = false;
> +			continue;
> +		}

This sets not_built unconditionally, regardless of what should_run()
returned.  The commit message says:

  "Tests filtered out by -t/-n remain invisible as before"

but doesn't this do the opposite?  When should_run() already returned
false because of -t/-n filtering, the test still gets not_built = true.

> @@ -2106,9 +2131,18 @@ int main(int argc, char **argv)
>
>  	for (i = 0; i < prog_test_cnt; i++) {
>  		struct prog_test_def *test = &prog_test_defs[i];
> +		struct test_state *state = &test_states[i];
>
> -		if (!test->should_run)
> +		if (!test->should_run) {
> +			if (test->not_built && !env.get_test_cnt &&
> +			    !env.list_test_names) {
> +				state->tested = true;
> +				state->skip_cnt = 1;
> +				env.not_built_cnt++;
> +				print_test_result(test, state);
> +			}
>  			continue;
> +		}

Then here, every not-built test is printed and counted as skipped,
even ones the user excluded with -t or -n.  Running something like
"./test_progs -t my_test" on a partial build would print
"SKIP (not built)" for all unbuilt tests, and inflate both succ_cnt
and skip_cnt in calculate_summary_and_print_errors().

The same issue applies to the server_main() loop:

> @@ -1772,6 +1780,19 @@ static void server_main(void)
> +	/* mark not-built tests as skipped */
> +	for (int i = 0; i < prog_test_cnt; i++) {
> +		struct prog_test_def *test = &prog_test_defs[i];
> +		struct test_state *state = &test_states[i];
> +
> +		if (test->not_built) {

This also has no check against the original test selector, so in
parallel mode with -t, all not-built tests are surfaced as well.

Would it make sense to preserve the original should_run() result and
only set not_built when the test was actually selected?

This was also flagged in an earlier review of v5:
https://sashiko.dev/#/patchset/20260415-selftests-bpf_misconfig-v5-0-03d0a52a898a@suse.com?part=10


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/24478691588

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH bpf-next v5 02/11] selftests/bpf: Fix test_kmods KDIR to honor O= and distro kernels
  2026-04-15 20:59 ` [PATCH bpf-next v5 02/11] selftests/bpf: Fix test_kmods KDIR to honor O= and distro kernels Ricardo B. Marlière
  2026-04-15 21:18   ` sashiko-bot
@ 2026-04-15 21:43   ` bot+bpf-ci
  1 sibling, 0 replies; 20+ messages in thread
From: bot+bpf-ci @ 2026-04-15 21:43 UTC (permalink / raw)
  To: rbm, andrii, eddyz87, ast, daniel, martin.lau, memxor, song,
	yonghong.song, jolsa, shuah, nathan, nick.desaulniers+lkml, morbo,
	justinstitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, alan.maguire, rbm, ast,
	andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
	ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 2082 bytes --]

> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index c8ba8ccc2c6d..5c4cdf1dafc8 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -296,7 +296,7 @@ $(addprefix test_kmods/,$(subst .ko,%ko,$(TEST_KMODS))): $(VMLINUX_BTF) $(RESOLV
>
>  $(TEST_KMOD_TARGETS): $(addprefix test_kmods/,$(TEST_KMODS))
>  	$(call msg,MOD,,$@)
> -	$(Q)cp test_kmods/$(@F) $@
> +	$(Q)$(if $(PERMISSIVE),if [ -f test_kmods/$(@F) ]; then )cp test_kmods/$(@F) $@$(if $(PERMISSIVE),; fi)

When permissive mode skips this cp because the .ko file was not built,
the target file under $(OUTPUT) is never created.  However,
TEST_KMOD_TARGETS is included in TRUNNER_EXTRA_FILES:

    TRUNNER_EXTRA_FILES := ...
                           $(TEST_KMOD_TARGETS)
                           ...

and the test_progs-extras rule passes those paths straight to rsync:

    $(TRUNNER_BINARY)-extras: $(TRUNNER_EXTRA_FILES) | $(TRUNNER_OUTPUT)
    ifneq ($2:$(OUTPUT),:$(shell pwd))
        $(Q)rsync -aq $$^ $(TRUNNER_OUTPUT)/
    endif

For out-of-tree builds (the exact scenario described in the cover
letter -- make -C tools/testing/selftests TARGETS=bpf
O=/lib/modules/$(uname -r)/build BPF_STRICT_BUILD=0), doesn't rsync
fail with "No such file or directory" on the missing .ko paths and
abort the build?

The later commit 671e16611575 ("selftests/bpf: Tolerate missing files
during install") adds --ignore-missing-args to the install rsync
rules, but does not patch this extras target.

Would adding --ignore-missing-args here as well (or filtering the
prerequisite list through $(wildcard)) be needed to make the
permissive out-of-tree path work end to end?

> diff --git a/tools/testing/selftests/bpf/test_kmods/Makefile b/tools/testing/selftests/bpf/test_kmods/Makefile

[ ... ]


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/24478691588

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH bpf-next v5 03/11] selftests/bpf: Tolerate BPF and skeleton generation failures
  2026-04-15 20:59 ` [PATCH bpf-next v5 03/11] selftests/bpf: Tolerate BPF and skeleton generation failures Ricardo B. Marlière
  2026-04-15 21:15   ` sashiko-bot
@ 2026-04-15 21:43   ` bot+bpf-ci
  1 sibling, 0 replies; 20+ messages in thread
From: bot+bpf-ci @ 2026-04-15 21:43 UTC (permalink / raw)
  To: rbm, andrii, eddyz87, ast, daniel, martin.lau, memxor, song,
	yonghong.song, jolsa, shuah, nathan, nick.desaulniers+lkml, morbo,
	justinstitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, alan.maguire, rbm, ast,
	andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
	ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 3493 bytes --]

> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index 5c4cdf1dafc8..a305d13409e4 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile

[ ... ]

> @@ -598,47 +602,77 @@ $(TRUNNER_BPF_OBJS): $(TRUNNER_OUTPUT)/%.bpf.o:
>
>  $(TRUNNER_BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
> -	$$(call msg,GEN-SKEL,$(TRUNNER_BINARY),$$@)
> -	$(Q)$$(BPFTOOL) gen object $$(<:.o=.linked1.o) $$<
> -	$(Q)$$(BPFTOOL) gen object $$(<:.o=.linked2.o) $$(<:.o=.linked1.o)
> -	$(Q)$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o)
> -	$(Q)diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
> -	$(Q)$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$@
> -	$(Q)$$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h)
> -	$(Q)rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)
> +	$(Q)$(if $(PERMISSIVE),if [ ! -f $$< ]; then			\
> +		printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
> +		exit 0;							\
> +	fi;)								\

When the .bpf.o prerequisite is missing during an incremental
permissive build, this exits 0 without removing $@ (.skel.h).
If a stale .skel.h remains from a previous successful build,
downstream targets will silently compile against it.

The commit message says "remove failed outputs so downstream rules
can detect absence" -- would adding $(RM) $$@ before exit 0 match
that intent?

> +	printf '  %-12s %s\n' 'GEN-SKEL' '[$(TRUNNER_BINARY)] $$(notdir $$@)' 1>&2; \
> +	$$(BPFTOOL) gen object $$(<:.o=.linked1.o) $$< &&		\
> +	$$(BPFTOOL) gen object $$(<:.o=.linked2.o) $$(<:.o=.linked1.o) && \
> +	$$(BPFTOOL) gen object $$(<:.o=.linked3.o) $$(<:.o=.linked2.o) && \
> +	diff $$(<:.o=.linked2.o) $$(<:.o=.linked3.o) &&		\
> +	$$(BPFTOOL) gen skeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$@ && \
> +	$$(BPFTOOL) gen subskeleton $$(<:.o=.linked3.o) name $$(notdir $$(<:.bpf.o=)) > $$(@:.skel.h=.subskel.h) $(if $(PERMISSIVE),|| { \
> +		$$(RM) $$@ $$(@:.skel.h=.subskel.h); \
> +		printf '  %-12s %s\n' 'SKIP-SKEL' '$$(notdir $$@)' 1>&2; \
> +	}); \
> +	rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)

When PERMISSIVE is not set (strict mode, the default), the $(if)
block expands to nothing and this recipe becomes a single shell
command ending with:

    ... > $$(@:.skel.h=.subskel.h) ; \
    rm -f $$(<:.o=.linked1.o) $$(<:.o=.linked2.o) $$(<:.o=.linked3.o)

If bpftool or diff fails anywhere in the && chain, the shell skips
to the semicolon and runs rm -f, which always returns 0.  Make then
sees exit code 0 from the recipe and continues the build as though
skeleton generation succeeded.

The original code used separate $(Q)-prefixed recipe lines, where
make saw each command's exit code individually and would abort on
failure.

The same pattern appears in the TRUNNER_BPF_LSKELS,
TRUNNER_BPF_LSKELS_SIGNED, and TRUNNER_BPF_SKELS_LINKED rules.

One possible fix would be to capture the exit status before the
cleanup, for example:

    ... > subskel.h ; rc=$$?; \
    rm -f linked1.o linked2.o linked3.o; \
    exit $$rc

https://lore.kernel.org/bpf/20260415211532.A56BEC19424@smtp.kernel.org/


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/24478691588

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH bpf-next v5 07/11] selftests/bpf: Allow test_progs to link with a partial object set
  2026-04-15 20:59 ` [PATCH bpf-next v5 07/11] selftests/bpf: Allow test_progs to link with a partial object set Ricardo B. Marlière
  2026-04-15 21:19   ` sashiko-bot
@ 2026-04-15 21:54   ` bot+bpf-ci
  1 sibling, 0 replies; 20+ messages in thread
From: bot+bpf-ci @ 2026-04-15 21:54 UTC (permalink / raw)
  To: rbm, andrii, eddyz87, ast, daniel, martin.lau, memxor, song,
	yonghong.song, jolsa, shuah, nathan, nick.desaulniers+lkml, morbo,
	justinstitt
  Cc: bpf, linux-kselftest, linux-kernel, llvm, alan.maguire, rbm, ast,
	andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
	ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 2695 bytes --]

> diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
> index ee7bbfcd661b..128ea61fd986 100644
> --- a/tools/testing/selftests/bpf/Makefile
> +++ b/tools/testing/selftests/bpf/Makefile
> @@ -754,14 +754,14 @@ endif
>  # some X.test.o files have runtime dependencies on Y.bpf.o files
>  $(OUTPUT)/$(TRUNNER_BINARY): | $(TRUNNER_BPF_OBJS)
>
> -$(OUTPUT)/$(TRUNNER_BINARY): $(TRUNNER_TEST_OBJS)			\
> -			     $(TRUNNER_EXTRA_OBJS) $$(BPFOBJ)		\
> +$(OUTPUT)/$(TRUNNER_BINARY): $(TRUNNER_EXTRA_OBJS) $$(BPFOBJ)		\
>  			     $(TRUNNER_LIB_OBJS)			\
>  			     $(TRUNNER_BPFTOOL)				\
>  			     $(OUTPUT)/veristat				\
> -			     | $(TRUNNER_BINARY)-extras
> +			     | $(TRUNNER_BINARY)-extras			\
> +			     $(TRUNNER_TEST_OBJS)

Does moving TRUNNER_TEST_OBJS to the order-only prerequisite list
break incremental builds in the default (BPF_STRICT_BUILD=1) case?

Order-only prerequisites ensure build ordering but do not cause the
target to be rebuilt when they are updated.  If a developer edits a
test source file, the corresponding .test.o is correctly recompiled
via the pattern rule and .d dependencies, but because
TRUNNER_TEST_OBJS is no longer a normal prerequisite of
$(OUTPUT)/$(TRUNNER_BINARY), the binary will not be relinked to
pick up the new object.  The developer would need to run make clean
or touch a normal prerequisite to get the updated test code linked
into the binary.

>  	$$(call msg,BINARY,,$$@)
> -	$(Q)$$(CC) $$(CFLAGS) $$(filter %.a %.o,$$^) $$(LDLIBS) $$(LLVM_LDLIBS) $$(LDFLAGS) $$(LLVM_LDFLAGS) -o $$@
> +	$(Q)$$(CC) $$(CFLAGS) $$(filter %.a %.o,$(if $(PERMISSIVE),$$(wildcard $(TRUNNER_TEST_OBJS)),$(TRUNNER_TEST_OBJS)) $$^) $$(LDLIBS) $$(LLVM_LDLIBS) $$(LDFLAGS) $$(LLVM_LDFLAGS) -o $$@

When PERMISSIVE is set and some .test.o files are absent, the
resulting binary still contains entries in the prog_test_defs[]
array for the missing tests (via tests.h and __weak symbols), but
both run_test and run_serial_test resolve to NULL.  The existing
validation in test_progs.c main():

    if ((test->run_test == NULL && test->run_serial_test == NULL) ||
        (test->run_test != NULL && test->run_serial_test != NULL)) {
            ...
            exit(EXIT_ERR_SETUP_INFRA);
    }

will abort the entire test run.  This is addressed later in the
series by commit ec7dae68360b ("selftests/bpf: Skip tests whose
objects were not built"), which replaces the abort with a skip
marker.


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/24478691588

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-04-15 21:54 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-15 20:59 [PATCH bpf-next v5 00/11] selftests/bpf: Tolerate partial builds across kernel configs Ricardo B. Marlière
2026-04-15 20:59 ` [PATCH bpf-next v5 01/11] selftests/bpf: Add BPF_STRICT_BUILD toggle Ricardo B. Marlière
2026-04-15 20:59 ` [PATCH bpf-next v5 02/11] selftests/bpf: Fix test_kmods KDIR to honor O= and distro kernels Ricardo B. Marlière
2026-04-15 21:18   ` sashiko-bot
2026-04-15 21:43   ` bot+bpf-ci
2026-04-15 20:59 ` [PATCH bpf-next v5 03/11] selftests/bpf: Tolerate BPF and skeleton generation failures Ricardo B. Marlière
2026-04-15 21:15   ` sashiko-bot
2026-04-15 21:43   ` bot+bpf-ci
2026-04-15 20:59 ` [PATCH bpf-next v5 04/11] selftests/bpf: Avoid rebuilds when running emit_tests Ricardo B. Marlière
2026-04-15 20:59 ` [PATCH bpf-next v5 05/11] selftests/bpf: Make skeleton headers order-only prerequisites of .test.d Ricardo B. Marlière
2026-04-15 20:59 ` [PATCH bpf-next v5 06/11] selftests/bpf: Tolerate test file compilation failures Ricardo B. Marlière
2026-04-15 20:59 ` [PATCH bpf-next v5 07/11] selftests/bpf: Allow test_progs to link with a partial object set Ricardo B. Marlière
2026-04-15 21:19   ` sashiko-bot
2026-04-15 21:54   ` bot+bpf-ci
2026-04-15 20:59 ` [PATCH bpf-next v5 08/11] selftests/bpf: Tolerate benchmark build failures Ricardo B. Marlière
2026-04-15 20:59 ` [PATCH bpf-next v5 09/11] selftests/bpf: Provide weak definitions for cross-test functions Ricardo B. Marlière
2026-04-15 20:59 ` [PATCH bpf-next v5 10/11] selftests/bpf: Skip tests whose objects were not built Ricardo B. Marlière
2026-04-15 21:11   ` sashiko-bot
2026-04-15 21:43   ` bot+bpf-ci
2026-04-15 20:59 ` [PATCH bpf-next v5 11/11] selftests/bpf: Tolerate missing files during install Ricardo B. Marlière

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox