The current support for LLVM and clang in nolibc and its testsuite is
very limited.
* Various architectures plain do not compile
* The user *has* to specify "-Os" otherwise the program crashes
* Cross-compilation of the tests does not work
* Using clang is not wired up in run-tests.sh
This series extends this support.
Signed-off-by: Thomas Weißschuh <linux(a)weissschuh.net>
---
Thomas Weißschuh (12):
tools/nolibc: use clang-compatible asm syntax in arch-arm.h
tools/nolibc: limit powerpc stack-protector workaround to GCC
tools/nolibc: move entrypoint specifics to compiler.h
tools/nolibc: use attribute((naked)) if available
selftests/nolibc: report failure if no testcase passed
selftests/nolibc: avoid passing NULL to printf("%s")
selftests/nolibc: determine $(srctree) first
selftests/nolibc: setup objtree without Makefile.include
selftests/nolibc: add support for LLVM= parameter
selftests/nolibc: add cc-option compatible with clang cross builds
selftests/nolibc: run-tests.sh: avoid overwriting CFLAGS_EXTRA
selftests/nolibc: run-tests.sh: allow building through LLVM
tools/include/nolibc/arch-aarch64.h | 4 ++--
tools/include/nolibc/arch-arm.h | 8 ++++----
tools/include/nolibc/arch-i386.h | 4 ++--
tools/include/nolibc/arch-loongarch.h | 4 ++--
tools/include/nolibc/arch-mips.h | 4 ++--
tools/include/nolibc/arch-powerpc.h | 6 +++---
tools/include/nolibc/arch-riscv.h | 4 ++--
tools/include/nolibc/arch-s390.h | 4 ++--
tools/include/nolibc/arch-x86_64.h | 4 ++--
tools/include/nolibc/compiler.h | 12 ++++++++++++
tools/testing/selftests/nolibc/Makefile | 27 ++++++++++++++++-----------
tools/testing/selftests/nolibc/nolibc-test.c | 4 ++--
tools/testing/selftests/nolibc/run-tests.sh | 20 ++++++++++++++++----
13 files changed, 67 insertions(+), 38 deletions(-)
---
base-commit: 0db287736bc586fcd5a2925518ef09eec6924803
change-id: 20240727-nolibc-llvm-3fad68590d4c
Best regards,
--
Thomas Weißschuh <linux(a)weissschuh.net>
Don't print that 88 sub-tests are going to be executed, but then skip.
This is against TAP compliance. Instead check pre-requisites first
before printing total number of tests.
Old non-tap compliant output:
TAP version 13
1..88
ok 2 # SKIP all tests require euid == 0
# Planned tests != run tests (88 != 1)
# Totals: pass:0 fail:0 xfail:0 xpass:0 skip:1 error:0
New and correct output:
TAP version 13
1..0 # SKIP all tests require euid == 0
Signed-off-by: Muhammad Usama Anjum <usama.anjum(a)collabora.com>
---
Changes since v1:
- Remove simplifying if condition lines
- Update the patch message
---
tools/testing/selftests/openat2/resolve_test.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/openat2/resolve_test.c b/tools/testing/selftests/openat2/resolve_test.c
index bbafad440893c..85a4c64ee950d 100644
--- a/tools/testing/selftests/openat2/resolve_test.c
+++ b/tools/testing/selftests/openat2/resolve_test.c
@@ -508,12 +508,13 @@ void test_openat2_opath_tests(void)
int main(int argc, char **argv)
{
ksft_print_header();
- ksft_set_plan(NUM_TESTS);
/* NOTE: We should be checking for CAP_SYS_ADMIN here... */
if (geteuid() != 0)
ksft_exit_skip("all tests require euid == 0\n");
+ ksft_set_plan(NUM_TESTS);
+
test_openat2_opath_tests();
if (ksft_get_fail_cnt() + ksft_get_error_cnt() > 0)
--
2.39.2
A small bugfix for "run-user XARCH=ppc64le" and run-user support for
run-tests.sh.
Signed-off-by: Thomas Weißschuh <linux(a)weissschuh.net>
---
Thomas Weißschuh (2):
selftests/nolibc: introduce QEMU_ARCH_USER
selftests/nolibc: run-tests.sh: enable testing via qemu-user
tools/testing/selftests/nolibc/Makefile | 5 ++++-
tools/testing/selftests/nolibc/run-tests.sh | 22 +++++++++++++++++++---
2 files changed, 23 insertions(+), 4 deletions(-)
---
base-commit: ba335752620565c25c3028fff9496bb8ef373602
change-id: 20770915-nolibc-run-user-845375a3ec4f
Best regards,
--
Thomas Weißschuh <linux(a)weissschuh.net>
Introduce a new test to identify regressions causing devices to go
missing on the system.
For each bus and class on the system the test checks the number of
devices present against a reference file, which needs to have been
generated by the program at a previous point on a known-good kernel, and
if there are missing devices they are reported.
Signed-off-by: Nícolas F. R. A. Prado <nfraprado(a)collabora.com>
---
Hi,
Key points about this test:
* Goal: Identify regressions causing devices to go missing on the system
* Focus:
* Ease of maintenance: the reference file is generated programatically
* Minimum of false-positives: the script makes as few assumptions as possible
about the stability of device identifiers to ensure renames/refactors don't
trigger false-positives
* How it works: For each bus and class on the system the test checks the number
of devices present against a reference file, which needs to have been
generated by the program at a previous point on a known-good kernel, and if
there are missing devices they are reported.
* Comparison to other tests: It might be possible(*) to replace the discoverable
devices test [1] with this. The benefits of this test is that it's easier
to setup and maintain and has wider coverage of devices.
Additional detail:
* Having more devices on the running system than the reference does not cause a
failure, but a warning is printed in that case to suggest that the reference
be updated.
* Missing devices are detected per bus/class based on the number of devices.
When the test fails, the known metadata for each of the expected and detected
devices is printed and some simple similitarity comparison is done to suggest
the devices that are the most likely to be missing.
* The proposed place to store the generated reference files is the
'platform-test-parameters' repository in KernelCI [2].
Example output: This is an example of a failing test case when one of the two
devices in the nvmem bus went missing:
# Missing devices for subsystem 'nvmem': 1 (Expected 2, found 1)
# =================
# Devices expected:
#
# uevent:
# OF_NAME=efuse
# OF_FULLNAME=/soc/efuse@11c10000
# OF_COMPATIBLE_0=mediatek,mt8195-efuse
# OF_COMPATIBLE_1=mediatek,efuse
# OF_COMPATIBLE_N=2
#
# uevent:
# OF_NAME=flash
# OF_FULLNAME=/soc/spi@1132c000/flash@0
# OF_COMPATIBLE_0=jedec,spi-nor
# OF_COMPATIBLE_N=1
#
# -----------------
# Devices found:
#
# uevent:
# OF_NAME=efuse
# OF_FULLNAME=/soc/efuse@11c10000
# OF_COMPATIBLE_0=mediatek,mt8195-efuse
# OF_COMPATIBLE_1=mediatek,efuse
# OF_COMPATIBLE_N=2
#
# -----------------
# Devices missing (best guess):
#
# uevent:
# OF_NAME=flash
# OF_FULLNAME=/soc/spi@1132c000/flash@0
# OF_COMPATIBLE_0=jedec,spi-nor
# OF_COMPATIBLE_N=1
#
# =================
not ok 19 bus.nvmem
Example of how the data for these devices is encoded in the reference file:
bus:
...
nvmem:
count: 2
devices:
- info:
uevent: 'OF_NAME=efuse
OF_FULLNAME=/soc/efuse@11c10000
OF_COMPATIBLE_0=mediatek,mt8195-efuse
OF_COMPATIBLE_1=mediatek,efuse
OF_COMPATIBLE_N=2
'
- info:
uevent: 'OF_NAME=flash
OF_FULLNAME=/soc/spi@1132c000/flash@0
OF_COMPATIBLE_0=jedec,spi-nor
OF_COMPATIBLE_N=1
'
(Full reference file: http://0x0.st/Xp60.yaml;)
Caveat: Relying only on the count of devices in a subsystem makes the test
susceptible to false-negatives eg. if a device goes missing and another in the
same subsystem is added the count will be the same so this regression won't be
reported. In order to avoid this we may include properties that must match
individual devices, but we must be very careful (and it's why I haven't done it)
since matching against properties that aren't guaranteed to be stable will
introduce false-positives (ie. detecting false regressions) due to eventual
renames.
Some things to improve in the near future / gather feedback on:
* (*): Currently this test only checks for the existence of devices. We could
extend it to also encode into the reference which devices are bound to drivers
to be able to completely replace the discoverable devices probe kselftest [1].
* Expanding identifying properties: Currently the properties that are stored
(when present) in the reference for each device to be used for identification
in the result output are uevent, device/uevent, firmware_node/uevent and name.
Suggestions of others properties to add are welcome.
* Adding more filtering to reduce noise:
* Ignoring buses/classes: Currently the devlink class is ignored by the test
since it seems like a kernel internal detail that userspace doesn't actually
care about. We should add others that are similar.
* Ignoring non-devices: There can be entries in /sys/class/ that aren't
devices. For now we're filtering down to only symlinks, but there might be a
better way.
* As mentioned in the caveat section above we may want to add actual matching
of devices based on properties to avoid false-negatives if we identify
suitable properties.
* It would be nice to have an option in the program to compare a newer reference
to an older one to make it easier for the user to see the differences and
decide if the new reference is ok.
* Since the reference file is not supposed to be manually edited, JSON might be
a better choice than YAML since it is included in the python standard library.
Let me know your thoughts.
Thanks,
Nícolas
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/too…
[2] https://github.com/kernelci/platform-test-parameters
---
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/devices/exist/Makefile | 3 +
tools/testing/selftests/devices/exist/exist.py | 268 +++++++++++++++++++++++++
3 files changed, 272 insertions(+)
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index bc8fe9e8f7f2..9c49b5ec5bef 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -14,6 +14,7 @@ TARGETS += cpufreq
TARGETS += cpu-hotplug
TARGETS += damon
TARGETS += devices/error_logs
+TARGETS += devices/exist
TARGETS += devices/probe
TARGETS += dmabuf-heaps
TARGETS += drivers/dma-buf
diff --git a/tools/testing/selftests/devices/exist/Makefile b/tools/testing/selftests/devices/exist/Makefile
new file mode 100644
index 000000000000..3075cac32092
--- /dev/null
+++ b/tools/testing/selftests/devices/exist/Makefile
@@ -0,0 +1,3 @@
+TEST_PROGS := exist.py
+
+include ../../lib.mk
diff --git a/tools/testing/selftests/devices/exist/exist.py b/tools/testing/selftests/devices/exist/exist.py
new file mode 100755
index 000000000000..8241b2fabc8e
--- /dev/null
+++ b/tools/testing/selftests/devices/exist/exist.py
@@ -0,0 +1,268 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2024 Collabora Ltd
+
+# * Goal: Identify regressions causing devices to go missing on the system
+# * Focus:
+# * Ease of maintenance: the reference file is generated programatically
+# * Minimum of false-positives: the script makes as few assumptions as
+# possible about the stability of device identifiers to ensure
+# renames/refactors don't trigger false-positives
+# * How it works: For each bus and class on the system the test checks the
+# number of devices present against a reference file, which needs to have been
+# generated by the program at a previous point on a known-good kernel, and if
+# there are missing devices they are reported.
+
+import os
+import sys
+import argparse
+
+import yaml
+
+# Allow ksft module to be imported from different directory
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(this_dir, "../../kselftest/"))
+
+import ksft
+
+
+def generate_devs_obj():
+ obj = {}
+
+ device_sources = [
+ {
+ "base_dir": "/sys/class",
+ "add_path": "",
+ "key_name": "class",
+ "ignored": ["devlink"],
+ },
+ {
+ "base_dir": "/sys/bus",
+ "add_path": "devices",
+ "key_name": "bus",
+ "ignored": [],
+ },
+ ]
+
+ properties = sorted(["uevent", "device/uevent", "firmware_node/uevent", "name"])
+
+ for source in device_sources:
+ source_subsystems = {}
+ for subsystem in sorted(os.listdir(source["base_dir"])):
+ if subsystem in source["ignored"]:
+ continue
+
+ devs_path = os.path.join(source["base_dir"], subsystem, source["add_path"])
+ dev_dirs = [dev for dev in os.scandir(devs_path) if dev.is_symlink()]
+ devs_data = []
+ for dev_dir in dev_dirs:
+ dev_path = os.path.join(devs_path, dev_dir)
+ dev_data = {"info": {}}
+ for prop in properties:
+ if os.path.isfile(os.path.join(dev_path, prop)):
+ with open(os.path.join(dev_path, prop)) as f:
+ dev_data["info"][prop] = f.read()
+ devs_data.append(dev_data)
+ if len(dev_dirs):
+ source_subsystems[subsystem] = {
+ "count": len(dev_dirs),
+ "devices": devs_data,
+ }
+ obj[source["key_name"]] = source_subsystems
+
+ return obj
+
+
+def commented(s):
+ return s.replace("\n", "\n# ")
+
+
+def indented(s, n):
+ return " " * n + s.replace("\n", "\n" + " " * n)
+
+
+def stripped(s):
+ return s.strip("\n")
+
+
+def devices_difference(dev1, dev2):
+ difference = 0
+
+ for prop in dev1["info"].keys():
+ for l1, l2 in zip(
+ dev1["info"].get(prop, "").split("\n"),
+ dev2["info"].get(prop, "").split("\n"),
+ ):
+ if l1 != l2:
+ difference += 1
+ return difference
+
+
+def guess_missing_devices(cur_devs_subsystem, ref_devs_subsystem):
+ # Detect what devices on the current system are the most similar to devices
+ # on the reference one by one until the leftovers are the most dissimilar
+ # devices and therefore most likely the missing ones.
+ found_count = cur_devs_subsystem["count"]
+ expected_count = ref_devs_subsystem["count"]
+ missing_count = found_count - expected_count
+
+ diffs = []
+ for cur_d in cur_devs_subsystem["devices"]:
+ for ref_d in ref_devs_subsystem["devices"]:
+ diffs.append((devices_difference(cur_d, ref_d), cur_d, ref_d))
+
+ diffs.sort(key=lambda x: x[0])
+
+ assigned_ref_devs = []
+ assigned_cur_devs = []
+ for diff in diffs:
+ if len(assigned_ref_devs) >= expected_count - missing_count:
+ break
+ if diff[1] in assigned_cur_devs or diff[2] in assigned_ref_devs:
+ continue
+ assigned_cur_devs.append(diff[1])
+ assigned_ref_devs.append(diff[2])
+
+ missing_devices = []
+ for d in ref_devs_subsystem["devices"]:
+ if d not in assigned_ref_devs:
+ missing_devices.append(d)
+
+ return missing_devices
+
+
+def dump_devices_info(cur_devs_subsystem, ref_devs_subsystem):
+ def dump_device_info(dev):
+ for name, val in dev["info"].items():
+ ksft.print_msg(indented(name + ":", 2))
+ val = stripped(val)
+ if val:
+ ksft.print_msg(commented(indented(val, 4)))
+ ksft.print_msg("")
+
+ ksft.print_msg("=================")
+ ksft.print_msg("Devices expected:")
+ ksft.print_msg("")
+ for d in ref_devs_subsystem["devices"]:
+ dump_device_info(d)
+ ksft.print_msg("-----------------")
+ ksft.print_msg("Devices found:")
+ ksft.print_msg("")
+ for d in cur_devs_subsystem["devices"]:
+ dump_device_info(d)
+ ksft.print_msg("-----------------")
+ ksft.print_msg("Devices missing (best guess):")
+ ksft.print_msg("")
+ missing_devices = guess_missing_devices(cur_devs_subsystem, ref_devs_subsystem)
+ for d in missing_devices:
+ dump_device_info(d)
+ ksft.print_msg("=================")
+
+
+def run_test(ref_filename):
+ ksft.print_msg(f"Using reference file: {ref_filename}")
+
+ with open(ref_filename) as f:
+ ref_devs_obj = yaml.safe_load(f)
+
+ num_tests = 0
+ for dev_source in ref_devs_obj.values():
+ num_tests += len(dev_source)
+ ksft.set_plan(num_tests)
+
+ cur_devs_obj = generate_devs_obj()
+
+ reference_outdated = False
+
+ for source, ref_devs_source_obj in ref_devs_obj.items():
+ for subsystem, ref_devs_subsystem_obj in ref_devs_source_obj.items():
+ test_name = f"{source}.{subsystem}"
+ if not (
+ cur_devs_obj.get(source) and cur_devs_obj.get(source).get(subsystem)
+ ):
+ ksft.print_msg(f"Device subsystem '{subsystem}' missing")
+ ksft.test_result_fail(test_name)
+ continue
+ cur_devs_subsystem_obj = cur_devs_obj[source][subsystem]
+
+ found_count = cur_devs_subsystem_obj["count"]
+ expected_count = ref_devs_subsystem_obj["count"]
+ if found_count < expected_count:
+ ksft.print_msg(
+ f"Missing devices for subsystem '{subsystem}': {expected_count - found_count} (Expected {expected_count}, found {found_count})"
+ )
+ dump_devices_info(cur_devs_subsystem_obj, ref_devs_subsystem_obj)
+ ksft.test_result_fail(test_name)
+ else:
+ ksft.test_result_pass(test_name)
+ if found_count > expected_count:
+ reference_outdated = True
+
+ if len(cur_devs_obj[source]) > len(ref_devs_source_obj):
+ reference_outdated = True
+
+ if reference_outdated:
+ ksft.print_msg(
+ "Warning: The current system contains more devices and/or subsystems than the reference. Updating the reference is recommended."
+ )
+
+
+def get_possible_ref_filenames():
+ filenames = []
+
+ dt_board_compatible_file = "/proc/device-tree/compatible"
+ if os.path.exists(dt_board_compatible_file):
+ with open(dt_board_compatible_file) as f:
+ for line in f:
+ compatibles = [compat for compat in line.split("\0") if compat]
+ filenames.extend(compatibles)
+ else:
+ dmi_id_dir = "/sys/devices/virtual/dmi/id"
+ vendor_dmi_file = os.path.join(dmi_id_dir, "sys_vendor")
+ product_dmi_file = os.path.join(dmi_id_dir, "product_name")
+
+ with open(vendor_dmi_file) as f:
+ vendor = f.read().replace("\n", "")
+ with open(product_dmi_file) as f:
+ product = f.read().replace("\n", "")
+
+ filenames = [vendor + "," + product]
+
+ return filenames
+
+
+def get_ref_filename(ref_dir):
+ chosen_ref_filename = ""
+ full_ref_paths = [os.path.join(ref_dir, f + ".yaml") for f in get_possible_ref_filenames()]
+ for path in full_ref_paths:
+ if os.path.exists(path):
+ chosen_ref_filename = path
+ break
+
+ if not chosen_ref_filename:
+ tried_paths = ",".join(["'" + p + "'" for p in full_ref_paths])
+ ksft.print_msg(f"No matching reference file found (tried {tried_paths})")
+ ksft.exit_fail()
+
+ return chosen_ref_filename
+
+
+parser = argparse.ArgumentParser()
+parser.add_argument(
+ "--reference-dir", default=".", help="Directory containing the reference files"
+)
+parser.add_argument("--generate-reference", action="store_true", help="Generate a reference file with the devices on the running system")
+args = parser.parse_args()
+
+if args.generate_reference:
+ print(f"# Kernel version: {os.uname().release}")
+ print(yaml.dump(generate_devs_obj()))
+ sys.exit(0)
+
+ksft.print_header()
+
+ref_filename = get_ref_filename(args.reference_dir)
+
+run_test(ref_filename)
+
+ksft.finished()
---
base-commit: 73399b58e5e5a1b28a04baf42e321cfcfc663c2f
change-id: 20240724-kselftest-dev-exist-bb1bcf884654
Best regards,
--
Nícolas F. R. A. Prado <nfraprado(a)collabora.com>
When looking at improving the user experience around the MPTCP endpoints
setup, I noticed that setting an endpoint with both the 'signal' and the
'subflow' flags -- as it has been done in the past by users according to
bug reports we got -- was resulting on only announcing the endpoint, but
not using it to create subflows: the 'subflow' flag was then ignored.
My initial thought was to modify IPRoute2 to warn the user when the two
flags were set, but it doesn't sound normal to ignore one of them. I
then looked at modifying the kernel not to allow having the two flags
set, but when discussing about that with Mat, we thought it was maybe
not ideal to do that, as there might be use-cases, we might break some
configs. Then I saw it was working before v5.17. So instead, I fixed the
support on the kernel side (patch 5) using Paolo's suggestion. This also
includes a fix on the options side (patch 1: for v5.11+), an explicit
deny of some options combinations (patch 2: for v5.18+), and some
refactoring (patches 3 and 4) to ease the inclusion of the patch 5.
While at it, I added a new selftest (patch 7) to validate this case --
including a modification of the chk_add_nr helper to inverse the sides
were the counters are checked (patch 6) -- and allowed ADD_ADDR echo
just after the MP_JOIN 3WHS.
The selftests modification have the same Fixes tag as the previous
commit, but no 'Cc: Stable': if the backport can work, that's good --
but it still need to be verified by running the selftests -- if not, no
need to worry, many CIs will use the selftests from the last stable
version to validate previous stable releases.
Signed-off-by: Matthieu Baerts (NGI0) <matttbe(a)kernel.org>
---
Matthieu Baerts (NGI0) (7):
mptcp: fully established after ADD_ADDR echo on MPJ
mptcp: pm: deny endp with signal + subflow + port
mptcp: pm: reduce indentation blocks
mptcp: pm: don't try to create sf if alloc failed
mptcp: pm: do not ignore 'subflow' if 'signal' flag is also set
selftests: mptcp: join: ability to invert ADD_ADDR check
selftests: mptcp: join: test both signal & subflow
net/mptcp/options.c | 3 +-
net/mptcp/pm_netlink.c | 47 +++++++++++++--------
tools/testing/selftests/net/mptcp/mptcp_join.sh | 55 ++++++++++++++++++-------
3 files changed, 73 insertions(+), 32 deletions(-)
---
base-commit: 0bf50cead4c4710d9f704778c32ab8af47ddf070
change-id: 20240731-upstream-net-20240731-mptcp-endp-subflow-signal-181d640cf5e8
Best regards,
--
Matthieu Baerts (NGI0) <matttbe(a)kernel.org>