Pull Kunit fixes from Shuah Khan: - Fixes to address the structleak plugin causing the stack frame size to grow immensely when used with KUnit. Fixes include adding a new makefile to disable structleak and using it from KUnit iio, device property, thunderbolt, and bitfield tests to disable it. - KUnit framework reference count leak in kfree_at_end - KUnit tool fix to resolve conflict between --json and --raw_output and generate correct test output in either case. - kernel-doc warnings due to mismatched arg names * tag 'linux-kselftest-kunit-fixes-5.15-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: kunit: fix kernel-doc warnings due to mismatched arg names bitfield: build kunit tests without structleak plugin thunderbolt: build kunit tests without structleak plugin device property: build kunit tests without structleak plugin iio/test-format: build kunit tests without structleak plugin gcc-plugins/structleak: add makefile var for disabling structleak kunit: fix reference count leak in kfree_at_end kunit: tool: better handling of quasi-bool args (--json, --raw_output)
Unified · Split
| @@ -2,4 +2,4 @@ · 1 unmodified line | ||
| 2 | 2 | obj-$(CONFIG_TEST_ASYNC_DRIVER_PROBE) += test_async_driver_probe.o |
| 3 | 3 | |
| 4 | 4 | obj-$(CONFIG_DRIVER_PE_KUNIT_TEST) += property-entry-test.o |
| 5 | −CFLAGS_REMOVE_property-entry-test.o += -fplugin-arg-structleak_plugin-byref -fplugin-arg-structleak_plugin-byref-all | |
| 5 | +CFLAGS_property-entry-test.o += $(DISABLE_STRUCTLEAK_PLUGIN) | |
| @@ -5,3 +5,4 @@ · 4 unmodified lines | ||
| 5 | 5 | |
| 6 | 6 | # Keep in alphabetical order |
| 7 | 7 | obj-$(CONFIG_IIO_TEST_FORMAT) += iio-test-format.o |
| 8 | +CFLAGS_iio-test-format.o += $(DISABLE_STRUCTLEAK_PLUGIN) | |
| @@ -7,6 +7,7 @@ thunderbolt-objs += usb4_port.o nvm.o retimer.o quirks.o · 6 unmodified lines | ||
| 7 | 7 | thunderbolt-${CONFIG_ACPI} += acpi.o |
| 8 | 8 | thunderbolt-$(CONFIG_DEBUG_FS) += debugfs.o |
| 9 | 9 | thunderbolt-${CONFIG_USB4_KUNIT_TEST} += test.o |
| 10 | +CFLAGS_test.o += $(DISABLE_STRUCTLEAK_PLUGIN) | |
| 10 | 11 | |
| 11 | 12 | thunderbolt_dma_test-${CONFIG_USB4_DMA_TEST} += dma_test.o |
| 12 | 13 | obj-$(CONFIG_USB4_DMA_TEST) += thunderbolt_dma_test.o |
| @@ -613,7 +613,7 @@ void kunit_remove_resource(struct kunit *test, struct kunit_resource *res); · 612 unmodified lines | ||
| 613 | 613 | * and is automatically cleaned up after the test case concludes. See &struct |
| 614 | 614 | * kunit_resource for more information. |
| 615 | 615 | */ |
| 616 | −void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t flags); | |
| 616 | +void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp); | |
| 617 | 617 | |
| 618 | 618 | /** |
| 619 | 619 | * kunit_kmalloc() - Like kmalloc() except the allocation is *test managed*. |
| @@ -657,9 +657,9 @@ static inline void *kunit_kzalloc(struct kunit *test, size_t size, gfp_t gfp) · 37 unmodified lines | ||
| 657 | 657 | * |
| 658 | 658 | * See kcalloc() and kunit_kmalloc_array() for more information. |
| 659 | 659 | */ |
| 660 | −static inline void *kunit_kcalloc(struct kunit *test, size_t n, size_t size, gfp_t flags) | |
| 660 | +static inline void *kunit_kcalloc(struct kunit *test, size_t n, size_t size, gfp_t gfp) | |
| 661 | 661 | { |
| 662 | − return kunit_kmalloc_array(test, n, size, flags | __GFP_ZERO); | |
| 662 | + return kunit_kmalloc_array(test, n, size, gfp | __GFP_ZERO); | |
| 663 | 663 | } |
| 664 | 664 | |
| 665 | 665 | void kunit_cleanup(struct kunit *test); |
| @@ -351,7 +351,7 @@ obj-$(CONFIG_OBJAGG) += objagg.o · 350 unmodified lines | ||
| 351 | 351 | obj-$(CONFIG_PLDMFW) += pldmfw/ |
| 352 | 352 | |
| 353 | 353 | # KUnit tests |
| 354 | −CFLAGS_bitfield_kunit.o := $(call cc-option,-Wframe-larger-than=10240) | |
| 354 | +CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN) | |
| 355 | 355 | obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o |
| 356 | 356 | obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o |
| 357 | 357 | obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o |
| @@ -116,8 +116,8 @@ static void kfree_at_end(struct kunit *test, const void *to_free) · 115 unmodified lines | ||
| 116 | 116 | /* kfree() handles NULL already, but avoid allocating a no-op cleanup. */ |
| 117 | 117 | if (IS_ERR_OR_NULL(to_free)) |
| 118 | 118 | return; |
| 119 | − kunit_alloc_and_get_resource(test, NULL, kfree_res_free, GFP_KERNEL, | |
| 120 | − (void *)to_free); | |
| 119 | + kunit_alloc_resource(test, NULL, kfree_res_free, GFP_KERNEL, | |
| 120 | + (void *)to_free); | |
| 121 | 121 | } |
| 122 | 122 | |
| 123 | 123 | static struct kunit_suite *alloc_fake_suite(struct kunit *test, |
| @@ -19,6 +19,10 @@ gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF) \ · 18 unmodified lines | ||
| 19 | 19 | += -fplugin-arg-structleak_plugin-byref |
| 20 | 20 | gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL) \ |
| 21 | 21 | += -fplugin-arg-structleak_plugin-byref-all |
| 22 | +ifdef CONFIG_GCC_PLUGIN_STRUCTLEAK | |
| 23 | + DISABLE_STRUCTLEAK_PLUGIN += -fplugin-arg-structleak_plugin-disable | |
| 24 | +endif | |
| 25 | +export DISABLE_STRUCTLEAK_PLUGIN | |
| 22 | 26 | gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) \ |
| 23 | 27 | += -DSTRUCTLEAK_PLUGIN |
| 24 | 28 | |
| @@ -16,7 +16,7 @@ assert sys.version_info >= (3, 7), "Python version is too old" · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | from collections import namedtuple |
| 18 | 18 | from enum import Enum, auto |
| 19 | −from typing import Iterable | |
| 19 | +from typing import Iterable, Sequence | |
| 20 | 20 | |
| 21 | 21 | import kunit_config |
| 22 | 22 | import kunit_json |
| @@ -186,6 +186,26 @@ def run_tests(linux: kunit_kernel.LinuxSourceTree, · 163 unmodified lines | ||
| 186 | 186 | exec_result.elapsed_time)) |
| 187 | 187 | return parse_result |
| 188 | 188 | |
| 189 | +# Problem: | |
| 190 | +# $ kunit.py run --json | |
| 191 | +# works as one would expect and prints the parsed test results as JSON. | |
| 192 | +# $ kunit.py run --json suite_name | |
| 193 | +# would *not* pass suite_name as the filter_glob and print as json. | |
| 194 | +# argparse will consider it to be another way of writing | |
| 195 | +# $ kunit.py run --json=suite_name | |
| 196 | +# i.e. it would run all tests, and dump the json to a `suite_name` file. | |
| 197 | +# So we hackily automatically rewrite --json => --json=stdout | |
| 198 | +pseudo_bool_flag_defaults = { | |
| 199 | + '--json': 'stdout', | |
| 200 | + '--raw_output': 'kunit', | |
| 201 | +} | |
| 202 | +def massage_argv(argv: Sequence[str]) -> Sequence[str]: | |
| 203 | + def massage_arg(arg: str) -> str: | |
| 204 | + if arg not in pseudo_bool_flag_defaults: | |
| 205 | + return arg | |
| 206 | + return f'{arg}={pseudo_bool_flag_defaults[arg]}' | |
| 207 | + return list(map(massage_arg, argv)) | |
| 208 | + | |
| 189 | 209 | def add_common_opts(parser) -> None: |
| 190 | 210 | parser.add_argument('--build_dir', |
| 191 | 211 | help='As in the make command, it specifies the build ' |
| @@ -303,7 +323,7 @@ def main(argv, linux=None): · 111 unmodified lines | ||
| 303 | 323 | help='Specifies the file to read results from.', |
| 304 | 324 | type=str, nargs='?', metavar='input_file') |
| 305 | 325 | |
| 306 | − cli_args = parser.parse_args(argv) | |
| 326 | + cli_args = parser.parse_args(massage_argv(argv)) | |
| 307 | 327 | |
| 308 | 328 | if get_kernel_root_path(): |
| 309 | 329 | os.chdir(get_kernel_root_path()) |
| @@ -408,6 +408,14 @@ class KUnitMainTest(unittest.TestCase): · 407 unmodified lines | ||
| 408 | 408 | self.assertNotEqual(call, mock.call(StrContains('Testing complete.'))) |
| 409 | 409 | self.assertNotEqual(call, mock.call(StrContains(' 0 tests run'))) |
| 410 | 410 | |
| 411 | + def test_run_raw_output_does_not_take_positional_args(self): | |
| 412 | + # --raw_output is a string flag, but we don't want it to consume | |
| 413 | + # any positional arguments, only ones after an '=' | |
| 414 | + self.linux_source_mock.run_kernel = mock.Mock(return_value=[]) | |
| 415 | + kunit.main(['run', '--raw_output', 'filter_glob'], self.linux_source_mock) | |
| 416 | + self.linux_source_mock.run_kernel.assert_called_once_with( | |
| 417 | + args=None, build_dir='.kunit', filter_glob='filter_glob', timeout=300) | |
| 418 | + | |
| 411 | 419 | def test_exec_timeout(self): |
| 412 | 420 | timeout = 3453 |
| 413 | 421 | kunit.main(['exec', '--timeout', str(timeout)], self.linux_source_mock) |